From 828fb94ce229e3f67f9886ac57b505a08af7db0a Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Fri, 19 Apr 2013 11:35:10 +0200 Subject: [PATCH] SONAR-3755 Fix issue in Issues Tracking --- .../plugins/core/issue/IssueTracking.java | 49 ++++++++++++----- .../ViolationTrackingDecorator.java | 46 ++++++++-------- .../plugins/core/issue/IssueTrackingTest.java | 52 +++++++++++++++++++ .../issue/IssueTrackingTest/example3-v1.txt | 16 ++++++ .../issue/IssueTrackingTest/example3-v2.txt | 20 +++++++ 5 files changed, 147 insertions(+), 36 deletions(-) create mode 100644 plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v1.txt create mode 100644 plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v2.txt diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java index da62686b1a6..1f9e4233091 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/issue/IssueTracking.java @@ -23,6 +23,9 @@ package org.sonar.plugins.core.issue; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; import com.google.common.collect.*; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.BatchExtension; import org.sonar.api.batch.SonarIndex; import org.sonar.api.resources.Project; @@ -41,9 +44,15 @@ import java.util.*; public class IssueTracking implements BatchExtension { + private static final Logger LOG = LoggerFactory.getLogger(IssueTracking.class); + private static final Comparator LINE_PAIR_COMPARATOR = new Comparator() { public int compare(LinePair o1, LinePair o2) { - return o2.weight - o1.weight; + if (o2.weight - o1.weight != 0) { + return o2.weight - o1.weight; + } else { + return Math.abs(o1.lineA -o1.lineB) - Math.abs(o2.lineA - o2.lineB); + } } }; private final Project project; @@ -67,6 +76,8 @@ public class IssueTracking implements BatchExtension { } public void track(Resource resource, Collection referenceIssues, Collection newIssues) { + LOG.debug("Tracking : " + resource); + referenceIssuesMap.clear(); String source = index.getSource(resource); @@ -117,13 +128,13 @@ public class IssueTracking implements BatchExtension { unmappedLastIssues.addAll(lastIssues); for (IssueDto lastIssue : lastIssues) { - lastIssuesByRule.put(getRule(lastIssue), lastIssue); + lastIssuesByRule.put(getRuleId(lastIssue), lastIssue); } // Match the key of the issue. (For manual issues) for (DefaultIssue newIssue : newIssues) { mapIssue(newIssue, - findLastIssueWithSameKey(newIssue, lastIssuesByRule.get(getRule(newIssue))), + findLastIssueWithSameKey(newIssue, lastIssuesByRule.get(getRuleId(newIssue))), lastIssuesByRule, referenceIssuesMap); } @@ -131,7 +142,7 @@ public class IssueTracking implements BatchExtension { for (DefaultIssue newIssue : newIssues) { if (isNotAlreadyMapped(newIssue)) { mapIssue(newIssue, - findLastIssueWithSameLineAndChecksum(newIssue, lastIssuesByRule.get(getRule(newIssue))), + findLastIssueWithSameLineAndChecksum(newIssue, lastIssuesByRule.get(getRuleId(newIssue))), lastIssuesByRule, referenceIssuesMap); } } @@ -179,6 +190,7 @@ public class IssueTracking implements BatchExtension { for (HashOccurrence hashOccurrence : map.values()) { if (hashOccurrence.countA == 1 && hashOccurrence.countB == 1) { // Guaranteed that lineA has been moved to lineB, so we can map all issues on lineA to all issues on lineB + LOG.debug("*** Guaranteed that lineA has been moved to lineB, so we can map all issues on lineA to all issues on lineB"); map(newIssuesByLines.get(hashOccurrence.lineB), lastIssuesByLines.get(hashOccurrence.lineA), lastIssuesByRule); lastIssuesByLines.removeAll(hashOccurrence.lineA); newIssuesByLines.removeAll(hashOccurrence.lineB); @@ -197,6 +209,7 @@ public class IssueTracking implements BatchExtension { Collections.sort(possibleLinePairs, LINE_PAIR_COMPARATOR); for (LinePair linePair : possibleLinePairs) { // High probability that lineA has been moved to lineB, so we can map all Issues on lineA to all Issues on lineB + LOG.debug("*** High probability that lineA has been moved to lineB, so we can map all Issues on lineA to all Issues on lineB"); map(newIssuesByLines.get(linePair.lineB), lastIssuesByLines.get(linePair.lineA), lastIssuesByRule); } } @@ -206,8 +219,9 @@ public class IssueTracking implements BatchExtension { // Try then to match issues on same rule with same message and with same checksum for (DefaultIssue newIssue : newIssues) { if (isNotAlreadyMapped(newIssue)) { + LOG.debug("*** Try then to match issues on same rule with same message and with same checksum"); mapIssue(newIssue, - findLastIssueWithSameChecksumAndMessage(newIssue, lastIssuesByRule.get(getRule(newIssue))), + findLastIssueWithSameChecksumAndMessage(newIssue, lastIssuesByRule.get(getRuleId(newIssue))), lastIssuesByRule, referenceIssuesMap); } } @@ -215,8 +229,9 @@ public class IssueTracking implements BatchExtension { // Try then to match issues on same rule with same line and with same message for (DefaultIssue newIssue : newIssues) { if (isNotAlreadyMapped(newIssue)) { + LOG.debug("*** Try then to match issues on same rule with same line and with same message"); mapIssue(newIssue, - findLastIssueWithSameLineAndMessage(newIssue, lastIssuesByRule.get(getRule(newIssue))), + findLastIssueWithSameLineAndMessage(newIssue, lastIssuesByRule.get(getRuleId(newIssue))), lastIssuesByRule, referenceIssuesMap); } } @@ -225,8 +240,9 @@ public class IssueTracking implements BatchExtension { // See SONAR-2812 for (DefaultIssue newIssue : newIssues) { if (isNotAlreadyMapped(newIssue)) { + LOG.debug("*** Last check: match issue if same rule and same checksum but different line and different message"); mapIssue(newIssue, - findLastIssueWithSameChecksum(newIssue, lastIssuesByRule.get(getRule(newIssue))), + findLastIssueWithSameChecksum(newIssue, lastIssuesByRule.get(getRuleId(newIssue))), lastIssuesByRule, referenceIssuesMap); } } @@ -236,9 +252,12 @@ public class IssueTracking implements BatchExtension { for (DefaultIssue newIssue : newIssues) { if (isNotAlreadyMapped(newIssue)) { for (IssueDto pastIssue : lastIssues) { - if (isNotAlreadyMapped(pastIssue) && Objects.equal(getRule(newIssue), getRule(pastIssue))) { + if (isNotAlreadyMapped(pastIssue) && Objects.equal(getRuleId(newIssue), getRuleId(pastIssue))) { + LOG.debug("mapIssue newIssue : "+ newIssue + " with : "+ pastIssue); mapIssue(newIssue, pastIssue, lastIssuesByRule, referenceIssuesMap); break; + } else { + LOG.debug("Not mapIssue newIssue : "+ newIssue + " with : "+ pastIssue); } } } @@ -319,7 +338,7 @@ public class IssueTracking implements BatchExtension { } private boolean isSameChecksum(DefaultIssue newIssue, IssueDto pastIssue) { - return Objects.equal(pastIssue.getChecksum(), newIssue.getChecksum()); + return StringUtils.equals(pastIssue.getChecksum(), newIssue.getChecksum()); } private boolean isSameLine(DefaultIssue newIssue, IssueDto pastIssue) { @@ -327,7 +346,7 @@ public class IssueTracking implements BatchExtension { } private boolean isSameMessage(DefaultIssue newIssue, IssueDto pastIssue) { - return Objects.equal(IssueDto.abbreviateMessage(newIssue.message()), pastIssue.getMessage()); + return StringUtils.equals(IssueDto.abbreviateMessage(newIssue.message()), pastIssue.getMessage()); } private boolean isSameKey(DefaultIssue newIssue, IssueDto pastIssue) { @@ -336,6 +355,8 @@ public class IssueTracking implements BatchExtension { private void mapIssue(DefaultIssue newIssue, IssueDto pastIssue, Multimap lastIssuesByRule, Map issueMap) { if (pastIssue != null) { + LOG.debug("Mapping with old issue from newIssue : "+ newIssue + " and pastIssue : "+ pastIssue); + newIssue.setKey(pastIssue.getUuid()); if (pastIssue.isManualSeverity()) { newIssue.setSeverity(pastIssue.getSeverity()); @@ -348,10 +369,12 @@ public class IssueTracking implements BatchExtension { // TODO // newIssue.setPersonId(pastIssue.getPersonId()); - lastIssuesByRule.remove(getRule(newIssue), pastIssue); + lastIssuesByRule.remove(getRuleId(newIssue), pastIssue); issueMap.put(newIssue, pastIssue); unmappedLastIssues.remove(pastIssue); } else { + LOG.debug("No old issue, creating new one with newIssue : "+ newIssue + " and pastIssue : "+ pastIssue); + newIssue.setNew(true); newIssue.setCreatedAt(project.getAnalysisDate()); } @@ -362,11 +385,11 @@ public class IssueTracking implements BatchExtension { return referenceIssuesMap.get(issue); } - private Integer getRule(DefaultIssue issue) { + private Integer getRuleId(DefaultIssue issue) { return ruleFinder.findByKey(issue.ruleKey()).getId(); } - private Integer getRule(IssueDto issue) { + private Integer getRuleId(IssueDto issue) { return issue.getRuleId(); } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java index 430e707e803..7971be2434e 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/ViolationTrackingDecorator.java @@ -21,44 +21,30 @@ package org.sonar.plugins.core.timemachine; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; +import com.google.common.collect.*; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.Decorator; -import org.sonar.api.batch.DecoratorBarriers; -import org.sonar.api.batch.DecoratorContext; -import org.sonar.api.batch.DependedUpon; -import org.sonar.api.batch.DependsUpon; -import org.sonar.api.batch.SonarIndex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.*; import org.sonar.api.database.model.RuleFailureModel; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.rules.Violation; import org.sonar.api.violations.ViolationQuery; import org.sonar.batch.scan.LastSnapshots; -import org.sonar.plugins.core.timemachine.tracking.HashedSequence; -import org.sonar.plugins.core.timemachine.tracking.HashedSequenceComparator; -import org.sonar.plugins.core.timemachine.tracking.RollingHashSequence; -import org.sonar.plugins.core.timemachine.tracking.RollingHashSequenceComparator; -import org.sonar.plugins.core.timemachine.tracking.StringText; -import org.sonar.plugins.core.timemachine.tracking.StringTextComparator; +import org.sonar.plugins.core.timemachine.tracking.*; import javax.annotation.Nullable; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; @DependsUpon({DecoratorBarriers.END_OF_VIOLATIONS_GENERATION, DecoratorBarriers.START_VIOLATION_TRACKING}) @DependedUpon(DecoratorBarriers.END_OF_VIOLATION_TRACKING) public class ViolationTrackingDecorator implements Decorator { + + private static final Logger LOG = LoggerFactory.getLogger(ViolationTrackingDecorator.class); + private LastSnapshots lastSnapshots; private Map referenceViolationsMap = Maps.newIdentityHashMap(); private SonarIndex index; @@ -80,6 +66,8 @@ public class ViolationTrackingDecorator implements Decorator { } public void decorate(Resource resource, DecoratorContext context) { + LOG.debug("ViolationTracking : " + resource); + referenceViolationsMap.clear(); ViolationQuery violationQuery = ViolationQuery.create().forResource(resource).setSwitchMode(ViolationQuery.SwitchMode.BOTH); @@ -195,6 +183,7 @@ public class ViolationTrackingDecorator implements Decorator { for (HashOccurrence hashOccurrence : map.values()) { if (hashOccurrence.countA == 1 && hashOccurrence.countB == 1) { // Guaranteed that lineA has been moved to lineB, so we can map all violations on lineA to all violations on lineB + LOG.debug("*** Guaranteed that lineA has been moved to lineB, so we can map all issues on lineA to all issues on lineB"); map(newViolationsByLines.get(hashOccurrence.lineB), lastViolationsByLines.get(hashOccurrence.lineA), lastViolationsByRule); lastViolationsByLines.removeAll(hashOccurrence.lineA); newViolationsByLines.removeAll(hashOccurrence.lineB); @@ -213,6 +202,7 @@ public class ViolationTrackingDecorator implements Decorator { Collections.sort(possibleLinePairs, LINE_PAIR_COMPARATOR); for (LinePair linePair : possibleLinePairs) { // High probability that lineA has been moved to lineB, so we can map all violations on lineA to all violations on lineB + LOG.debug("*** High probability that lineA has been moved to lineB, so we can map all Issues on lineA to all Issues on lineB"); map(newViolationsByLines.get(linePair.lineB), lastViolationsByLines.get(linePair.lineA), lastViolationsByRule); } } @@ -222,6 +212,7 @@ public class ViolationTrackingDecorator implements Decorator { // Try then to match violations on same rule with same message and with same checksum for (Violation newViolation : newViolations) { if (isNotAlreadyMapped(newViolation)) { + LOG.debug("*** Try then to match issues on same rule with same message and with same checksum"); mapViolation(newViolation, findLastViolationWithSameChecksumAndMessage(newViolation, lastViolationsByRule.get(newViolation.getRule().getId())), lastViolationsByRule, referenceViolationsMap); @@ -231,6 +222,7 @@ public class ViolationTrackingDecorator implements Decorator { // Try then to match violations on same rule with same line and with same message for (Violation newViolation : newViolations) { if (isNotAlreadyMapped(newViolation)) { + LOG.debug("*** Try then to match issues on same rule with same line and with same message"); mapViolation(newViolation, findLastViolationWithSameLineAndMessage(newViolation, lastViolationsByRule.get(newViolation.getRule().getId())), lastViolationsByRule, referenceViolationsMap); @@ -241,6 +233,7 @@ public class ViolationTrackingDecorator implements Decorator { // See SONAR-2812 for (Violation newViolation : newViolations) { if (isNotAlreadyMapped(newViolation)) { + LOG.debug("*** Last check: match issue if same rule and same checksum but different line and different message"); mapViolation(newViolation, findLastViolationWithSameChecksum(newViolation, lastViolationsByRule.get(newViolation.getRule().getId())), lastViolationsByRule, referenceViolationsMap); @@ -257,8 +250,11 @@ public class ViolationTrackingDecorator implements Decorator { if (isNotAlreadyMapped(newViolation)) { for (RuleFailureModel pastViolation : lastViolations) { if (isNotAlreadyMapped(pastViolation) && Objects.equal(newViolation.getRule().getId(), pastViolation.getRuleId())) { + LOG.debug("mapIssue newViolation : " + newViolation + " with pastViolation : " + pastViolation); mapViolation(newViolation, pastViolation, lastViolationsByRule, referenceViolationsMap); break; + } else { + LOG.debug("Not mapIssue newViolation : " + newViolation + " with pastViolation : " + pastViolation); } } } @@ -384,6 +380,8 @@ public class ViolationTrackingDecorator implements Decorator { private void mapViolation(Violation newViolation, RuleFailureModel pastViolation, Multimap lastViolationsByRule, Map violationMap) { if (pastViolation != null) { + LOG.debug("Mapping with old violation from newViolation : " + newViolation + " and pastViolation : " + pastViolation); + newViolation.setCreatedAt(pastViolation.getCreatedAt()); newViolation.setPermanentId(pastViolation.getPermanentId()); newViolation.setSwitchedOff(pastViolation.isSwitchedOff()); @@ -393,6 +391,8 @@ public class ViolationTrackingDecorator implements Decorator { violationMap.put(newViolation, pastViolation); unmappedLastViolations.remove(pastViolation); } else { + LOG.debug("No old violation, creating new one with newViolation : " + newViolation + " and pastViolation : " + pastViolation); + newViolation.setNew(true); newViolation.setCreatedAt(project.getAnalysisDate()); } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingTest.java index eab2ff4a71c..550fbb95d60 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/issue/IssueTrackingTest.java @@ -62,12 +62,16 @@ public class IssueTrackingTest { rule1.setId(1); Rule rule2 = Rule.create("squid", "NullDeref"); rule2.setId(2); + Rule rule3 = Rule.create("pmd", "UnusedLocalVariable"); + rule3.setId(3); ruleFinder = mock(RuleFinder.class); when(ruleFinder.findById(1)).thenReturn(rule1); when(ruleFinder.findById(2)).thenReturn(rule2); + when(ruleFinder.findById(3)).thenReturn(rule3); when(ruleFinder.findByKey(RuleKey.of("squid", "AvoidCycle"))).thenReturn(rule1); when(ruleFinder.findByKey(RuleKey.of("squid", "NullDeref"))).thenReturn(rule2); + when(ruleFinder.findByKey(RuleKey.of("pmd", "UnusedLocalVariable"))).thenReturn(rule3); lastSnapshots = mock(LastSnapshots.class); @@ -346,6 +350,41 @@ public class IssueTrackingTest { assertThat(newIssue3.isNew()).isTrue(); } + @Test + public void should_track_issues_based_on_blocks_recognition_on_example3() throws Exception { + when(lastSnapshots.getSource(project)).thenReturn(load("example3-v1")); + String source = load("example3-v2"); + + IssueDto referenceIssue1 = newReferenceIssue("Avoid unused local variables such as 'j'.", 6, 1, "63c11570fc0a76434156be5f8138fa03"); + IssueDto referenceIssue2 = newReferenceIssue("Avoid unused private methods such as 'myMethod()'.", 13, 2, "ef23288705d1ef1e512448ace287586e"); + IssueDto referenceIssue3 = newReferenceIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9, 3, "ed5cdd046fda82727d6fedd1d8e3a310"); + + // New issue + DefaultIssue newIssue1 = newDefaultIssue("Avoid unused local variables such as 'msg'.", 18, RuleKey.of("squid", "AvoidCycle"), "a24254126be2bf1a9b9a8db43f633733"); + // Same as referenceIssue2 + DefaultIssue newIssue2 = newDefaultIssue("Avoid unused private methods such as 'myMethod()'.", 13, RuleKey.of("squid", "NullDeref"), "ef23288705d1ef1e512448ace287586e"); + // Same as referenceIssue3 + DefaultIssue newIssue3 = newDefaultIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9, RuleKey.of("pmd", "UnusedLocalVariable"), "ed5cdd046fda82727d6fedd1d8e3a310"); + // New issue + DefaultIssue newIssue4 = newDefaultIssue("Method 'newViolation' is not designed for extension - needs to be abstract, final or empty.", 17, RuleKey.of("pmd", "UnusedLocalVariable"), "7d58ac9040c27e4ca2f11a0269e251e2"); + // Same as referenceIssue1 + DefaultIssue newIssue5 = newDefaultIssue("Avoid unused local variables such as 'j'.", 6, RuleKey.of("squid", "AvoidCycle"), "4432a2675ec3e1620daefe38386b51ef"); + + Map mapping = decorator.mapIssues( + Arrays.asList(newIssue1, newIssue2, newIssue3, newIssue4, newIssue5), + Arrays.asList(referenceIssue1, referenceIssue2, referenceIssue3), + source, project); + + assertThat(newIssue1.isNew()).isTrue(); + assertThat(newIssue2.isNew()).isFalse(); + assertThat(newIssue3.isNew()).isFalse(); + assertThat(newIssue4.isNew()).isTrue(); + assertThat(newIssue5.isNew()).isFalse(); + assertThat(mapping.get(newIssue2)).isEqualTo(referenceIssue2); + assertThat(mapping.get(newIssue3)).isEqualTo(referenceIssue3); + assertThat(mapping.get(newIssue5)).isEqualTo(referenceIssue1); + } + private static String load(String name) throws IOException { return Resources.toString(IssueTrackingTest.class.getResource("IssueTrackingTest/" + name + ".txt"), Charsets.UTF_8); } @@ -366,4 +405,17 @@ public class IssueTrackingTest { return referenceIssue; } + public void test(){ + IssueDto referenceIssue1 = newReferenceIssue("Avoid unused local variables such as 'j'.", 6, 1, "63c11570fc0a76434156be5f8138fa03"); + IssueDto referenceIssue2 = newReferenceIssue("Avoid unused private methods such as 'myMethod()'.", 13, 2, "ef23288705d1ef1e512448ace287586e"); + IssueDto referenceIssue3 = newReferenceIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9, 3, "ed5cdd046fda82727d6fedd1d8e3a310"); + + DefaultIssue newIssue1 = newDefaultIssue("Avoid unused local variables such as 'msg'.", 18, RuleKey.of("squid", "AvoidCycle"), "a24254126be2bf1a9b9a8db43f633733"); + DefaultIssue newIssue2 = newDefaultIssue("Avoid unused private methods such as 'myMethod()'.", 13, RuleKey.of("squid", "NullDeref"), "ef23288705d1ef1e512448ace287586e"); + DefaultIssue newIssue3 = newDefaultIssue("Method 'avoidUtilityClass' is not designed for extension - needs to be abstract, final or empty.", 9, RuleKey.of("pmd", "UnusedLocalVariable"), "ed5cdd046fda82727d6fedd1d8e3a310"); + DefaultIssue newIssue4 = newDefaultIssue("Method 'newViolation' is not designed for extension - needs to be abstract, final or empty.", 17, RuleKey.of("pmd", "UnusedLocalVariable"), "7d58ac9040c27e4ca2f11a0269e251e2"); + DefaultIssue newIssue5 = newDefaultIssue("Avoid unused local variables such as 'j'.", 6, RuleKey.of("squid", "AvoidCycle"), "4432a2675ec3e1620daefe38386b51ef"); + + } + } diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v1.txt b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v1.txt new file mode 100644 index 00000000000..facdcbc008c --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v1.txt @@ -0,0 +1,16 @@ +package sample; + +public class Sample { + + public Sample(int i) { + int j = i+1; // violation: unused local variable + } + + public boolean avoidUtilityClass() { + return true; + } + + private String myMethod() { // violation : unused private method + return "hello"; + } +} diff --git a/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v2.txt b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v2.txt new file mode 100644 index 00000000000..91db843fc4d --- /dev/null +++ b/plugins/sonar-core-plugin/src/test/resources/org/sonar/plugins/core/issue/IssueTrackingTest/example3-v2.txt @@ -0,0 +1,20 @@ +package sample; + +public class Sample { + + public Sample(int i) { + int j = i+1; // still the same violation: unused local variable + } + + public boolean avoidUtilityClass() { + return true; + } + + private String myMethod() { // violation "unused private method" is fixed because it's called in newViolation + return "hello"; + } + + public void newViolation() { + String msg = myMethod(); // new violation : msg is an unused variable + } +} -- 2.39.5