Skip to content

Commit 0aba90d

Browse files
authored
Merge pull request #1299 from guwirth/add-cxx-docu-metric
add cxx specific documentation metrics
2 parents df7418c + 2c08cb1 commit 0aba90d

File tree

4 files changed

+190
-35
lines changed

4 files changed

+190
-35
lines changed

cxx-sensors/src/main/java/org/sonar/cxx/sensors/squid/CxxSquidSensor.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import org.sonar.api.measures.FileLinesContextFactory;
5959
import org.sonar.api.measures.Metric;
6060
import org.sonar.api.rule.RuleKey;
61+
import org.sonar.api.utils.Version;
6162
import org.sonar.api.utils.log.Logger;
6263
import org.sonar.api.utils.log.Loggers;
6364
import org.sonar.cxx.CxxLanguage;
@@ -116,21 +117,25 @@ public CxxSquidSensor(CxxLanguage language,
116117
* {@inheritDoc}
117118
*/
118119
public CxxSquidSensor(CxxLanguage language,
119-
FileLinesContextFactory fileLinesContextFactory,
120-
CheckFactory checkFactory,
121-
@Nullable CustomCxxRulesDefinition[] customRulesDefinition,
122-
@Nullable CxxCoverageCache coverageCache) {
120+
FileLinesContextFactory fileLinesContextFactory,
121+
CheckFactory checkFactory,
122+
@Nullable CustomCxxRulesDefinition[] customRulesDefinition,
123+
@Nullable CxxCoverageCache coverageCache) {
123124
this.checks = CxxChecks.createCxxCheck(checkFactory)
124125
.addChecks(language.getRepositoryKey(), language.getChecks())
125126
.addCustomChecks(customRulesDefinition);
126127
this.fileLinesContextFactory = fileLinesContextFactory;
127128
this.language = language;
128-
129+
129130
if (coverageCache == null) {
130131
this.cache = new CxxCoverageCache();
131132
} else {
132133
this.cache = coverageCache;
133134
}
135+
136+
if (language.getMetricsCache().isEmpty()) {
137+
new CxxMetrics(language);
138+
}
134139
}
135140

136141
@Override
@@ -245,7 +250,7 @@ private void save(Collection<SourceCode> squidSourceFiles, SensorContext context
245250
}
246251
}
247252

