QL: add query detecting upper-case acronyms

This commit is contained in:
Erik Krogh Kristensen
2022-03-03 19:22:41 +01:00
parent df9533f46e
commit e3a15792fa
4 changed files with 77 additions and 0 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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.
}

View File

@@ -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"