From e3a15792fa6034f24dae02c3b0f3faa3cca3ae7b Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 3 Mar 2022 19:22:41 +0100 Subject: [PATCH] QL: add query detecting upper-case acronyms --- ql/ql/src/codeql/Locations.qll | 1 + ql/ql/src/codeql_ql/ast/internal/Module.qll | 9 ++++ .../style/AcronymsShouldBeCamelCaseQuery.qll | 50 +++++++++++++++++++ .../style/AcronymsShouldBeCamelCase.ql | 17 +++++++ 4 files changed, 77 insertions(+) create mode 100644 ql/ql/src/codeql_ql/style/AcronymsShouldBeCamelCaseQuery.qll create mode 100644 ql/ql/src/queries/style/AcronymsShouldBeCamelCase.ql diff --git a/ql/ql/src/codeql/Locations.qll b/ql/ql/src/codeql/Locations.qll index 7497525d7af..7d2df1565d8 100644 --- a/ql/ql/src/codeql/Locations.qll +++ b/ql/ql/src/codeql/Locations.qll @@ -28,6 +28,7 @@ class Location extends @location { int getNumLines() { result = getEndLine() - getStartLine() + 1 } /** Gets a textual representation of this element. */ + cached string toString() { exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and diff --git a/ql/ql/src/codeql_ql/ast/internal/Module.qll b/ql/ql/src/codeql_ql/ast/internal/Module.qll index 1e58d34ac53..a5f1eec3043 100644 --- a/ql/ql/src/codeql_ql/ast/internal/Module.qll +++ b/ql/ql/src/codeql_ql/ast/internal/Module.qll @@ -14,6 +14,15 @@ private class ContainerOrModule extends TContainerOrModule { ) { none() } + + /** Gets the kind of this file/module/folder. */ + string getKind() { + this = TFile(_) and result = "file" + or + this = TModule(_) and result = "module" + or + this = TFolder(_) and result = "folder" + } } private class TFileOrModule = TFile or TModule; diff --git a/ql/ql/src/codeql_ql/style/AcronymsShouldBeCamelCaseQuery.qll b/ql/ql/src/codeql_ql/style/AcronymsShouldBeCamelCaseQuery.qll new file mode 100644 index 00000000000..0b4f241e53a --- /dev/null +++ b/ql/ql/src/codeql_ql/style/AcronymsShouldBeCamelCaseQuery.qll @@ -0,0 +1,50 @@ +import ql + +/** + * Gets the name for a `node` that defines something in a QL program. + * E.g. a predicate, class, or module definition. + */ +string getName(AstNode node, string kind) { + result = node.(Class).getName() and kind = "class" + or + // not including CharPreds or db relations. The remaining are: classlessPredicate, classPredicate, newTypeBranch. + result = node.(ClasslessPredicate).getName() and + kind = "classlessPredicate" + or + result = node.(ClassPredicate).getName() and + kind = "classPredicate" + or + result = node.(NewTypeBranch).getName() and + kind = "newtypeBranch" + or + result = node.(NewType).getName() and + kind = "newtype" + or + result = node.(VarDecl).getName() and + kind = "variable" and + not node = any(FieldDecl f).getVarDecl() + or + result = node.(FieldDecl).getName() and kind = "field" + or + result = node.(Module).getName() and kind = "module" +} + +/** + * Holds if `name` seems to contain an upper-cased acronym that could be pascal-cased. + * `name` is the name of `node`, and `kind` describes what kind of definition `node` is. + */ +predicate shouldBePascalCased(string name, AstNode node, string kind) { + name = getName(node, kind) and + ( + // when the acronym is followed by something, then there must be 4 upper-case letters + name.regexpMatch(".*[A-Z]{4,}([^A-Z]).*") + or + // when the acronym is the last part, then we only require 3 upper-case letters + name.regexpMatch(".*[A-Z]{3,}$") + ) and + not node.hasAnnotation("deprecated") and + // allowed upper-case acronyms. + not name.regexpMatch(".*(PEP|AES|DES|EOF).*") and + not (name.regexpMatch("T[A-Z]{3}[^A-Z].*") and node instanceof NewTypeBranch) and + not name.toUpperCase() = name // We are OK with fully-uppercase names. +} diff --git a/ql/ql/src/queries/style/AcronymsShouldBeCamelCase.ql b/ql/ql/src/queries/style/AcronymsShouldBeCamelCase.ql new file mode 100644 index 00000000000..b9b64f93e13 --- /dev/null +++ b/ql/ql/src/queries/style/AcronymsShouldBeCamelCase.ql @@ -0,0 +1,17 @@ +/** + * @name Acronyms should be PascalCase/camelCase. + * @description Acronyms should be PascalCase/camelCase instead of upper-casing all the letters. + * @kind problem + * @problem.severity warning + * @id ql/acronyms-should-be-pascal-case + * @tags correctness + * maintainability + * @precision high + */ + +import ql +import codeql_ql.style.AcronymsShouldBeCamelCaseQuery + +from string name, AstNode node +where shouldBePascalCased(name, node, _) +select node, "Acronyms should be PascalCase/camelCase"