Skip to content

Commit aa0a835

Browse files
committed
Add support for guideline recategorizations
This commit adds: - A new section `guideline-recategorizations` to the configuration specification for `coding-standards.yml`. - Two tests to list all the indexed guideline recategorizations and all the invalid guideline recategorizations. This commit does not include the application of the effective category.
1 parent 8647dd4 commit aa0a835

15 files changed

+253
-30
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* A module for runtime configuration settings specified in a `conding-standards.yml` file.
3+
*/
4+
5+
import cpp
6+
import semmle.code.cpp.XML
7+
import codingstandards.cpp.exclusions.RuleMetadata
8+
import codingstandards.cpp.deviations.Deviations
9+
10+
/** A `coding-standards.xml` configuration file (usually generated from an YAML configuration file). */
11+
class CodingStandardsFile extends XMLFile {
12+
CodingStandardsFile() {
13+
this.getBaseName() = "coding-standards.xml" and
14+
// Must be within the users source code.
15+
exists(this.getRelativePath())
16+
}
17+
}
18+
19+
class CodingStandardsConfigSection extends XMLElement {
20+
CodingStandardsConfigSection() { getParent() instanceof CodingStandardsConfig }
21+
}
22+
23+
/** A "Coding Standards" configuration file */
24+
class CodingStandardsConfig extends XMLElement {
25+
CodingStandardsConfig() {
26+
any(CodingStandardsFile csf).getARootElement() = this and
27+
this.getName() = "codingstandards"
28+
}
29+
30+
/** Get a section in this configuration file. */
31+
CodingStandardsConfigSection getASection() { result.getParent() = this }
32+
}

cpp/common/src/codingstandards/cpp/deviations/Deviations.qll

+5-30
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import cpp
88
import semmle.code.cpp.XML
99
import codingstandards.cpp.exclusions.RuleMetadata
10+
import codingstandards.cpp.Config
1011

