Static Analysis Tool
Overview
cjlint (Cangjie Lint) is a static analysis tool developed based on the Cangjie Language Programming Specification. It identifies code segments that violate programming standards, helps developers detect vulnerabilities, and ensures the production of Cangjie code that meets Clean Source requirements.
Usage Instructions
cjlint -h displays help information and option descriptions.
Options:
-h Show usage
eg: ./cjlint -h
-v Show version
eg: ./cjlint -v
-f <value> Detected file directory (absolute or relative paths). If a directory is specified, the default output filename is cjReport
eg: ./cjlint -f fileDir -c . -m .
eg: ./cjlint -f "fileDir1 fileDir2" -c . -m .
-e <v1:v2:...> Excluded files, directories, or configurations (separated by ':'). Supports regular expressions
eg: ./cjlint -f fileDir -e fileDir/a/:fileDir/b/*.cj
-o <value> Output file path (absolute or relative)
eg: ./cjlint -f fileDir -o ./out
-r [csv|json] Report file format (csv or json, default: json)
eg: ./cjlint -f fileDir -r csv -o ./out
-c <value> Config directory path (absolute or relative to the executable)
eg: ./cjlint -f fileDir -c .
-m <value> Modules directory path (absolute or relative to the executable)
eg: ./cjlint -f fileDir -m .
--import-path <value> Add .cjo search path
cjlint -f specifies the target directory for analysis.
cjlint -f fileDir [option] fileDir...
# For multiple paths, separate them with spaces within ""
cjlint -f "fileDir1 fileDir2" [option] fileDir...
Note:
The path after
-fshould point to thesrcdirectory containing *.cj files.
Correct example:
cjlint -f xxx/xxx/src
Incorrect example:
cjlint -f xxx/xxx/src/xxx.cj
Explanation:
This limitation stems from compiler module constraints. As the compiler's compilation options are currently being refactored with unstable APIs, the tool only supports module compilation for now. Eventually, the tool will align with the compiler's stable compilation options.
-r specifies the scan report format (currently supports json and csv).
-r must be used with -o. If -o is not specified to output to a file, no report will be generated even if -r is set. If -o is specified without -r, the default format is json.
cjlint -f ./src -r csv -o ./report # Generates report.csv
cjlint -f ./src -r csv -o ./output/report # Generates report.csv in the output directory
-c and -m allow developers to specify custom config and modules directory paths when needed.
By default, cjlint uses the config and modules directories in its installation path. Developers can override these using -c and -m.
Example: If custom config and modules paths are ./tools/cjlint/config and ./tools/cjlint/modules respectively (both under ./tools/cjlint), the command would be:
cjlint -f ./src -c ./tools/cjlint -m ./tools/cjlint
--import-path specifies .cjo search paths (supports multiple paths).
cjlint --import-path fileDir
# For multiple paths, separate them with spaces within ""
cjlint --import-path "fileDir1 fileDir2"
Rule-Level Warning Suppression
The config directory (located alongside the cjlint executable) contains two configuration files: cjlint_rule_list.json and exclude_lists.json. cjlint_rule_list.json: Rule list configuration. Developers can enable/disable specific rules by modifying this file. exclude_lists.json: Warning suppression configuration. Developers can suppress specific rule violations by adding entries here.
Example: To enable only 5 specific rules:
{
"RuleList": [
"G.FMT.01",
"G.ENU.01",
"G.EXP.03",
"G.OTH.01",
"G.OTH.02"
]
}
Example: To suppress specific violations of rule "G.OTH.01":
Note:
pathsupports fuzzy matching (format:xxx.cj).linerequires exact matching.columis optional for column-level precision.
{
"G.OTH.01" : [
{"path":"xxx/example.cj", "line":"42"},
{"path":"xxx/example.cj", "line":"42", "colum": "2"},
{"path":"example.cj", "line":"42", "colum": "2"}
]
}
Source Code Comment-Based Suppression
Special Comment BNF
<content of cjlint-ignore comment> ::= "cjlint-ignore" [-start] <ignore-rule>{...} [description] | cjlint-ignore <-end> [description]
<ignore-rule> ::="!"<rule-name>
<rule-name> ::= <letters>
Note:
- The
cjlint-ignoremarker,-start/-endoptions, and rule specifications must appear on the same line. Descriptions can span multiple lines.- For single-line suppression, separate multiple rules with spaces. The suppression applies to the current line.
- For multi-line suppression,
-startmarks the beginning and-endmarks the end. The suppression applies to all lines between them. Each-endpairs with the nearest preceding-start.
Correct Single-Line Example 1: Suppress G.FUN.02
func foo(a: Int64, b: Int64, c: Int64, d: Int64) { /* cjlint-ignore !G.FUN.02 */
return a + b + c
}
Correct Single-Line Example 2: Suppress G.FUN.02
func foo(a: Int64, b: Int64, c: Int64, d: Int64) { // cjlint-ignore !G.FUN.02 description
return a + b + c
}
Correct Multi-Line Example 1: Suppress G.FUN.02
/*cjlint-ignore -start !G.FUN.02 description */
func foo(a: Int64, b: Int64, c: Int64, d: Int64) {
return a + b + c
}
/* cjlint-ignore -end description */
Correct Multi-Line Example 2: Suppress G.FUN.02
// cjlint-ignore -start !G.FUN.02 description
func foo(a: Int64, b: Int64, c: Int64, d: Int64) {
return a + b + c
}
// cjlint-ignore -end description
Correct Multi-Line Example 3: Suppress G.FUN.02
/**
* cjlint-ignore -start !G.FUN.02 description
*/
func foo(a: Int64, b: Int64, c: Int64, d: Int64) {
return a + b + c
}
// cjlint-ignore -end description
Incorrect Single-Line Example 1: Failed G.FUN.02 suppression
func foo(a: Int64, b: Int64, c: Int64, d: Int64) { /*cjlint-ignore !G.FUN.02!G.FUN.01*/
return a + b + c // ERROR: Missing space between rules
}
Incorrect Single-Line Example 2: Failed G.FUN.02 suppression
func foo(a: Int64, b: Int64, c: Int64, d: Int64) { /*cjlint-ignore !G.FUN.02description*/
return a + b + c // ERROR: Missing space before description
}
Incorrect Multi-Line Example 1: Failed G.FUN.02 suppression
/* cjlint-ignore -start
* !G.FUN.02 description */
func foo(a: Int64, b: Int64, c: Int64, d: Int64) {
return a + b + c
}
/* cjlint-ignore -end description */
// ERROR: Rule not on same line as 'cjlint-ignore'
File-Level Warning Suppression
-
cjlintsupports file-level suppression via the-eoption.Specify exclusion patterns (relative to
-fsource directory, supports regex) within quotes, separated by spaces. Example: This command excludes all.cjfiles undersrc/dir1/,src/dir2/a.cj, and files matchingtest*.cjinsrc/.cjlint -f src/ -e "dir1/ dir2/a.cj test*.cj" -
cjlintsupports batch exclusions via.cfgconfiguration files.Use
-eto specify.cfgfiles (separated by spaces). Example: This command excludes files matching patterns insrc/exclude_config_1.cfgandsrc/dir2/exclude_config_2.cfg, plussrc/dir1/.cjlint -f src/ -e "dir1/ exclude_config_1.cfg dir2/exclude_config_2.cfg".cfgfiles contain one pattern per line (relative to the config file's directory, supports regex). Example: Ifsrc/dir2/exclude_config_2.cfgcontains these lines, the above command would excludesrc/dir2/subdir1/andsrc/dir2/subdir2/a.cj.subdir1/ subdir2/a.cj -
cjlintsupports default configuration file for exclusions.The default exclusion config file is
cjlint_file_exclude.cfgin the-fsource directory. Example: Whensrc/cjlint_file_exclude.cfgexists,cjlint -f src/will apply its exclusion patterns. If other valid.cfgfiles are specified via-e, the default file is ignored.
Supported Rules (Continuously Updated)
Default enabled rules:
- G.NAM.01 Package names should be lowercase with optional underscores/numbers.
- G.NAM.02 Source filenames should use lowercase_with_underscores style.
- G.NAM.03 Interfaces, classes, structs, enums, and type aliases use PascalCase.
- G.NAM.04 Functions use camelCase.
- G.NAM.05 Global
letandstatic letvariables use UPPER_CASE. - G.FMT.01 Source files must use UTF-8 encoding (including comments).
- G.FMT.15 Never omit leading 0 in floating-point numbers.
- G.DCL.01 Avoid variable shadowing.
- G.DCL.02 Explicitly declare types for public variables and function returns.
- G.FUN.01 Functions should have single responsibility.
- G.FUN.02 Functions must not have unused parameters.
- G.FUN.03 Avoid overloading unrelated functions with the same name.
- G.CLS.01 Don't increase visibility when overriding methods.
- G.ITF.02 Prefer implementing interfaces at type definition rather than via extension.
- G.ITF.01 Use
mutfor self-modifying interface functions to support structs. - G.ITF.03 Avoid implementing both parent and child interfaces simultaneously.
- G.ITF.04 Prefer generic constraints over direct interface types.
- G.OPR.01 Avoid unconventional operator overloading.
- G.OPR.02 Avoid overloading
()in enums. - G.ENU.01 Avoid enum constructor/top-level name collisions.
- G.ENU.02 Minimize unnecessary constructor overloading across enums.
- G.VAR.01 Prefer immutable variables.
- G.VAR.02 Minimize variable scope.
- G.TYP.03 Use
isNaN()for NaN checks. - G.EXP.01 Avoid mixing pattern types in single
matchlevel. - G.EXP.02 Don't expect precise results from floating-point operations.
- G.EXP.03 Avoid side effects in right-hand operands of
&&,||,?,??. - G.EXP.04 Avoid relying on operator evaluation order for side effects.
- G.EXP.05 Use parentheses to clarify operation order.
- G.EXP.06 Avoid redundant
==or!=with Booleans. - G.EXP.07 Place changing expressions on the left in comparisons.
- G.ERR.01 Use proper error handling mechanisms.
- G.ERR.02 Prevent sensitive data leaks via exceptions.
- G.ERR.03 Avoid
getorthrowwith Option types. - G.ERR.04 Don't use
return,break,continue, or exceptions to exitfinally. - G.PKG.01 Avoid wildcard
import *. - G.CON.01 Don't expose internal lock objects to untrusted code.
- P.01 Acquire locks in consistent order to prevent deadlocks.
- G.CON.02 Ensure lock release during exceptions.
- G.CON.03 Don't override thread-safe functions with unsafe versions.
- P.02 Avoid data races.
- G.CHK.01 Validate untrusted data before cross-boundary use.
- G.CHK.02 Never log external data directly.
- G.CHK.03 Normalize and validate file paths from external data.
- G.CHK.04 Never construct regex directly from untrusted data.
- G.FIO.01 Delete temporary files after use.
- G.SER.01 Never serialize unencrypted sensitive data.
- G.SER.02 Prevent deserialization bypassing constructor security.
- G.SER.03 Maintain consistent serialization/deserialization types.
- G.SEC.01 Security check methods must not be
open. - P.03 Use defensive copies for external object security checks.
- G.OTH.01 Never log passwords, keys, or sensitive data.
- G.OTH.02 Never hardcode sensitive information.
- G.OTH.03 Avoid public network addresses in code.
- G.OTH.04 Use dedicated types (not String) for sensitive data; clear after use.
- FFI.C.7 Prevent truncation errors in pointer type conversions.
Optional rules (enable via cjlint_rule_list.json):
- G.NAM.06 Variables use camelCase.
- G.VAR.03 Avoid global variables.
- G.FMT.13 File headers should include license information.
Specifications
-
G.CON.02: Doesn't cover lock/unlock via assigned variables.
The
lock()function andunlock()function are assigned to variables. Scenarios where the assigned variables are then used for locking/unlocking operations are not covered by this rule check. -
G.OTH.03: Macro checking is unsupported.
-
Macro checking requires correct package paths.
Example: Macro source
a.cjshould be atxxx/src/a/a.cj. -
cjlintonly checks invoked macros and cannot detect redundant macro code.
Syntax Restriction Checking
-
Enable G.SYN.01 in
cjlint_rule_list.jsonto check for prohibited syntax elements. -
Currently supported restricted syntax:
Syntax Keyword Rationale Package Import Import Prevent arbitrary imports Let Variables Let Use varexclusivelyThread Creation Spawn Disallow thread creation Synchronization Synchronized Prevent deadlocks Main Function Main Disallow entry points Macro Definition MacroQuote Allow macro use but not definition Cross-Language Foreign Disallow mixed-language programming While Loops While Prevent complex/deadly loops Extensions Extend Disallow extension syntax Type Aliases Type Disallow custom type aliases Operator Overload Operator Disallow operator overloading Global Variables GlobalVariable Prevent side effects/memory leaks Enum Definition Enum Avoid complex code Class Definition Class Avoid complex code Interface Def. Interface Avoid complex code Struct Definition Struct Avoid complex code Generic Def. Generic Avoid complex code Conditional Comp When Prevent platform-specific code Pattern Matching Match Functional paradigm is hard to master Exception Handling TryCatch Prevent ignored errors Higher-Order Func HigherOrderFunc Avoid complexity Primitive Types PrimitiveType Restrict to Int64, float64, bool Container Types ContainerType Use only List, Map, Set -
Add keywords to
structural_rule_G_SYN_01.jsonto enable specific syntax restrictions. Example: Disallow imports
{
"SyntaxKeyword": [
"Import"
]
}