]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2782 Fix detection of false-positive duplication in case of chain of cases
authorEvgeny Mandrikov <mandrikov@gmail.com>
Tue, 27 Sep 2011 07:01:56 +0000 (11:01 +0400)
committerEvgeny Mandrikov <mandrikov@gmail.com>
Tue, 27 Sep 2011 08:59:40 +0000 (12:59 +0400)
sonar-duplications/src/main/java/org/sonar/duplications/java/JavaStatementBuilder.java
sonar-duplications/src/test/java/org/sonar/duplications/java/JavaDuplicationsFunctionalTest.java [new file with mode: 0644]
sonar-duplications/src/test/java/org/sonar/duplications/java/JavaStatementBuilderTest.java

index e783cd3c7582bf66e6f269e610815185440df3c1..66917fa87d16535ec491336190ef9e65b491645b 100644 (file)
@@ -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 (file)
index 0000000..c9a1c1b
--- /dev/null
@@ -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));
+  }
+
+}
index 59aa6ee04e662dd7d277615fb65c5a3c469e3e82..e264233f5bc4e76f3648a5f1d3424c358ea6fdce 100644 (file)
@@ -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