Skip to content

Commit 11147b7

Browse files
authored
Merge pull request spotbugs#110 from h3xstream/master
Enhancements for 3.5 release
2 parents 727616a + 4868475 commit 11147b7

File tree

12 files changed

+287
-79
lines changed

12 files changed

+287
-79
lines changed

src/main/java/org/sonar/plugins/findbugs/FindbugsConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
@BatchSide
5959
public class FindbugsConfiguration {
6060

61-
private static final Logger LOG = LoggerFactory.getLogger(FindbugsExecutor.class);
61+
private static final Logger LOG = LoggerFactory.getLogger(FindbugsConfiguration.class);
6262

6363
private final FileSystem fileSystem;
6464
private final Settings settings;

src/main/java/org/sonar/plugins/findbugs/FindbugsProfileExporter.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ public void exportProfile(RulesProfile profile, Writer writer) {
6565
public static FindBugsFilter buildFindbugsFilter(Iterable<ActiveRule> activeRules) {
6666
FindBugsFilter root = new FindBugsFilter();
6767
for (ActiveRule activeRule : activeRules) {
68-
if (FindbugsRulesDefinition.REPOSITORY_KEY.equals(activeRule.getRepositoryKey()) ||
69-
FbContribRulesDefinition.REPOSITORY_KEY.equals(activeRule.getRepositoryKey()) ||
70-
FindSecurityBugsRulesDefinition.REPOSITORY_KEY.equals(activeRule.getRepositoryKey()) ||
71-
FindSecurityBugsJspRulesDefinition.REPOSITORY_KEY.equals(activeRule.getRepositoryKey())) {
68+
String repoKey = activeRule.getRepositoryKey();
69+
70+
if (FindbugsRulesDefinition.REPOSITORY_KEY.equals(repoKey) ||
71+
FbContribRulesDefinition.REPOSITORY_KEY.equals(repoKey) ||
72+
FindSecurityBugsRulesDefinition.REPOSITORY_KEY.equals(repoKey) ||
73+
FindSecurityBugsJspRulesDefinition.REPOSITORY_KEY.equals(repoKey)) {
7274
Match child = new Match();
7375
child.setBug(new Bug(activeRule.getConfigKey()));
7476
root.addMatch(child);

src/main/java/org/sonar/plugins/findbugs/FindbugsSensor.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ public class FindbugsSensor implements Sensor {
4949

5050
private static final Logger LOG = LoggerFactory.getLogger(FindbugsSensor.class);
5151

52+
public static final String[] REPOS = {FindbugsRulesDefinition.REPOSITORY_KEY, FbContribRulesDefinition.REPOSITORY_KEY,
53+
FindSecurityBugsRulesDefinition.REPOSITORY_KEY, FindSecurityBugsJspRulesDefinition.REPOSITORY_KEY};
54+
5255
private RulesProfile profile;
5356
private ActiveRules ruleFinder;
5457
private FindbugsExecutor executor;
@@ -95,10 +98,8 @@ public void execute(SensorContext context) {
9598
for (ReportedBug bugInstance : collection) {
9699

97100
try {
98-
String[] repos = {FindbugsRulesDefinition.REPOSITORY_KEY, FbContribRulesDefinition.REPOSITORY_KEY,
99-
FindSecurityBugsRulesDefinition.REPOSITORY_KEY, FindSecurityBugsJspRulesDefinition.REPOSITORY_KEY};
100101
ActiveRule rule = null;
101-
for (String repoKey : repos) {
102+
for (String repoKey : REPOS) {
102103
rule = ruleFinder.findByInternalKey(repoKey, bugInstance.getType());
103104
if (rule != null) {
104105
break;
@@ -111,28 +112,33 @@ public void execute(SensorContext context) {
111112
}
112113

113114
String className = bugInstance.getClassName();
115+
String sourceFile = bugInstance.getSourceFile();
114116
String longMessage = bugInstance.getMessage();
115117
int line = bugInstance.getStartLine();
116118

117119

118120
//Regular Java class mapped to their original .java
119-
InputFile resource = byteCodeResourceLocator.findJavaClassFile(className, this.fs);
121+
InputFile resource = byteCodeResourceLocator.findSourceFile(sourceFile, this.fs);
120122
if (resource != null) {
121123
insertIssue(rule, resource, line, longMessage);
122124
continue;
123125
}
124126

125127
//Locate the original class file
126-
File classFile = findOriginalClassForBug(bugInstance.getClassName());
127-
128-
//If the class was an outer class, the source file will not be analog to the class name.
129-
//The original source file is available in the class file metadata.
130-
resource = byteCodeResourceLocator.findJavaOuterClassFile(className, classFile, this.fs);
131-
if (resource != null) {
132-
insertIssue(rule, resource, line, longMessage);
128+
File classFile = findOriginalClassForBug(bugInstance.getClassFile());
129+
if (classFile == null) {
130+
LOG.warn("Unable to find the class "+bugInstance.getClassName());
133131
continue;
134132
}
135133

134+
// //If the class was an outer class, the source file will not be analog to the class name.
135+
// //The original source file is available in the class file metadata.
136+
// resource = byteCodeResourceLocator.findJavaOuterClassFile(className, classFile, this.fs);
137+
// if (resource != null) {
138+
// insertIssue(rule, resource, line, longMessage);
139+
// continue;
140+
// }
141+
136142
//More advanced mapping if the original source is not Java files
137143
if (classFile != null) {
138144
//Attempt to load SMAP debug metadata
@@ -144,7 +150,7 @@ public void execute(SensorContext context) {
144150
}
145151

146152
//SMAP was found
147-
resource = byteCodeResourceLocator.buildInputFile(location.fileInfo.path, fs);
153+
resource = byteCodeResourceLocator.findSourceFile(location.fileInfo.path, fs);
148154
if (resource != null) {
149155
insertIssue(rule, resource, location.line, longMessage);
150156
continue;

src/main/java/org/sonar/plugins/findbugs/FindbugsXmlReportParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,15 @@ public static class XmlSourceLineAnnotation {
119119

120120
public void parseStart(String attrValue) {
121121
try {
122-
start = Integer.parseInt(attrValue);
122+
start = Integer.valueOf(attrValue);
123123
} catch (NumberFormatException e) {
124124
start = null;
125125
}
126126
}
127127

128128
public void parseEnd(String attrValue) {
129129
try {
130-
end = Integer.parseInt(attrValue);
130+
end = Integer.valueOf(attrValue);
131131
} catch (NumberFormatException e) {
132132
end = null;
133133
}

src/main/java/org/sonar/plugins/findbugs/ReportedBug.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,33 @@
2121

2222
import edu.umd.cs.findbugs.BugInstance;
2323

24+
import java.util.regex.Matcher;
25+
import java.util.regex.Pattern;
26+
2427
public class ReportedBug {
2528

2629
private final String type;
2730
private final String message;
2831
private final String className;
2932
private final int startLine;
33+
private final String sourceFile;
34+
private final String classFile;
35+
36+
private static final Pattern SOURCE_FILE_PATTERN = Pattern.compile("^(.*)\\.java$");
3037

3138
public ReportedBug(BugInstance bugInstance) {
3239
this.type = bugInstance.getType();
3340
this.message = bugInstance.getMessageWithoutPrefix();
3441
this.className = bugInstance.getPrimarySourceLineAnnotation().getClassName();
3542
this.startLine = bugInstance.getPrimarySourceLineAnnotation().getStartLine();
43+
this.sourceFile = bugInstance.getPrimarySourceLineAnnotation().getSourcePath();
44+
Matcher m = SOURCE_FILE_PATTERN.matcher(sourceFile);
45+
if (m.find()) {
46+
this.classFile = m.group(1).replaceAll("/",".");
47+
}
48+
else {
49+
this.classFile = className;
50+
}
3651
}
3752

3853
public String getType() {
@@ -51,4 +66,7 @@ public int getStartLine() {
5166
return startLine;
5267
}
5368

69+
public String getSourceFile() { return sourceFile; }
70+
71+
public String getClassFile() { return classFile; }
5472
}

src/main/java/org/sonar/plugins/findbugs/language/JspSyntaxSensor.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,18 @@
1111
import org.sonar.api.batch.sensor.SensorContext;
1212
import org.sonar.api.batch.sensor.SensorDescriptor;
1313
import org.sonar.api.issue.NoSonarFilter;
14+
import org.sonar.api.measures.CoreMetrics;
15+
import org.sonar.api.measures.FileLinesContext;
1416
import org.sonar.api.measures.FileLinesContextFactory;
17+
import org.sonar.api.measures.Metric;
18+
import org.sonar.plugins.findbugs.language.analyzers.PageCountLines;
1519
import org.sonar.plugins.findbugs.language.lex.PageLexer;
1620
import org.sonar.plugins.findbugs.language.visitor.HtmlAstScanner;
1721
import org.sonar.plugins.findbugs.language.visitor.NoSonarScanner;
1822
import org.sonar.plugins.findbugs.language.visitor.WebSourceCode;
1923

2024
import java.io.FileReader;
25+
import java.util.Map;
2126

2227
public class JspSyntaxSensor implements Sensor {
2328

@@ -59,18 +64,46 @@ public void execute(SensorContext sensorContext) {
5964

6065
try (FileReader reader = new FileReader(inputFile.file())) {
6166
scanner.scan(lexer.parse(reader), sourceCode, fileSystem.encoding());
67+
saveLineLevelMeasures(inputFile, sourceCode);
68+
saveMetrics(sensorContext, sourceCode);
6269

6370
} catch (Exception e) {
6471
LOG.error("Cannot analyze file " + inputFile.file().getAbsolutePath(), e);
6572
}
6673
}
6774
}
6875

76+
private void saveLineLevelMeasures(InputFile inputFile, WebSourceCode webSourceCode) {
77+
FileLinesContext fileLinesContext = fileLinesContextFactory.createFor(inputFile);
78+
79+
for (Integer line : webSourceCode.getDetailedLinesOfCode()) {
80+
fileLinesContext.setIntValue(CoreMetrics.NCLOC_DATA_KEY, line, 1);
81+
}
82+
for (Integer line : webSourceCode.getDetailedLinesOfComments()) {
83+
fileLinesContext.setIntValue(CoreMetrics.COMMENT_LINES_DATA_KEY, line, 1);
84+
}
85+
86+
fileLinesContext.save();
87+
}
88+
89+
private static void saveMetrics(SensorContext context, WebSourceCode sourceCode) {
90+
InputFile inputFile = sourceCode.inputFile();
91+
92+
for (Map.Entry<Metric<Integer>, Integer> entry : sourceCode.getMeasures().entrySet()) {
93+
context.<Integer>newMeasure()
94+
.on(inputFile)
95+
.forMetric(entry.getKey())
96+
.withValue(entry.getValue())
97+
.save();
98+
}
99+
}
100+
69101
/**
70102
* Create PageScanner with Visitors.
71103
*/
72104
private HtmlAstScanner setupScanner(SensorContext context) {
73105
HtmlAstScanner scanner = new HtmlAstScanner(ImmutableList.of(
106+
new PageCountLines(),
74107
new JspTokensVisitor(context),
75108
new NoSonarScanner(noSonarFilter)));
76109

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/*
2+
* SonarSource :: Web :: Sonar Plugin
3+
* Copyright (c) 2010-2017 SonarSource SA and Matthijs Galesloot
4+
* sonarqube@googlegroups.com
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.sonar.plugins.findbugs.language.analyzers;
19+
20+
import com.google.common.collect.Sets;
21+
import org.apache.commons.lang.StringUtils;
22+
import org.slf4j.Logger;
23+
import org.slf4j.LoggerFactory;
24+
import org.sonar.api.measures.CoreMetrics;
25+
import org.sonar.plugins.findbugs.language.node.Node;
26+
import org.sonar.plugins.findbugs.language.node.TextNode;
27+
import org.sonar.plugins.findbugs.language.visitor.DefaultNodeVisitor;
28+
import org.sonar.plugins.findbugs.language.visitor.WebSourceCode;
29+
30+
import javax.annotation.Nullable;
31+
import java.util.List;
32+
import java.util.Set;
33+
34+
/**
35+
* Count lines of code in web files.
36+
*
37+
* @author Matthijs Galesloot
38+
* @since 1.0
39+
*/
40+
public class PageCountLines extends DefaultNodeVisitor {
41+
42+
private static final Logger LOG = LoggerFactory.getLogger(PageCountLines.class);
43+
44+
private int blankLines;
45+
private int commentLines;
46+
private int headerCommentLines;
47+
private int linesOfCode;
48+
private final Set<Integer> detailedLinesOfCode = Sets.newHashSet();
49+
private final Set<Integer> detailedLinesOfComments = Sets.newHashSet();
50+
51+
@Override
52+
public void startDocument(List<Node> nodes) {
53+
linesOfCode = 0;
54+
blankLines = 0;
55+
commentLines = 0;
56+
headerCommentLines = 0;
57+
detailedLinesOfCode.clear();
58+
detailedLinesOfComments.clear();
59+
60+
count(nodes);
61+
}
62+
63+
private void addMeasures() {
64+
WebSourceCode webSourceCode = getWebSourceCode();
65+
66+
webSourceCode.addMeasure(CoreMetrics.NCLOC, linesOfCode);
67+
webSourceCode.addMeasure(CoreMetrics.COMMENT_LINES, commentLines);
68+
69+
webSourceCode.setDetailedLinesOfCode(detailedLinesOfCode);
70+
webSourceCode.setDetailedLinesOfComments(detailedLinesOfComments);
71+
72+
LOG.debug("WebSensor: " + getWebSourceCode().toString() + ":" + linesOfCode + "," + commentLines + "," + headerCommentLines + "," + blankLines);
73+
}
74+
75+
private void count(List<Node> nodeList) {
76+
for (int i = 0; i < nodeList.size(); i++) {
77+
Node node = nodeList.get(i);
78+
Node previousNode = i > 0 ? nodeList.get(i - 1) : null;
79+
Node nextNode = i < nodeList.size() - 1 ? nodeList.get(i) : null;
80+
handleToken(node, previousNode, nextNode);
81+
}
82+
addMeasures();
83+
}
84+
85+
private void handleToken(Node node, @Nullable Node previousNode, @Nullable Node nextNode) {
86+
87+
int linesOfCodeCurrentNode = node.getLinesOfCode();
88+
if (nextNode == null) {
89+
linesOfCodeCurrentNode++;
90+
}
91+
92+
switch (node.getNodeType()) {
93+
case TAG:
94+
case DIRECTIVE:
95+
case EXPRESSION:
96+
linesOfCode += linesOfCodeCurrentNode;
97+
addLineNumbers(node, detailedLinesOfCode);
98+
break;
99+
case COMMENT:
100+
handleTokenComment(node, previousNode, linesOfCodeCurrentNode);
101+
break;
102+
case TEXT:
103+
handleTextToken((TextNode) node, previousNode, linesOfCodeCurrentNode);
104+
break;
105+
default:
106+
break;
107+
}
108+
}
109+
110+
private void handleTokenComment(Node node, @Nullable Node previousNode, int linesOfCodeCurrentNode) {
111+
if (previousNode == null) {
112+
// this is a header comment
113+
headerCommentLines += linesOfCodeCurrentNode;
114+
} else {
115+
commentLines += linesOfCodeCurrentNode;
116+
addLineNumbers(node, detailedLinesOfComments);
117+
}
118+
}
119+
120+
private void handleTextToken(TextNode textNode, @Nullable Node previousNode, int linesOfCodeCurrentNode) {
121+
handleDetailedTextToken(textNode);
122+
if (textNode.isBlank() && linesOfCodeCurrentNode > 0) {
123+
int nonBlankLines = 0;
124+
125+
// add one newline to the previous node
126+
if (previousNode != null) {
127+
switch (previousNode.getNodeType()) {
128+
case COMMENT:
129+
nonBlankLines = handleTextTokenComment(previousNode, nonBlankLines);
130+
break;
131+
case TAG:
132+
case DIRECTIVE:
133+
case EXPRESSION:
134+
linesOfCode++;
135+
nonBlankLines++;
136+
break;
137+
default:
138+
break;
139+
}
140+
}
141+
142+
// remaining newlines are added to blanklines
143+
blankLines += linesOfCodeCurrentNode - nonBlankLines;
144+
} else {
145+
linesOfCode += linesOfCodeCurrentNode;
146+
}
147+
}
148+
149+
private void handleDetailedTextToken(TextNode textNode) {
150+
String[] element = textNode.getCode().split("\n", -1);
151+
int startLine = textNode.getStartLinePosition();
152+
for (int i = 0; i < element.length; i++) {
153+
if (!StringUtils.isBlank(element[i])) {
154+
detailedLinesOfCode.add(startLine + i);
155+
}
156+
}
157+
}
158+
159+
private int handleTextTokenComment(Node previousNode, int nonBlankLines) {
160+
if (previousNode.getStartLinePosition() == 1) {
161+
// this was a header comment
162+
headerCommentLines++;
163+
} else {
164+
commentLines++;
165+
}
166+
return nonBlankLines + 1;
167+
}
168+
169+
private static void addLineNumbers(Node node, Set<Integer> detailedLines) {
170+
for (int i = node.getStartLinePosition(); i <= node.getEndLinePosition(); i++) {
171+
detailedLines.add(i);
172+
}
173+
}
174+
}

0 commit comments

Comments
 (0)