mirror of
https://github.com/github/codeql.git
synced 2026-01-04 10:10:20 +01:00
72 lines
2.4 KiB
Plaintext
72 lines
2.4 KiB
Plaintext
/**
|
|
* @name Feature envy
|
|
* @description A function that uses more functions and variables from another file than functions and variables from its own file. This function might be better placed in the other file, to avoid exposing internals of the file it depends on.
|
|
* @kind problem
|
|
* @problem.severity recommendation
|
|
* @precision medium
|
|
* @id cpp/feature-envy
|
|
* @tags maintainability
|
|
* modularity
|
|
* statistical
|
|
* non-attributable
|
|
*/
|
|
|
|
import cpp
|
|
|
|
predicate functionUsesVariable(Function source, Variable v, File target) {
|
|
v.getAnAccess().getEnclosingFunction() = source and
|
|
not v.(LocalScopeVariable).getFunction() = source and
|
|
v.getFile() = target
|
|
}
|
|
|
|
predicate functionUsesFunction(Function source, Function f, File target) {
|
|
exists(FunctionCall fc | fc.getEnclosingFunction() = source and fc.getTarget() = f) and
|
|
f.getFile() = target
|
|
}
|
|
|
|
predicate dependencyCount(Function source, File target, int res) {
|
|
res =
|
|
strictcount(Declaration d |
|
|
functionUsesVariable(source, d, target) or
|
|
functionUsesFunction(source, d, target)
|
|
)
|
|
}
|
|
|
|
predicate selfDependencyCountOrZero(Function source, int res) {
|
|
exists(File target | target = source.getFile() and onlyInFile(source, target) |
|
|
res = max(int i | dependencyCount(source, target, i) or i = 0)
|
|
)
|
|
}
|
|
|
|
predicate dependsHighlyOn(Function source, File target, int res) {
|
|
dependencyCount(source, target, res) and
|
|
target.fromSource() and
|
|
exists(int selfCount |
|
|
selfDependencyCountOrZero(source, selfCount) and
|
|
res > 2 * selfCount and
|
|
res > 4
|
|
)
|
|
}
|
|
|
|
predicate onlyInFile(Function f, File file) {
|
|
file = f.getFile() and
|
|
not exists(File file2 | file2 = f.getFile() and file2 != file)
|
|
}
|
|
|
|
from Function f, File other, int selfCount, int depCount, string selfDeps
|
|
where
|
|
dependsHighlyOn(f, other, depCount) and
|
|
selfDependencyCountOrZero(f, selfCount) and
|
|
not exists(File yetAnother | dependsHighlyOn(f, yetAnother, _) and yetAnother != other) and
|
|
not other instanceof HeaderFile and
|
|
not f instanceof MemberFunction and
|
|
if selfCount = 0
|
|
then selfDeps = "0 dependencies"
|
|
else
|
|
if selfCount = 1
|
|
then selfDeps = "only 1 dependency"
|
|
else selfDeps = "only " + selfCount.toString() + " dependencies"
|
|
select f,
|
|
"Function " + f.getName() + " could be moved to file $@" + " since it has " + depCount.toString() +
|
|
" dependencies to that file, but " + selfDeps + " to its own file.", other, other.getBaseName()
|