1112
predicate applyDeviationsAtQueryLevel() {
1213
not exists(CodingStandardsReportDeviatedAlerts reportDeviatedResults |
@@ -15,26 +16,6 @@ predicate applyDeviationsAtQueryLevel() {
1516
)
1617
}
1718

18-
/** A `coding-standards.xml` configuration file (usually generated from an YAML configuration file). */
19-
class CodingStandardsFile extends XMLFile {
20-
CodingStandardsFile() {
21-
this.getBaseName() = "coding-standards.xml" and
22-
// Must be within the users source code.
23-
exists(this.getRelativePath())
24-
}
25-
}
26-
27-
/** A "Coding Standards" configuration file */
28-
class CodingStandardsConfig extends XMLElement {
29-
CodingStandardsConfig() {
30-
any(CodingStandardsFile csf).getARootElement() = this and
31-
this.getName() = "codingstandards"
32-
}
33-
34-
/** Gets a deviation record for this configuration. */
35-
DeviationRecord getADeviationRecord() { result = getAChild().(DeviationRecords).getAChild() }
36-
}
37-
3819
/** An element which tells the analysis whether to report deviated results. */
3920
class CodingStandardsReportDeviatedAlerts extends XMLElement {
4021
CodingStandardsReportDeviatedAlerts() {
@@ -44,19 +25,13 @@ class CodingStandardsReportDeviatedAlerts extends XMLElement {
4425
}
4526

4627
/** A container of deviation records. */
47-
class DeviationRecords extends XMLElement {
48-
DeviationRecords() {
49-
getParent() instanceof CodingStandardsConfig and
50-
hasName("deviations")
51-
}
28+
class DeviationRecords extends CodingStandardsConfigSection {
29+
DeviationRecords() { hasName("deviations") }
5230
}
5331

5432
/** A container for the deviation permits records. */
55-
class DeviationPermits extends XMLElement {
56-
DeviationPermits() {
57-
getParent() instanceof CodingStandardsConfig and
58-
hasName("deviation-permits")
59-
}
33+
class DeviationPermits extends CodingStandardsConfigSection {
34+
DeviationPermits() { hasName("deviation-permits") }
6035
}
6136

6237
/** A deviation permit record, that is specified by a permit identifier */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* A module for identifying guideline recategorizations specified in a `conding-standards.yml` file.
3+
*/
4+
5+
import cpp
6+
import semmle.code.cpp.XML
7+
import codingstandards.cpp.exclusions.RuleMetadata
8+
import codingstandards.cpp.Config
9+
10+
/** A container of guideline recategorizations. */
11+
class GuidelineRecategorizations extends CodingStandardsConfigSection {
12+
GuidelineRecategorizations() { hasName("guideline-recategorizations") }
13+
}
14+
15+
newtype TEffectiveCategory =
16+
TInvalid(string reason) {
17+
exists(GuidelineRecategorization gr | reason = gr.getAnInvalidReason())
18+
} or
19+
TDisapplied() or
20+
TAdvisory() or
21+
TRequired() or
22+
TMandatory()
23+
24+
class EffectiveCategory extends TEffectiveCategory {
25+
string toString() {
26+
this instanceof TInvalid and result = "invalid"
27+
or
28+
this instanceof TDisapplied and result = "disapplied"
29+
or
30+
this instanceof TAdvisory and result = "advisory"
31+
or
32+
this instanceof TRequired and result = "required"
33+
or
34+
this instanceof TMandatory and result = "mandatory"
35+
}
36+
37+
/** Holds if the effective category permits a deviation */
38+
predicate permitsDeviation() { not this instanceof TMandatory and not this instanceof TInvalid }
39+
}
40+
41+
class GuidelineRecategorization extends XMLElement {
42+
GuidelineRecategorization() {
43+
getParent() instanceof GuidelineRecategorizations and
44+
hasName("guideline-recategorizations-entry")
45+
}
46+
47+
string getRuleId() { result = getAChild("rule-id").getTextValue() }
48+
49+
string getCategory() { result = getAChild("category").getTextValue() }
50+
51+
/** Get a query for which a recategorization is specified. */
52+
Query getQuery() { result.getRuleId() = getRuleId() }
53+
54+
private EffectiveCategory getValidEffectiveCategory() {
55+
exists(string category, string recategorization |
56+
category = getQuery().getCategory() and
57+
recategorization = getCategory()
58+
|
59+
result = TMandatory() and
60+
category = ["advisory", "required"] and
61+
recategorization = "mandatory"
62+
or
63+
result = TRequired() and
64+
category = "advisory" and
65+
recategorization = "required"
66+
or
67+
result = TDisapplied() and
68+
category = "advisory" and
69+
recategorization = "disapplied"
70+
)
71+
}
72+
73+
private predicate isValidRecategorization(string category, string recategorization) {
74+
category = ["advisory", "required"] and
75+
recategorization = "mandatory"
76+
or
77+
category = "advisory" and
78+
recategorization = "required"
79+
or
80+
category = "advisory" and
81+
recategorization = "disapplied"
82+
}
83+
84+
string getAnInvalidReason() {
85+
not isValidRecategorization(this.getQuery().getCategory(), this.getCategory()) and
86+
if exists(this.getQuery())
87+
then
88+
result =
89+
"Invalid recategorization from '" + this.getQuery().getCategory() + "' to '" +
90+
this.getCategory() + "'."
91+
else result = "Unknown rule id '" + this.getRuleId() + "'."
92+
}
93+
94+
predicate isValid() { not isInvalid() }
95+
96+
predicate isInvalid() { getEffectiveCategory() = TInvalid(_) }
97+
98+
EffectiveCategory getEffectiveCategory() {
99+
(
100+
if exists(getValidEffectiveCategory())
101+
then result = getValidEffectiveCategory()
102+
else result = TInvalid(getAnInvalidReason())
103+
)
104+
}
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @id cpp/coding-standards/invalid-guideline-recategorizations
3+
* @name Invalid guideline recategorizations
4+
* @description Guideline recategorizations marked as invalid will not be applied.
5+
*/
6+
7+
import cpp
8+
import GuidelineRecategorizations
9+
10+
from GuidelineRecategorization gr
11+
select gr,
12+
gr.getFile().getRelativePath() + ": '" + gr.getAnInvalidReason() + "' for rule " + gr.getRuleId() +
13+
"."
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* @id cpp/coding-standards/list-guideline-recategorizations
3+
* @kind table
4+
* @name List all guideline recategorizations observed in a database
5+
* @description Lists all the guideline recategorizations that were indexed in the database.
6+
*/
7+
8+
import cpp
9+
import GuidelineRecategorizations
10+
11+
from GuidelineRecategorization gr
12+
select gr.getRuleId(), gr.getCategory()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| invalid/coding-standards.xml:5:7:8:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'advisory'.' for rule A0-1-1. |
2+
| invalid/coding-standards.xml:9:7:12:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'disapplied'.' for rule A0-1-2. |
3+
| invalid/coding-standards.xml:13:7:16:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Unknown rule id 'A1-4-3'.' for rule A1-4-3. |
4+
| invalid/coding-standards.xml:17:7:20:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-13-6. |
5+
| invalid/coding-standards.xml:21:7:24:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'rule' to 'required'.' for rule CON50-CPP. |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
codingstandards/cpp/guideline_recategorizations/InvalidGuidelineRecategorizations.ql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
| A0-1-1 | advisory |
2+
| A0-1-1 | mandatory |
3+
| A0-1-2 | disapplied |
4+
| A0-1-6 | disapplied |
5+
| A1-4-3 | mandatory |
6+
| A10-4-1 | required |
7+
| A11-0-1 | mandatory |
8+
| CON50-CPP | required |
9+
| RULE-13-6 | required |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
codingstandards/cpp/guideline_recategorizations/ListGuidelineRecategorizations.ql
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?xml version="1.0"?>
2+
<!-- Dummy XML file in root of test to ensure the XML extractor is invoked on CLIs prior to v2.10.3. -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" ?>
2+
<codingstandards>
3+
<!--GENERATED: DO NOT MODIFY. Changes should be made to coding-standards.yml instead.-->
4+
<guideline-recategorizations>
5+
<guideline-recategorizations-entry>
6+
<rule-id>A0-1-1</rule-id>
7+
<category>advisory</category>
8+
</guideline-recategorizations-entry>
9+
<guideline-recategorizations-entry>
10+
<rule-id>A0-1-2</rule-id>
11+
<category>disapplied</category>
12+
</guideline-recategorizations-entry>
13+
<guideline-recategorizations-entry>
14+
<rule-id>A1-4-3</rule-id>
15+
<category>mandatory</category>
16+
</guideline-recategorizations-entry>
17+
<guideline-recategorizations-entry>
18+
<rule-id>RULE-13-6</rule-id>
19+
<category>required</category>
20+
</guideline-recategorizations-entry>
21+
<guideline-recategorizations-entry>
22+
<rule-id>CON50-CPP</rule-id>
23+
<category>required</category>
24+
</guideline-recategorizations-entry>
25+
</guideline-recategorizations>
26+
</codingstandards>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
guideline-recategorizations:
2+
- rule-id: "A0-1-1"
3+
category: "advisory"
4+
- rule-id: "A0-1-2"
5+
category: "disapplied"
6+
- rule-id: "A1-4-3"
7+
category: "mandatory"
8+
- rule-id: "RULE-13-6"
9+
category: "required"
10+
- rule-id: "CON50-CPP"
11+
category: "required"

cpp/common/test/guideline_recategorizations/test.cpp

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" ?>
2+
<codingstandards>
3+
<!--GENERATED: DO NOT MODIFY. Changes should be made to coding-standards.yml instead.-->
4+
<guideline-recategorizations>
5+
<guideline-recategorizations-entry>
6+
<rule-id>A0-1-1</rule-id>
7+
<category>mandatory</category>
8+
</guideline-recategorizations-entry>
9+
<guideline-recategorizations-entry>
10+
<rule-id>A0-1-6</rule-id>
11+
<category>disapplied</category>
12+
</guideline-recategorizations-entry>
13+
<guideline-recategorizations-entry>
14+
<rule-id>A10-4-1</rule-id>
15+
<category>required</category>
16+
</guideline-recategorizations-entry>
17+
<guideline-recategorizations-entry>
18+
<rule-id>A11-0-1</rule-id>
19+
<category>mandatory</category>
20+
</guideline-recategorizations-entry>
21+
</guideline-recategorizations>
22+
</codingstandards>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
guideline-recategorizations:
2+
- rule-id: "A0-1-1"
3+
category: "mandatory"
4+
- rule-id: "A0-1-6"
5+
category: "disapplied"
6+
- rule-id: "A10-4-1"
7+
category: "required"
8+
- rule-id: "A11-0-1"
9+
category: "mandatory"

0 commit comments

Comments
 (0)