aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Mandrikov <mandrikov@gmail.com>2011-09-27 11:01:56 +0400
committerEvgeny Mandrikov <mandrikov@gmail.com>2011-09-27 12:59:40 +0400
commit591faa52ca6342ce9efef999d726bbfcac13462b (patch)
treeacfad8ea9d231ce9a3b5552cd20781afe0746145
parent75fc94e0b6f64c29f2c08d999715966319eee311 (diff)
downloadsonarqube-591faa52ca6342ce9efef999d726bbfcac13462b.tar.gz
sonarqube-591faa52ca6342ce9efef999d726bbfcac13462b.zip
SONAR-2782 Fix detection of false-positive duplication in case of chain of cases
-rw-r--r--sonar-duplications/src/main/java/org/sonar/duplications/java/JavaStatementBuilder.java4
-rw-r--r--sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java95
-rw-r--r--sonar-duplications/src/test/java/org/sonar/duplications/java/JavaStatementBuilderTest.java36
3 files changed, 123 insertions, 12 deletions
diff --git a/sonar-duplications/src/main/java/org/sonar/duplications/java/JavaStatementBuilder.java b/sonar-duplications/src/main/java/org/sonar/duplications/java/JavaStatementBuilder.java
index e783cd3c758..66917fa87d1 100644
--- a/sonar-duplications/src/main/java/org/sonar/duplications/java/JavaStatementBuilder.java
+++ b/sonar-duplications/src/main/java/org/sonar/duplications/java/JavaStatementBuilder.java
@@ -43,8 +43,8 @@ public final class JavaStatementBuilder {
.statement(from("else"))
.statement(from("for"), bridge("(", ")"))
.statement(from("while"), bridge("(", ")"))
- .statement(from("case"), to(":"))
- .statement(from("default"), to(":"))
+ .statement(from("case"), to(";", "{", "}"), forgetLastToken())
+ .statement(from("default"), to(";", "{", "}"), forgetLastToken())
.statement(to(";", "{", "}"), forgetLastToken())
.build();
}
diff --git a/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java b/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java
new file mode 100644
index 00000000000..c9a1c1b90c7
--- /dev/null
+++ b/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java
@@ -0,0 +1,95 @@
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * Sonar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.duplications.java;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.sonar.duplications.block.Block;
+import org.sonar.duplications.block.BlockChunker;
+import org.sonar.duplications.detector.original.OriginalCloneDetectionAlgorithm;
+import org.sonar.duplications.index.CloneGroup;
+import org.sonar.duplications.index.MemoryCloneIndex;
+import org.sonar.duplications.statement.Statement;
+import org.sonar.duplications.statement.StatementChunker;
+import org.sonar.duplications.token.TokenChunker;
+
+import com.google.common.base.Joiner;
+
+public class JavaDuplicationsFunctionalTest {
+
+ private static final int BLOCK_SIZE = 1;
+
+ private TokenChunker tokenChunker = JavaTokenProducer.build();
+ private StatementChunker statementChunker = JavaStatementBuilder.build();
+ private BlockChunker blockChunker = new BlockChunker(BLOCK_SIZE);
+
+ private List<CloneGroup> detect(String... lines) {
+ String sourceCode = Joiner.on('\n').join(lines);
+ MemoryCloneIndex index = new MemoryCloneIndex();
+ List<Statement> statements = statementChunker.chunk(tokenChunker.chunk(sourceCode));
+ List<Block> blocks = blockChunker.chunk("resourceId", statements);
+ for (Block block : blocks) {
+ index.insert(block);
+ }
+ return OriginalCloneDetectionAlgorithm.detect(index, blocks);
+ }
+
+ /**
+ * See SONAR-2837
+ */
+ @Test
+ public void initializationOfMultidimensionalArray() {
+ List<CloneGroup> duplications = detect("int[][] idx = new int[][] { { 1, 2 }, { 3, 4 } };");
+ assertThat(duplications.size(), is(0));
+ }
+
+ /**
+ * See SONAR-2782
+ */
+ @Test
+ public void chainOfCases() {
+ List<CloneGroup> duplications = detect(
+ "switch (a) {",
+ " case 'a': case 'b': case 'c':",
+ " doSomething();",
+ " case 'd': case 'e': case 'f':",
+ " doSomethingElse();",
+ "}");
+ assertThat(duplications.size(), is(0));
+ }
+
+ @Test
+ public void literalsNormalization() {
+ List<CloneGroup> duplications = detect(
+ "String s = \"abc\";",
+ "String s = \"def\";");
+ assertThat(duplications.size(), is(1));
+
+ duplications = detect(
+ "int i = 1;",
+ "int i = 2;");
+ assertThat(duplications.size(), is(1));
+ }
+
+}
diff --git a/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaStatementBuilderTest.java b/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaStatementBuilderTest.java
index 59aa6ee04e6..e264233f5bc 100644
--- a/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaStatementBuilderTest.java
+++ b/sonar-duplications/src/test/java/org/sonar/duplications/java/JavaStatementBuilderTest.java
@@ -127,17 +127,33 @@ public class JavaStatementBuilderTest {
"switch (month) {" +
" case 1 : monthString=\"January\"; break;" +
" case 2 : monthString=\"February\"; break;" +
- " default: monthString=\"Invalid\";");
- assertThat(statements.size(), is(9));
+ " default: monthString=\"Invalid\";" +
+ "}");
+ assertThat(statements.size(), is(6));
assertThat(statements.get(0).getValue(), is("switch(month)"));
- assertThat(statements.get(1).getValue(), is("case$NUMBER:"));
- assertThat(statements.get(2).getValue(), is("monthString=$CHARS"));
- assertThat(statements.get(3).getValue(), is("break"));
- assertThat(statements.get(4).getValue(), is("case$NUMBER:"));
- assertThat(statements.get(5).getValue(), is("monthString=$CHARS"));
- assertThat(statements.get(6).getValue(), is("break"));
- assertThat(statements.get(7).getValue(), is("default:"));
- assertThat(statements.get(8).getValue(), is("monthString=$CHARS"));
+ assertThat(statements.get(1).getValue(), is("case$NUMBER:monthString=$CHARS"));
+ assertThat(statements.get(2).getValue(), is("break"));
+ assertThat(statements.get(3).getValue(), is("case$NUMBER:monthString=$CHARS"));
+ assertThat(statements.get(4).getValue(), is("break"));
+ assertThat(statements.get(5).getValue(), is("default:monthString=$CHARS"));
+ }
+
+ /**
+ * See SONAR-2782
+ */
+ @Test
+ public void shouldHandleNestedSwitch() {
+ List<Statement> statements = chunk("" +
+ "switch (a) {" +
+ " case 'a': case 'b': case 'c': something(); break;" +
+ " case 'd': case 'e': case 'f': somethingOther(); break;" +
+ "}");
+ assertThat(statements.size(), is(5));
+ assertThat(statements.get(0).getValue(), is("switch(a)"));
+ assertThat(statements.get(1).getValue(), is("case$CHARS:case$CHARS:case$CHARS:something()"));
+ assertThat(statements.get(2).getValue(), is("break"));
+ assertThat(statements.get(3).getValue(), is("case$CHARS:case$CHARS:case$CHARS:somethingOther()"));
+ assertThat(statements.get(4).getValue(), is("break"));
}
@Test