mirror of
https://github.com/github/codeql.git
synced 2025-12-23 04:06:37 +01:00
CPP: Rewrite the VDE grouping in ClassesWithManyField.ql to be more performant (and modern).
This commit is contained in:
@@ -33,70 +33,133 @@ predicate vdeInfo(VariableDeclarationEntry vde, Class c, File f, int line)
|
||||
line = vde.getLocation().getStartLine()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `previous` describes a `VariableDeclarationEntry` occurring soon before
|
||||
* `vde` (this may have many results).
|
||||
*/
|
||||
predicate previousVde(VariableDeclarationEntry previous, VariableDeclarationEntry vde)
|
||||
{
|
||||
exists(Class c, File f, int line | vdeInfo(vde, c, f, line) |
|
||||
vdeInfo(previous, c, f, line - 3) or
|
||||
vdeInfo(previous, c, f, line - 2) or
|
||||
vdeInfo(previous, c, f, line - 1) or
|
||||
(vdeInfo(previous, c, f, line) and exists(int prevCol, int vdeCol |
|
||||
prevCol = previous.getLocation().getStartColumn() and vdeCol = vde.getLocation().getStartColumn() |
|
||||
prevCol < vdeCol or (prevCol = vdeCol and previous.getName() < vde.getName())
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* The first `VariableDeclarationEntry` in a group.
|
||||
*/
|
||||
predicate masterVde(VariableDeclarationEntry master, VariableDeclarationEntry vde)
|
||||
{
|
||||
(not previousVde(_, vde) and master = vde) or
|
||||
exists(VariableDeclarationEntry previous | previousVde(previous, vde) and masterVde(master, previous))
|
||||
}
|
||||
|
||||
/**
|
||||
* A group of `VariableDeclaratinEntry`'s in the same class and in close proximity
|
||||
* to each other.
|
||||
*/
|
||||
class VariableDeclarationGroup extends ElementBase {
|
||||
VariableDeclarationGroup() {
|
||||
this instanceof VariableDeclarationEntry and
|
||||
not previousVde(_, this)
|
||||
newtype TVariableDeclarationInfo =
|
||||
TVariableDeclarationLine(Class c, File f, int line) {
|
||||
vdeInfo(_, c, f, line)
|
||||
}
|
||||
|
||||
/**
|
||||
* A line that contains one or more `VariableDeclarationEntry`s (in the same class).
|
||||
*/
|
||||
class VariableDeclarationLine extends TVariableDeclarationInfo
|
||||
{
|
||||
Class c;
|
||||
File f;
|
||||
int line;
|
||||
|
||||
VariableDeclarationLine() {
|
||||
vdeInfo(_, c, f, line) and
|
||||
this = TVariableDeclarationLine(c, f, line)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class associated with this `VariableDeclarationLine`.
|
||||
*/
|
||||
Class getClass() {
|
||||
vdeInfo(this, result, _, _)
|
||||
result = c
|
||||
}
|
||||
|
||||
// pragma[noopt] since otherwise the two locationInfo relations get join-ordered
|
||||
// after each other
|
||||
pragma[noopt]
|
||||
predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) {
|
||||
exists(VariableDeclarationEntry last, Location lstart, Location lend |
|
||||
masterVde(this, last) and
|
||||
this instanceof VariableDeclarationGroup and
|
||||
not previousVde(last, _) and
|
||||
exists(VariableDeclarationEntry vde | vde=this and vde instanceof VariableDeclarationEntry and vde.getLocation() = lstart) and
|
||||
last.getLocation() = lend and
|
||||
lstart.hasLocationInfo(path, startline, startcol, _, _) and
|
||||
lend.hasLocationInfo(path, _, _, endline, endcol)
|
||||
/**
|
||||
* Gets the line of this `VariableDeclarationLine`.
|
||||
*/
|
||||
int getLine() {
|
||||
result = line
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `VariableDeclarationEntry` on this line.
|
||||
*/
|
||||
VariableDeclarationEntry getAVDE()
|
||||
{
|
||||
vdeInfo(result, c, f, line)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the start column of the first `VariableDeclarationEntry` on this line.
|
||||
*/
|
||||
int getStartColumn() {
|
||||
result = min(getAVDE().getLocation().getStartColumn())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the end column of the last `VariableDeclarationEntry` on this line.
|
||||
*/
|
||||
int getEndColumn() {
|
||||
result = max(getAVDE().getLocation().getEndColumn())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank of this `VariableDeclarationLine` in it's file and class
|
||||
* (that is, the first is 0, the second is 1 and so on).
|
||||
*/
|
||||
private int getRank() {
|
||||
line = rank[result](VariableDeclarationLine vdl, int l |
|
||||
vdl = TVariableDeclarationLine(c, f, l) |
|
||||
l
|
||||
)
|
||||
}
|
||||
|
||||
string describeGroup() {
|
||||
if previousVde(this, _) then
|
||||
result = "group of "
|
||||
+ strictcount(string name
|
||||
| exists(VariableDeclarationEntry vde
|
||||
| masterVde(this, vde) and
|
||||
name = vde.getName()))
|
||||
+ " fields here"
|
||||
else
|
||||
result = "declaration of " + this.(VariableDeclarationEntry).getVariable().getName()
|
||||
/**
|
||||
* Gets the `VariableDeclarationLine` following this one, if any.
|
||||
*/
|
||||
VariableDeclarationLine getNext() {
|
||||
result = TVariableDeclarationLine(c, f, _) and
|
||||
result.getRank() = getRank() + 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `VariableDeclarationLine` following this one, if it is nearby.
|
||||
*/
|
||||
VariableDeclarationLine getProximateNext() {
|
||||
result = getNext() and
|
||||
result.getLine() <= this.getLine() + 3
|
||||
}
|
||||
|
||||
string toString() {
|
||||
result = "VariableDeclarationLine"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A group of `VariableDeclarationEntry`s in the same class that are approximately
|
||||
* contiguous.
|
||||
*/
|
||||
class VariableDeclarationGroup extends VariableDeclarationLine
|
||||
{
|
||||
VariableDeclarationLine end;
|
||||
|
||||
VariableDeclarationGroup() {
|
||||
// there is no `VariableDeclarationLine` within three lines previously
|
||||
not any(VariableDeclarationLine prev).getProximateNext() = this and
|
||||
|
||||
// `end` is the last transitively proximate line
|
||||
end = getProximateNext*() and
|
||||
not exists(end.getProximateNext())
|
||||
}
|
||||
|
||||
predicate hasLocationInfo(string path, int startline, int startcol, int endline, int endcol) {
|
||||
path = f.getAbsolutePath() and
|
||||
startline = getLine() and
|
||||
startcol = getStartColumn() and
|
||||
endline = end.getLine() and
|
||||
endcol = end.getEndColumn()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of uniquely named `VariableDeclarationEntry`s in this group.
|
||||
*/
|
||||
int getCount() {
|
||||
result = count(VariableDeclarationLine l | l = getProximateNext*() | l.getAVDE().getVariable().getName())
|
||||
}
|
||||
|
||||
override string toString() {
|
||||
(
|
||||
getCount() = 1 and
|
||||
result = "declaration of " + getAVDE().getVariable().getName()
|
||||
) or (
|
||||
getCount() > 1 and
|
||||
result = "group of " + getCount() + " fields here"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,4 +191,4 @@ where n = strictcount(string fieldName
|
||||
c = vdg.getClass() and
|
||||
if c.hasOneVariableGroup() then suffix = "" else suffix = " - see $@"
|
||||
select c, kindstr(c) + " " + c.getName() + " has " + n + " fields; we suggest refactoring to 15 fields or fewer" + suffix + ".",
|
||||
vdg, vdg.describeGroup()
|
||||
vdg, vdg.toString()
|
||||
|
||||
Reference in New Issue
Block a user