Skip to content

Commit 6dc3205

Browse files
committed
Rule 8.7: Improve performance
This rule was identified as containing one of the slowest predicates in our C Coding Standards query suites, and this commit improves the performance. Performance is improved with the following changes: (a) Factoring out a predicate for the repeated calls to getTarget(), to avoid duplication and to create a semantically meaningful predicate which gets the target for a reference to an external identifier. (b) Use the factored out predicate to refine the reference class to only be references to external identifiers. This reduces the size of the class. (c) Create a predicate for computing a table of external identifiers, references to those identifiers and the translation units those exist in. We can then compute this table once, and use it in both the "find me a reference to this external identifier" case and in the "where the external identifier is not referenced in any other translation unit" case. Part (c) is the critical change. Without that, the optimizer was creating an expensive join order in the negation case, where it was effectively creating a cross product of all references to each external identifier, before later excluding on the negation. The use of our predicate in the negation case means we can first create a table of external identifiers and translation units, then apply that in the negation case without cross producting the references.
1 parent 917c62e commit 6dc3205

File tree

1 file changed

+24
-15
lines changed

1 file changed

+24
-15
lines changed

c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,36 @@ import codingstandards.c.misra
2020
import codingstandards.cpp.Identifiers
2121
import codingstandards.cpp.Scope
2222

23+
ExternalIdentifiers getExternalIdentifierTarget(NameQualifiableElement nqe) {
24+
result = nqe.(Access).getTarget()
25+
or
26+
result = nqe.(FunctionCall).getTarget()
27+
}
28+
2329
/**
24-
* Re-introduce function calls into access description as
25-
* "any reference"
30+
* A reference to an external identifier, either as an `Access` or a `FunctionCall`.
2631
*/
27-
class Reference extends NameQualifiableElement {
28-
Reference() {
29-
this instanceof Access or
30-
this instanceof FunctionCall
31-
}
32+
class ExternalIdentifierReference extends NameQualifiableElement {
33+
ExternalIdentifierReference() { exists(getExternalIdentifierTarget(this)) }
34+
35+
ExternalIdentifiers getExternalIdentifierTarget() { result = getExternalIdentifierTarget(this) }
36+
}
37+
38+
predicate isReferencedInTranslationUnit(
39+
ExternalIdentifiers e, ExternalIdentifierReference r, TranslationUnit t
40+
) {
41+
r.getExternalIdentifierTarget() = e and
42+
r.getFile() = t
3243
}
3344

34-
from ExternalIdentifiers e, Reference a1, TranslationUnit t1
45+
from ExternalIdentifiers e, ExternalIdentifierReference a1, TranslationUnit t1
3546
where
3647
not isExcluded(e, Declarations6Package::shouldNotBeDefinedWithExternalLinkageQuery()) and
37-
(a1.(Access).getTarget() = e or a1.(FunctionCall).getTarget() = e) and
38-
a1.getFile() = t1 and
39-
//not accessed in any other translation unit
40-
not exists(TranslationUnit t2, Reference a2 |
41-
not t1 = t2 and
42-
(a2.(Access).getTarget() = e or a2.(FunctionCall).getTarget() = e) and
43-
a2.getFile() = t2
48+
isReferencedInTranslationUnit(e, a1, t1) and
49+
// Not referenced in any other translation unit
50+
not exists(TranslationUnit t2 |
51+
isReferencedInTranslationUnit(e, _, t2) and
52+
not t1 = t2
4453
)
4554
select e, "Declaration with external linkage is accessed in only one translation unit $@.", a1,
4655
a1.toString()

0 commit comments

Comments
 (0)