Recent from talks
Nothing was collected or created yet.
Lint (software)
View on Wikipedia| Lint | |
|---|---|
| Original author | Stephen C. Johnson |
| Developer | AT&T Bell Laboratories |
| Initial release | July 26, 1978[1] |
| Written in | C |
| Operating system | Cross-platform |
| Available in | English |
| Type | Static program analysis tools |
| License | Originally proprietary commercial software, now free software under a BSD-like license[2][3] |
Lint is the computer science term for a static code analysis tool used to flag programming errors, bugs, stylistic errors and suspicious constructs.[4] The term originates from a Unix utility that examined C language source code.[1] A program which performs this function is also known as a "linter" or "linting tool".
History
[edit]Stephen C. Johnson, a computer scientist at Bell Labs, came up with the term "lint" in 1978 while debugging the yacc grammar he was writing for C and dealing with portability issues stemming from porting Unix to a 32-bit machine.[5][1] The term was borrowed from the word lint, the tiny bits of fiber and fluff shed by clothing, as the command he wrote would act like a lint trap in a clothes dryer, capturing waste fibers while leaving whole fabrics intact. In 1979, lint programming was used outside of Bell Labs for the first time, in the seventh version (V7) of Unix.
Over the years, different versions of lint have been developed for many C and C++ compilers, and while modern-day compilers have lint-like functions, lint-like tools have also advanced their capabilities. For example, Gimpel's PC-Lint, introduced in 1985 and used to analyze C++ source code, is still for sale.[5]
Overview
[edit]In his original 1978 paper Johnson stated his reasoning in creating a separate program to detect errors, distinct from that which it analyzed: "...the general notion of having two programs is a good one" [because they concentrate on different things, thereby allowing the programmer to] "concentrate at one stage of the programming process solely on the algorithms, data structures, and correctness of the program, and then later retrofit, with the aid of lint, the desirable properties of universality and portability".[1]
Successor linters
[edit]The analysis performed by lint-like tools can also be performed by an optimizing compiler, which aims to generate faster code. Even though modern compilers have evolved to include many of lint's historical functions, lint-like tools have also evolved to detect an even wider variety of suspicious constructs. These include "warnings about syntax errors, uses of undeclared variables, calls to deprecated functions, spacing and formatting conventions, misuse of scope, implicit fallthrough in switch statements, missing license headers, [and]...dangerous language features".[6]
Lint-like tools are especially useful for dynamically typed languages like JavaScript and Python. Because the interpreters of such languages typically do not enforce as many and as strict rules during execution, linter tools can also be used as simple debuggers for finding common errors (e.g. syntactic discrepancies) as well as hard-to-find errors such as heisenbugs (drawing attention to suspicious code as "possible errors").[7] Lint-like tools generally perform static analysis of source code.[8]
Lint-like tools have also been developed for other aspects of software development, such as enforcing grammar and style guides for given language source code.[9] Some tools (such as ESLint) also allow rules to be auto-fixable: a rule definition can also come with the definition of a transform that resolves the warning. Rules about style are especially likely to come with an auto-fix. If the linter is run in "fix all" mode on a file that triggers only rules about formatting, the linter will act just like a formatter.
See also
[edit]References
[edit]- ^ a b c d Johnson, Stephen C. (25 October 1978). "Lint, a C Program Checker". Comp. Sci. Tech. Rep. Bell Labs: 78–1273. CiteSeerX 10.1.1.56.1841. Archived from the original on 2022-01-23.
- ^ "UNIX is free!". lemis.com. 2002-01-24.
- ^ Broderick, Bill (January 23, 2002). "Dear Unix enthusiasts" (PDF). Caldera International. Archived from the original (PDF) on February 19, 2009.
- ^ "About SublimeLinter". The SublimeLinter Community, revision 1cecc79c. Archived from the original on 2023-06-06. Retrieved 2020-03-29.
- ^ a b Morris, Richard (1 October 2009). "Stephen Curtis Johnson: Geek of the Week". Red Gate Software. Retrieved 19 January 2018.
- ^ "Arcanist User Guide: Lint". Phabricator. Retrieved 19 January 2018.
- ^ "ESLint - Customizable JavaScript linting tool (1)". theCodeCampus. 2015-06-09. Retrieved 2019-04-21.
- ^ Jones, Nigel (1 May 2002). "How to Use Lint for Static Code Analysis". Barr Group.
- ^ rust-lang/rustfmt, The Rust Programming Language, 2025-01-20, retrieved 2025-01-21
Further reading
[edit]- Darwin, Ian F. (1991). Checking C Programs with Lint: C Programming Utility (Revised ed.). United States: O'Reilly Media. ISBN 978-0937175309.
- "LINT(1)". NetBSD General Commands Manual. 2024-01-24.
Lint (software)
View on GrokipediaOverview
Definition and Purpose
Lint is a static code analysis utility designed to examine C source code for potential errors, bugs, stylistic issues, and obscurities without executing the program.[1] It enforces the type rules of C more strictly than the compiler, taking a global view to identify inconsistencies and inefficiencies that might otherwise go unnoticed.[1] The primary purpose of Lint is to separate error detection from the coding process, enabling developers to concentrate on algorithms and logic rather than immediate debugging.[1] As explained by its creator, Stephen C. Johnson, this separation has both historical and practical rationale, with compilers turning C programs into executable files rapidly and efficiently while Lint takes a more global, leisurely view of the program, looking much more carefully at the compatibilities.[1] Developed specifically for the C programming language, Lint addresses challenges in code portability across diverse systems and operating environments.[1] Among its key benefits, Lint facilitates the early identification of issues such as type mismatches in function calls and operators, unused variables or functions, and potential runtime errors like variables used before initialization.[1] By flagging these problems proactively, it significantly reduces debugging time and improves overall code quality and maintainability.[1]Key Features
One of the primary features of Lint is its capability for static analysis of C source code, examining structure and semantics without executing the program, thereby complementing dynamic testing by identifying potential issues such as unused variables, unreachable code, and type incompatibilities before runtime.[1] This non-executable approach allows Lint to take a "global, leisurely view" of the code, performing thorough checks that compilers might overlook due to their focus on rapid compilation.[1] Lint excels in inter-file analysis, processing multiple source files and library specifications simultaneously to ensure consistency across them, such as verifying that function declarations match their definitions and uses in separate modules.[1] By generating intermediate ASCII files from each input and sorting them to compare external identifiers, Lint detects discrepancies like mismatched argument types or undeclared variables that span files, which isolated per-file checks would miss.[1] A distinctive aspect of Lint is its emphasis on portability checks, activated via the-p flag, which flags code elements likely to behave inconsistently across different hardware architectures or operating systems, including assumptions about integer sizes, character signing, or multiple definitions of external variables.[1] For instance, it warns against portable-specific constructs like relying on the value of EOF or uninitialized externals that could vary between systems.[1]
Lint produces detailed textual output reports that list potential problems with precise line numbers, file references, and explanatory messages, without altering the original code, enabling developers to review and address issues manually.[1] Various flags, such as -u for unused externals or -v for function argument usage, allow customization of the verbosity and focus of these reports.[1]
Implemented as a standalone Unix command-line tool, Lint operates independently of the compilation process, typically invoked via a driver script that feeds source files through the Portable C Compiler's front end to generate analyzable intermediates before performing the checks.[1] This separation ensures it can be integrated into development workflows as a dedicated verification step, built upon the same parser as the compiler for accurate semantic understanding.[1]
History
Origins and Development
Lint was developed by Stephen C. Johnson at Bell Laboratories in 1978 as part of the early Unix development efforts, specifically to address the limitations of existing C compilers in detecting programming errors beyond basic syntax checks. Johnson developed Lint specifically to aid in debugging the YACC grammar he was writing for the C language, which highlighted issues in testing parsers and ensuring portability.[5][1] This tool emerged during a period when the C language was gaining prominence for system programming, particularly in the Unix environment, where compilers were optimized for rapid compilation rather than exhaustive error detection. Johnson noted that C compilers prioritized efficiency in generating executable code, often overlooking potential issues in type usage and portability that could arise in complex programs.[1] The primary motivations for creating Lint stemmed from the increasing adoption of Unix outside Bell Labs in the mid-1970s, which highlighted the need for robust debugging tools to support portable C code across diverse hardware and operating systems.[6] As Unix projects expanded, developers encountered challenges in maintaining code quality and consistency, especially when porting the system to new machines like the Interdata 8/32. Lint was designed to enforce stricter type checking and identify dubious constructions, such as inefficiencies or interface mismatches, that compilers might ignore to maintain speed.[1] Portability was a core goal, enabling better analysis of code intended for multiple environments without requiring full recompilation.[6] Key technical challenges in Lint's development included performing semantic analysis on C's intricate pointer arithmetic and type system independently of the compilation process. Johnson innovated by implementing global program analysis that could cross-reference symbols across separately compiled files, simulating aspects of a full build without generating object code. This approach allowed Lint to detect subtle errors, like type inconsistencies in function interfaces, that were difficult to catch otherwise.[1] Prior to its wider distribution, Lint underwent internal testing at Bell Labs, where it was employed to enhance code quality in Unix kernel development and facilitate porting the operating system and its utilities to other architectures. This pre-release use helped identify and resolve issues in core system components, contributing to the refinement of C programming practices within the Unix ecosystem.[6][1]Initial Release and Early Adoption
Lint was first publicly released as part of the Unix Version 7 distribution in January 1979, with its foundational documentation dated July 26, 1978, by developer Stephen C. Johnson at Bell Laboratories.[1][7] Developed internally as a tool to enforce stricter C language rules than compilers, it was included as a standard utility in this research-oriented Unix edition, made available at low cost to universities and research institutions under Bell Labs' distribution terms that permitted source code access for non-commercial purposes. Originally created within Bell Labs' proprietary environment, Lint's inclusion in V7 marked its transition to broader accessibility, later aligning with BSD-like licensing in subsequent open distributions. By 1979, Lint achieved widespread adoption within Unix development communities, serving as an essential aid for debugging and code quality in early C programming efforts. Its initial external references appeared in the Unix V7 programmer's manual, highlighting its role in examining source programs for bugs, obscurities, and portability issues across systems.[1] This early uptake influenced the evolution toward C language standardization by rigorously enforcing type checking and identifying non-portable constructs, thereby contributing to more consistent practices in multi-file and cross-platform development. Key milestones in the early 1980s included ports of Lint accompanying Unix adaptations to new hardware, such as VAX systems via Berkeley Software Distribution releases, expanding its utility beyond the original PDP-11 architecture. In 1985, Gimpel Software introduced PC-Lint, a commercial variant tailored for personal computers, which broadened Lint's application to MS-DOS environments and marked a shift toward specialized implementations.[8] Early adoption was not without challenges; developers often resisted incorporating Lint due to the extra processing time it required as an additional build step, rendering it impractical for routine compilations compared to faster compilers. Nonetheless, it was highly regarded for revealing subtle errors, type mismatches, and inefficient code that standard compilers overlooked, solidifying its value in professional Unix workflows.[1]Technical Implementation
Code Analysis Process
The original Lint tool performs static code analysis on C source code through a multi-phase process that examines the program's structure without executing it or generating object code. It begins with lexical analysis, or tokenization, where the input source files are scanned to identify symbols, keywords, operators, and other tokens using a modified version of the Portable C Compiler. This is followed by syntactic and semantic parsing, which constructs expression trees—analogous to an abstract syntax tree (AST)—and populates symbol tables to represent the program's declarations, definitions, and usages. Unlike a full compiler, Lint avoids code generation, focusing instead on diagnostic checks to uncover potential issues early in development.[1][9] The analysis proceeds in two main phases. In the first phase, Lint processes each input file individually, performing declaration checking and type inference for variables, functions, and expressions while building intermediate ASCII files that capture external symbols, including their names, contexts, types, file locations, and line numbers. The second phase involves sorting these intermediate files and conducting cross-file comparisons to verify consistency in declarations and usages, along with flow analysis to inspect control structures for issues such as unreachable code. Type inference is particularly rigorous, enforcing stricter rules than the C compiler for binary operators, structure selections, function arguments, and enumerations to detect mismatches that could lead to subtle errors.[1][9] Lint addresses several C language specifics to flag potential problems. For pointer usage, it applies strict type checking to assignments and operations, requiring exact matches (except for arrays and compatible pointers), and with the-p or -h flags, it identifies alignment issues across architectures like the PDP-11 and Honeywell 6000 that could cause dereference errors. Array bounds are not explicitly checked, representing a limitation in handling size incompatibilities between files. Macro expansions are scrutinized for ambiguities, such as older syntax like =+ or =- that may lead to incorrect substitutions, with recommendations to use modern operators like += and -=. These checks help prevent dereference errors by highlighting suspicious pointer and array manipulations without simulating runtime conditions.[1]
Invocation of Lint occurs via the command line, typically as lint file1.c file2.c to analyze multiple source files together, assuming they have been preprocessed if necessary. Configuration options include -p for portability warnings, -h for heuristic checks like null pointer effects (e.g., *p++), and -v to suppress reports on unused function arguments, allowing users to manage false positives. Output includes detailed messages with file names and line numbers for identified issues.[1][9]
A key limitation of Lint is its exclusive focus on static properties, providing no support for runtime behaviors such as memory leaks or dynamic allocation errors, which require execution to observe. It also cannot reliably detect control flow effects from non-returning functions like exit() or handle cross-file inconsistencies in structure and union sizes, emphasizing its role as a complementary tool to compilers rather than a complete verifier.[1]
Types of Errors Detected
The original Lint tool detects a range of programming errors and code quality issues in C programs, primarily through static analysis that examines source code without execution. These detections emphasize semantic correctness, cross-platform portability, and maintainability, helping programmers identify subtle bugs that compilers might overlook.[1] Lint flags semantic errors, including undeclared or undefined variables and functions, type mismatches between function parameters and their declarations, and inconsistencies in return types—such as functions that return a value in some paths but not others. It also warns about variables used before initialization, particularly local variables that may hold indeterminate values, and expressions with undefined evaluation order that could lead to non-portable behavior. For example, it reports cases where a function value is computed but not used, or where control flow might result in unreachable code after constructs like goto statements.[1] In terms of portability issues, Lint identifies assumptions that could fail across different systems, such as non-portable character comparisons treating signed and unsigned chars differently, potential pointer alignment problems, and assignments from long integers to shorter types that might truncate values. It highlights dependencies on specific integer sizes or endianness by flagging constructs like comparisons between pointers and integers, or uses of character values outside the portable range, ensuring code is more robust when ported to varied hardware architectures.[1] For style and maintainability, the tool detects unused variables or functions that are declared but never referenced, which can indicate dead code or overlooked elements. It also points out overly complex or suspicious expressions, such as "null effect" statements like*p++ where the pointer p might not be properly managed, potentially leading to issues like unintended null pointer dereferences. Additionally, Lint reports unreachable code segments, which could signal infinite loops or flawed control flow logic, and flags functions with no return statement despite being expected to return a value.[1]
Lint reports these issues in a categorized output format, distinguishing between errors (more severe semantic violations) and warnings (portability or style suggestions), with messages that include line numbers, context, and occasional fix recommendations like using typedefs for consistent types. Users can control verbosity with flags such as -h for heuristic checks or -v to suppress complaints about unused function arguments, allowing focused analysis while suppressing noise from known idioms via directives like /* NOTREACHED */ for unreachable code. This structured reporting enables efficient debugging, as the tool processes multiple source files together to catch inter-file inconsistencies.[1]