248-
private static void saveMeasures(InputFile inputFile, SourceFile squidFile, SensorContext context) {
253+
private void saveMeasures(InputFile inputFile, SourceFile squidFile, SensorContext context) {
249254
context.<Integer>newMeasure().forMetric(CoreMetrics.FILES).on(inputFile).withValue(squidFile.getInt(CxxMetric.FILES)).save();
250255
context.<Integer>newMeasure().forMetric(CoreMetrics.NCLOC).on(inputFile).withValue(squidFile.getInt(CxxMetric.LINES_OF_CODE)).save();
251256
context.<Integer>newMeasure().forMetric(CoreMetrics.STATEMENTS).on(inputFile).withValue(squidFile.getInt(CxxMetric.STATEMENTS)).save();
@@ -254,7 +259,18 @@ private static void saveMeasures(InputFile inputFile, SourceFile squidFile, Sens
254259
context.<Integer>newMeasure().forMetric(CoreMetrics.COMPLEXITY).on(inputFile).withValue(squidFile.getInt(CxxMetric.COMPLEXITY)).save();
255260
context.<Integer>newMeasure().forMetric(CoreMetrics.COMMENT_LINES).on(inputFile).withValue(squidFile.getInt(CxxMetric.COMMENT_LINES)).save();
256261
context.<Integer>newMeasure().forMetric(CoreMetrics.PUBLIC_API).on(inputFile).withValue(squidFile.getInt(CxxMetric.PUBLIC_API)).save();
257-
context.<Integer>newMeasure().forMetric(CoreMetrics.PUBLIC_UNDOCUMENTED_API).on(inputFile).withValue(squidFile.getInt(CxxMetric.PUBLIC_UNDOCUMENTED_API)).save();
262+
context.<Integer>newMeasure().forMetric(CoreMetrics.PUBLIC_UNDOCUMENTED_API).on(inputFile).withValue(squidFile.getInt(CxxMetric.PUBLIC_UNDOCUMENTED_API)).save();
263+
264+
// Configuration properties for SQ 6.2++
265+
// see https://jira.sonarsource.com/browse/SONAR-8328
266+
if (context.getSonarQubeVersion().isGreaterThanOrEqual(Version.create(6, 2))) {
267+
int publicApi = squidFile.getInt(CxxMetric.PUBLIC_API);
268+
int publicUndocumentedApi = squidFile.getInt(CxxMetric.PUBLIC_UNDOCUMENTED_API);
269+
double densityOfPublicDocumentedApi = (publicApi > publicUndocumentedApi) ? ((publicApi - publicUndocumentedApi) / (double)publicApi * 100.0) : 0.0;
270+
context.<Integer>newMeasure().forMetric(language.getMetric(CxxMetrics.PUBLIC_API_KEY)).on(inputFile).withValue(publicApi).save();
271+
context.<Integer>newMeasure().forMetric(language.getMetric(CxxMetrics.PUBLIC_UNDOCUMENTED_API_KEY)).on(inputFile).withValue(publicUndocumentedApi).save();
272+
context.<Double>newMeasure().forMetric(language.getMetric(CxxMetrics.PUBLIC_DOCUMENTED_API_DENSITY_KEY)).on(inputFile).withValue(densityOfPublicDocumentedApi).save();
273+
}
258274
}
259275

260276
private void saveFunctionAndClassComplexityDistribution(InputFile inputFile, SourceFile squidFile, SensorContext context) {

cxx-sensors/src/main/java/org/sonar/cxx/sensors/utils/CxxMetrics.java

Lines changed: 67 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,36 +44,88 @@
4444
public class CxxMetrics implements Metrics {
4545

4646
private final CxxLanguage language;
47+
private final String domain;
48+
49+
// Introduce own documentation metrics, after they has been removed from SQ core
50+
// see https://jira.sonarsource.com/browse/SONAR-8328
51+
public static final String PUBLIC_API_KEY = "public_api";
52+
public static final String PUBLIC_UNDOCUMENTED_API_KEY = "public_undocumented_api";
53+
public static final String PUBLIC_DOCUMENTED_API_DENSITY_KEY = "public_documented_api_density";
4754

4855
/**
4956
* CxxMetrics
5057
*
5158
* @param language for metrics
52-
*
59+
*
5360
*/
5461
public CxxMetrics(CxxLanguage language) {
5562
this.language = language;
63+
this.domain = language.getKey().toUpperCase(Locale.ENGLISH);
64+
65+
Metric<?> metric = new Metric.Builder(getKey(PUBLIC_API_KEY, language), "Public API", Metric.ValueType.INT)
66+
.setDescription("Public API")
67+
.setDirection(Metric.DIRECTION_WORST)
68+
.setQualitative(false)
69+
.setDomain(this.domain)
70+
.create();
71+
saveMetric(PUBLIC_API_KEY, metric);
72+
73+
metric = new Metric.Builder(getKey(PUBLIC_DOCUMENTED_API_DENSITY_KEY, language), "Public Documented API (%)", Metric.ValueType.PERCENT)
74+
.setDescription("Public documented classes and functions balanced by ncloc")
75+
.setDirection(Metric.DIRECTION_BETTER)
76+
.setQualitative(true)
77+
.setDomain(this.domain)
78+
.setWorstValue(0.0)
79+
.setBestValue(100.0)
80+
.setOptimizedBestValue(true)
81+
.create();
82+
saveMetric(PUBLIC_DOCUMENTED_API_DENSITY_KEY, metric);
5683

57-
buildMetric(CxxCompilerSensor.KEY, "Compiler issues", language);
58-
buildMetric(CxxCppCheckSensor.KEY, "CppCheck issues", language);
59-
buildMetric(CxxOtherSensor.KEY, "Other tools issues", language);
60-
buildMetric(CxxPCLintSensor.KEY, "PC-Lint issues", language);
61-
buildMetric(CxxRatsSensor.KEY, "Rats issues", language);
62-
buildMetric(CxxSquidSensor.KEY, "Squid issues", language);
63-
buildMetric(CxxValgrindSensor.KEY, "Valgrind issues", language);
64-
buildMetric(CxxVeraxxSensor.KEY, "Vera issues", language);
65-
buildMetric(CxxDrMemorySensor.KEY, "DrMemory issues", language);
66-
buildMetric(CxxClangSASensor.KEY, "ClangSA issues", language);
67-
buildMetric(CxxClangTidySensor.KEY, "ClangTidy issues", language);
84+
metric = new Metric.Builder(getKey(PUBLIC_UNDOCUMENTED_API_KEY, language), "Public Undocumented API", Metric.ValueType.INT)
85+
.setDescription("Public undocumented classes, functions and variables")
86+
.setDirection(Metric.DIRECTION_WORST)
87+
.setQualitative(true)
88+
.setDomain(this.domain)
89+
.setBestValue(0.0)
90+
.setDirection(Metric.DIRECTION_WORST)
91+
.setOptimizedBestValue(true)
92+
.create();
93+
saveMetric(PUBLIC_UNDOCUMENTED_API_KEY, metric);
94+
95+
saveMetric(CxxCompilerSensor.KEY, buildReportMetric(CxxCompilerSensor.KEY, "Compiler issues"));
96+
saveMetric(CxxCppCheckSensor.KEY, buildReportMetric(CxxCppCheckSensor.KEY, "CppCheck issues"));
97+
saveMetric(CxxOtherSensor.KEY, buildReportMetric(CxxOtherSensor.KEY, "Other tools issues"));
98+
saveMetric(CxxPCLintSensor.KEY, buildReportMetric(CxxPCLintSensor.KEY, "PC-Lint issues"));
99+
saveMetric(CxxRatsSensor.KEY, buildReportMetric(CxxRatsSensor.KEY, "Rats issues"));
100+
saveMetric(CxxSquidSensor.KEY, buildReportMetric(CxxSquidSensor.KEY, "Squid issues"));
101+
saveMetric(CxxValgrindSensor.KEY, buildReportMetric(CxxValgrindSensor.KEY, "Valgrind issues"));
102+
saveMetric(CxxVeraxxSensor.KEY, buildReportMetric(CxxVeraxxSensor.KEY, "Vera issues"));
103+
saveMetric(CxxDrMemorySensor.KEY, buildReportMetric(CxxDrMemorySensor.KEY, "DrMemory issues"));
104+
saveMetric(CxxClangSASensor.KEY, buildReportMetric(CxxClangSASensor.KEY, "ClangSA issues"));
105+
saveMetric(CxxClangTidySensor.KEY, buildReportMetric(CxxClangTidySensor.KEY, "ClangTidy issues"));
106+
}
107+
108+
private Metric<?> buildReportMetric(String key, String description) {
109+
String effectiveKey = CxxMetrics.getKey(key, this.language);
110+
Metric<?> metric = new Metric.Builder(effectiveKey, description, Metric.ValueType.INT)
111+
.setDirection(Metric.DIRECTION_WORST)
112+
.setQualitative(Boolean.TRUE)
113+
.setDomain(this.domain)
114+
.create();
115+
return metric;
116+
}
117+
118+
private Boolean saveMetric(String key, Metric<?> metric) {
119+
return this.language.SaveMetric(metric, key);
68120
}
69121

70122
/**
71-
* GetKey
123+
* getKey
72124
*
73125
* @param key for language
74126
* @param language for metrics
75-
* @return String
76-
*
127+
* @return effective key
128+
*
77129
*/
78130
public static String getKey(String key, CxxLanguage language) {
79131
return language.getPropertiesKey().toUpperCase(Locale.ENGLISH) + "-" + key.toUpperCase(Locale.ENGLISH);
@@ -83,15 +135,4 @@ public static String getKey(String key, CxxLanguage language) {
83135
public List<Metric> getMetrics() {
84136
return new ArrayList(this.language.getMetricsCache());
85137
}
86-
87-
private static void buildMetric(String key, String description, CxxLanguage language) {
88-
String effectiveKey = CxxMetrics.getKey(key, language);
89-
Metric<?> metric = new Metric.Builder(effectiveKey, description, Metric.ValueType.INT)
90-
.setDirection(Metric.DIRECTION_WORST)
91-
.setQualitative(Boolean.TRUE)
92-
.setDomain(language.getKey().toUpperCase(Locale.ENGLISH))
93-
.create();
94-
95-
language.SaveMetric(metric, key);
96-
}
97138
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Sonar C++ Plugin (Community)
3+
* Copyright (C) 2010-2017 SonarOpenCommunity
4+
* http://github.com/SonarOpenCommunity/sonar-cxx
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
package org.sonar.cxx.sensors.utils;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import org.junit.Before;
25+
import org.junit.Test;
26+
import org.sonar.api.config.Settings;
27+
import org.sonar.api.measures.Metric;
28+
import org.sonar.cxx.CxxLanguage;
29+
30+
public class CxxMetricsTest {
31+
32+
private CxxLanguage language;
33+
private CxxMetrics metrics;
34+
35+
public class CxxLanguageImpl extends CxxLanguage {
36+
37+
public CxxLanguageImpl(Settings settings) {
38+
super("c++", "c++", settings);
39+
}
40+
41+
@Override
42+
public String[] getFileSuffixes() {
43+
return new String[]{};
44+
}
45+
46+
@Override
47+
public String[] getSourceFileSuffixes() {
48+
return new String[]{};
49+
}
50+
51+
@Override
52+
public String[] getHeaderFileSuffixes() {
53+
return new String[]{};
54+
}
55+
56+
@Override
57+
public String getPropertiesKey() {
58+
return "cxx";
59+
}
60+
61+
@Override
62+
public List<Class> getChecks() {
63+
return new ArrayList<>();
64+
}
65+
66+
@Override
67+
public String getRepositoryKey() {
68+
return "cxx";
69+
}
70+
71+
}
72+
73+
@Before
74+
public void setUp() {
75+
language = new CxxLanguageImpl(new Settings());
76+
metrics = new CxxMetrics(language);
77+
}
78+
79+
@Test
80+
public void getMetricsTest() {
81+
List<Metric> list = metrics.getMetrics();
82+
assert (list.size() == 14);
83+
}
84+
85+
@Test
86+
public void getMetricTest() {
87+
Metric metric = language.getMetric(CxxMetrics.PUBLIC_API_KEY);
88+
assert (metric != null);
89+
90+
metric = language.getMetric(CxxMetrics.PUBLIC_UNDOCUMENTED_API_KEY);
91+
assert (metric != null);
92+
93+
metric = language.getMetric(CxxMetrics.PUBLIC_DOCUMENTED_API_DENSITY_KEY);
94+
assert (metric != null);
95+
}
96+
}

cxx-squid/src/main/java/org/sonar/cxx/CxxLanguage.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,12 @@ public boolean hasKey(String key) {
111111
return this.settings.hasKey(getPluginProperty(key));
112112
}
113113

114-
public void SaveMetric(Metric metric, String key) {
114+
public boolean SaveMetric(Metric metric, String key) {
115115
if (!MetricsCache.containsKey(key)) {
116116
MetricsCache.put(key, metric);
117-
}
117+
return true;
118+
}
119+
return false;
118120
}
119121

120122
public Collection<Metric> getMetricsCache() {

0 commit comments

Comments
 (0)