diff --git a/integration-tests/features/multimodule_analysis.feature b/integration-tests/features/multimodule_analysis.feature index 9606a46670..ca7878d739 100644 --- a/integration-tests/features/multimodule_analysis.feature +++ b/integration-tests/features/multimodule_analysis.feature @@ -36,8 +36,8 @@ Feature: cpp-multimodule-project | comment_lines_density | 30 | | comment_lines | 24 | # duplications - | duplicated_lines_density | 57.3 | - | duplicated_lines | 86 | + | duplicated_lines_density | 56.0 | + | duplicated_lines | 84 | | duplicated_blocks | 2 | | duplicated_files | 2 | # complexity diff --git a/integration-tests/features/smoketest.feature b/integration-tests/features/smoketest.feature index d30f169227..def875b284 100644 --- a/integration-tests/features/smoketest.feature +++ b/integration-tests/features/smoketest.feature @@ -31,8 +31,8 @@ Feature: Smoketest | comment_lines_density | 30 | | comment_lines | 24 | # duplications - | duplicated_lines_density | 57.0 | - | duplicated_lines | 86 | + | duplicated_lines_density | 55.6 | + | duplicated_lines | 84 | | duplicated_blocks | 2 | | duplicated_files | 2 | # complexity diff --git a/pom.xml b/pom.xml index 86626d6923..4a5718accf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,12 @@ org.sonarsource.parent parent - 32 + + 36 org.sonarsource.sonarqube-plugins.cxx @@ -165,7 +170,10 @@ http://github.com/SonarOpenCommunity/sonar-cxx true 5.6 + + 1.17 1.21 + 2.6.1 org.sonar.plugins.cxx.CxxPlugin target/${project.artifactId}-${project.version}.jar C++ (Community) @@ -213,19 +221,27 @@ org.sonarsource.sslr-squid-bridge sslr-squid-bridge - 2.6.1 + ${sslr-squid-bridge.version} org.codehaus.sonar.sslr sslr-core + + org.codehaus.sonar.sslr + sslr-xpath + org.codehaus.sonar sonar-plugin-api - org.codehaus.sonar.sslr - sslr-xpath + org.picocontainer + picocontainer + + + org.slf4j + slf4j-api org.slf4j @@ -257,7 +273,7 @@ org.slf4j slf4j-api - 1.6.2 + 1.7.21 test diff --git a/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxCpdMapping.java b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxCpdMapping.java deleted file mode 100644 index 270a8ebc61..0000000000 --- a/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxCpdMapping.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Sonar C++ Plugin (Community) - * Copyright (C) 2010-2016 SonarOpenCommunity - * http://github.com/SonarOpenCommunity/sonar-cxx - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.cxx; - -import java.nio.charset.Charset; - -import net.sourceforge.pmd.cpd.Tokenizer; //@todo deprecated - -import org.sonar.api.batch.AbstractCpdMapping; //@todo deprecated -import org.sonar.api.resources.Language; -import org.sonar.api.batch.fs.FileSystem; - -public class CxxCpdMapping extends AbstractCpdMapping { - - private final CxxLanguage language; - private final Charset charset; - - public CxxCpdMapping(CxxLanguage language, FileSystem fs) { - this.language = language; - this.charset = fs.encoding(); - } - - @Override - public Tokenizer getTokenizer() { //@todo deprecated Tokenizer - return new CxxTokenizer(charset); - } - - @Override - public Language getLanguage() { - return language; - } - -} diff --git a/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxPlugin.java b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxPlugin.java index 01f6ecb7dc..8086392a15 100644 --- a/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxPlugin.java +++ b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxPlugin.java @@ -385,7 +385,6 @@ public void define(Context context) { l.add(CxxLanguage.class); l.add(CxxMetrics.class); l.add(CxxSquidSensor.class); - l.add(CxxCpdMapping.class); l.add(CxxRatsRuleRepository.class); l.add(CxxRatsSensor.class); l.add(CxxXunitSensor.class); diff --git a/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxTokenizer.java b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxTokenizer.java deleted file mode 100644 index 22eccda585..0000000000 --- a/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/CxxTokenizer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Sonar C++ Plugin (Community) - * Copyright (C) 2010-2016 SonarOpenCommunity - * http://github.com/SonarOpenCommunity/sonar-cxx - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.cxx; - -import java.io.File; -import java.nio.charset.Charset; -import java.util.List; - -import net.sourceforge.pmd.cpd.SourceCode; //@todo deprecated -import net.sourceforge.pmd.cpd.TokenEntry; //@todo deprecated -import net.sourceforge.pmd.cpd.Tokenizer; //@todo deprecated -import net.sourceforge.pmd.cpd.Tokens; //@todo deprecated - -import org.sonar.cxx.CxxConfiguration; -import org.sonar.cxx.lexer.CxxLexer; - -import com.sonar.sslr.api.Token; -import com.sonar.sslr.impl.Lexer; - -public class CxxTokenizer implements Tokenizer { - - private final Charset charset; - - public CxxTokenizer(Charset charset) { - this.charset = charset; - } - - @Override - public final void tokenize(SourceCode source, Tokens cpdTokens) { //@todo deprecated SourceCode - Lexer lexer = CxxLexer.create(new CxxConfiguration(charset)); - String fileName = source.getFileName(); - List tokens = lexer.lex(new File(fileName)); - for (Token token : tokens) { - TokenEntry cpdToken = new TokenEntry(getTokenImage(token), fileName, token.getLine()); - cpdTokens.add(cpdToken); - } - cpdTokens.add(TokenEntry.getEOF()); - } - - private String getTokenImage(Token token) { - return token.getValue(); - } - -} diff --git a/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/cpd/CxxCpdVisitor.java b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/cpd/CxxCpdVisitor.java new file mode 100644 index 0000000000..65407c44dd --- /dev/null +++ b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/cpd/CxxCpdVisitor.java @@ -0,0 +1,83 @@ +/* + * Sonar C++ Plugin (Community) + * Copyright (C) 2010-2016 SonarOpenCommunity + * http://github.com/SonarOpenCommunity/sonar-cxx + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.cxx.cpd; + +import java.io.File; +import javax.annotation.Nullable; + +import com.sonar.sslr.api.AstAndTokenVisitor; +import com.sonar.sslr.api.AstNode; +import com.sonar.sslr.api.GenericTokenType; +import com.sonar.sslr.api.Grammar; +import com.sonar.sslr.api.Token; +import org.sonar.squidbridge.SquidAstVisitor; + +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.TextRange; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.cpd.NewCpdTokens; +import org.sonar.cxx.api.CxxTokenType; + +public class CxxCpdVisitor extends SquidAstVisitor implements AstAndTokenVisitor { + + private final SensorContext sensorContext; + private InputFile inputFile; + private NewCpdTokens cpdTokens; + + public CxxCpdVisitor(SensorContext sensorContext) { + this.sensorContext = sensorContext; + } + + @Override + public void visitFile(@Nullable AstNode astNode) { + File file = getContext().getFile(); + inputFile = sensorContext.fileSystem().inputFile(sensorContext.fileSystem().predicates().is(file)); + cpdTokens = sensorContext.newCpdTokens().onFile(inputFile); + } + + @Override + public void leaveFile(@Nullable AstNode astNode) { + cpdTokens.save(); + } + + @Override + public void visitToken(Token token) { + if (!token.isGeneratedCode()) { + String text; + if (token.getType().equals(CxxTokenType.NUMBER)) { + text = "_N"; + } else if (token.getType().equals(CxxTokenType.STRING)) { + text = "_S"; + } else if (token.getType().equals(CxxTokenType.CHARACTER)) { + text = "_C"; + } else if (token.getType().equals(GenericTokenType.IDENTIFIER)) { + text = "_I"; + } else if (token.getType().equals(GenericTokenType.EOF)) { + return; + } else { + text = token.getValue(); + } + + TextRange range = inputFile.newRange(token.getLine(), token.getColumn(), token.getLine(), token.getColumn() + token.getValue().length()); + cpdTokens.addToken(range, text); + } + } + +} diff --git a/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxCpdMappingTest.java b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/cpd/package-info.java similarity index 60% rename from sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxCpdMappingTest.java rename to sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/cpd/package-info.java index 3c105f8b9e..8a4d46bc6d 100644 --- a/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxCpdMappingTest.java +++ b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/cpd/package-info.java @@ -17,22 +17,11 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.plugins.cxx; -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -import org.junit.Test; -import org.sonar.api.batch.fs.FileSystem; - -public class CxxCpdMappingTest { +/** + * Package with visitor to define tokens used by CPD algorithm on files. + */ +@ParametersAreNonnullByDefault +package org.sonar.plugins.cxx.cpd; - @Test - public void testMapping() { - CxxLanguage language = mock(CxxLanguage.class); - FileSystem fs = TestUtils.mockFileSystem(); - CxxCpdMapping mapping = new CxxCpdMapping(language, fs); - assertThat(mapping.getLanguage()).isSameAs(language); - assertThat(mapping.getTokenizer()).isInstanceOf(CxxTokenizer.class); - } -} +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/squid/CxxSquidSensor.java b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/squid/CxxSquidSensor.java index 13ee3b78d3..6b61628248 100644 --- a/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/squid/CxxSquidSensor.java +++ b/sonar-cxx-plugin/src/main/java/org/sonar/plugins/cxx/squid/CxxSquidSensor.java @@ -62,6 +62,7 @@ import org.sonar.api.ce.measure.RangeDistributionBuilder; import org.sonar.api.rule.RuleKey; import org.sonar.cxx.parser.CxxParser; +import org.sonar.plugins.cxx.cpd.CxxCpdVisitor; import org.sonar.plugins.cxx.highlighter.CxxHighlighter; @@ -111,6 +112,7 @@ public void describe(SensorDescriptor descriptor) { public void execute(SensorContext context) { List> visitors = new ArrayList<>((Collection) checks.all()); visitors.add(new CxxHighlighter(context)); + visitors.add(new CxxCpdVisitor(context)); this.scanner = CxxAstScanner.create(createConfiguration(context.fileSystem(), this.settings), context, visitors.toArray(new SquidAstVisitor[visitors.size()])); diff --git a/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxPluginTest.java b/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxPluginTest.java index 3867170c47..fa1850d88c 100644 --- a/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxPluginTest.java +++ b/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxPluginTest.java @@ -32,6 +32,6 @@ public void testGetExtensions() throws Exception { Plugin.Context context = new Plugin.Context(SonarQubeVersion.V5_6); CxxPlugin plugin = new CxxPlugin(); plugin.define(context); - assertThat(context.getExtensions()).hasSize(63); + assertThat(context.getExtensions()).hasSize(62); } } diff --git a/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxTokenizerTest.java b/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxTokenizerTest.java deleted file mode 100644 index 9a62d1e574..0000000000 --- a/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/CxxTokenizerTest.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Sonar C++ Plugin (Community) - * Copyright (C) 2010-2016 SonarOpenCommunity - * http://github.com/SonarOpenCommunity/sonar-cxx - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.cxx; - -import static org.fest.assertions.Assertions.assertThat; - -import java.io.File; -import java.net.URISyntaxException; -import java.nio.charset.Charset; -import java.util.List; - -import net.sourceforge.pmd.cpd.SourceCode; //@todo deprecated -import net.sourceforge.pmd.cpd.TokenEntry; //@todo deprecated -import net.sourceforge.pmd.cpd.Tokens; //@todo deprecated - -import org.junit.Test; - -public class CxxTokenizerTest { - - @Test - public void shouldWorkOnValidInput() throws URISyntaxException { - File file = new File(getClass().getResource("codechunks-project/code_chunks.cc").toURI()); - SourceCode source = new SourceCode(new SourceCode.FileCodeLoader(file, "key")); //@todo deprecated SourceCode - Tokens cpdTokens = new Tokens(); //@todo deprecated Tokens - CxxTokenizer tokenizer = new CxxTokenizer(Charset.forName("UTF-8")); - tokenizer.tokenize(source, cpdTokens); - List list = cpdTokens.getTokens(); //@todo deprecated TokenEntry - assertThat(list.size()).isEqualTo(371); - } - -} diff --git a/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/cpd/CxxCpdVisitorTest.java b/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/cpd/CxxCpdVisitorTest.java new file mode 100644 index 0000000000..7a32682fcb --- /dev/null +++ b/sonar-cxx-plugin/src/test/java/org/sonar/plugins/cxx/cpd/CxxCpdVisitorTest.java @@ -0,0 +1,86 @@ +/* + * Sonar C++ Plugin (Community) + * Copyright (C) 2010-2016 SonarOpenCommunity + * http://github.com/SonarOpenCommunity/sonar-cxx + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.cxx.cpd; + +import java.io.File; +import java.util.List; +import org.apache.commons.io.Charsets; +import static org.fest.assertions.Assertions.assertThat; +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.batch.sensor.internal.SensorContextTester; +import org.sonar.cxx.CxxAstScanner; + +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.fs.internal.FileMetadata; +import org.sonar.duplications.internal.pmd.TokensLine; + +public class CxxCpdVisitorTest { + + private SensorContextTester context; + private DefaultInputFile inputFile; + + @Before + @SuppressWarnings("unchecked") + public void scanFile() { + String dir = "src/test/resources/org/sonar/plugins/cxx"; + + File file = new File(dir, "/cpd.cc"); + inputFile = new DefaultInputFile("moduleKey", file.getName()) + .initMetadata(new FileMetadata().readMetadata(file, Charsets.UTF_8)); + + context = SensorContextTester.create(new File(dir)); + context.fileSystem().add(inputFile); + + CxxCpdVisitor cxxCpdVisitor = new CxxCpdVisitor(context); + CxxAstScanner.scanSingleFile(inputFile, context, cxxCpdVisitor); + } + + @Test + public void testCpdTokens() throws Exception { + List cpdTokenLines = context.cpdTokens("moduleKey:" + inputFile.file().getName()); + assertThat(cpdTokenLines).hasSize(75); + + // bits unixtime1(bits ld, bits ex) + TokensLine firstTokensLine = cpdTokenLines.get(0); + assertThat(firstTokensLine.getValue()).isEqualTo("_I_I(_I_I,_I_I)"); + assertThat(firstTokensLine.getStartLine()).isEqualTo(2); + assertThat(firstTokensLine.getStartUnit()).isEqualTo(1); + assertThat(firstTokensLine.getEndLine()).isEqualTo(2); + assertThat(firstTokensLine.getEndUnit()).isEqualTo(9); + + // ld &= 0xFF; + TokensLine secondTokensLine = cpdTokenLines.get(2); + assertThat(secondTokensLine.getValue()).isEqualTo("_I&=_N;"); + assertThat(secondTokensLine.getStartLine()).isEqualTo(4); + assertThat(secondTokensLine.getStartUnit()).isEqualTo(11); + assertThat(secondTokensLine.getEndLine()).isEqualTo(4); + assertThat(secondTokensLine.getEndUnit()).isEqualTo(14); + + // case 3: return "three"; + TokensLine thirdTokensLine = cpdTokenLines.get(71); + assertThat(thirdTokensLine.getValue()).isEqualTo("case_N:return_S;"); + assertThat(thirdTokensLine.getStartLine()).isEqualTo(86); + assertThat(thirdTokensLine.getStartUnit()).isEqualTo(388); + assertThat(thirdTokensLine.getEndLine()).isEqualTo(86); + assertThat(thirdTokensLine.getEndUnit()).isEqualTo(393); + } + +} diff --git a/sonar-cxx-plugin/src/test/resources/org/sonar/plugins/cxx/cpd.cc b/sonar-cxx-plugin/src/test/resources/org/sonar/plugins/cxx/cpd.cc new file mode 100644 index 0000000000..e0f48603c0 --- /dev/null +++ b/sonar-cxx-plugin/src/test/resources/org/sonar/plugins/cxx/cpd.cc @@ -0,0 +1,89 @@ +//------------------------------------ +bits unixtime1(bits ld, bits ex) +{ + ld &= 0xFF; + ld -= 51; + if (ex < 1855547904U) ld--; + ex -= 1855548004U; + return ex / 100 + 42949673U * ld - ld / 25; +} + +bits unixtime2(bits ld, bits ex) +{ + if (ld && ex) + { + ld &= 0xFF; + ld -= 51; + if (ex < 1855547904U) ld--; + ex -= 1855548004U; + return ex / 100 + 42949673U * ld - ld / 25; + } + return 0; +} + +//------------------------------------ +int acorntime(bits *ex, bits *ld, time_t utime) +{ + unsigned timlo; /* 3 lower bytes of acorn file-time plus carry byte */ + unsigned timhi; /* 2 high bytes of acorn file-time */ + + timlo = ((unsigned)utime & 0x00ffffffU) * 100 + 0x00996a00U; + timhi = ((unsigned)utime >> 24); + timhi = timhi * 100 + 0x0000336eU + (timlo >> 24); + if (timhi & 0xffff0000U) + return 1; /* calculation overflow, do not change time */ + + /* insert the five time bytes into loadaddr and execaddr variables */ + *ex = (timlo & 0x00ffffffU) | ((timhi & 0x000000ffU) << 24); + *ld = (*ld & 0xffffff00U) | ((timhi >> 8) & 0x000000ffU); + + return 0; /* subject to future extension to signal overflow */ +} + +//------------------------------------ +int object_exists1(char *fn) +{ + int ob; + if (xosfile_read_stamped_no_path(fn, &ob, 0, 0, 0, 0, 0)) return 0; + switch (ob) + { + case osfile_IS_FILE:return 1; + case osfile_IS_DIR:return 1; + case osfile_IS_IMAGE:return 1; + } + return 0; +} + +int object_exists2(char *fn) +{ + int ob; + if (xosfile_read_stamped_no_path(fn, &ob, 1, 1, 1, 1, 1)) return 1; + switch (ob) + { + case osfile_IS_FILE:return 2; + case osfile_IS_DIR:return 2; + case osfile_IS_IMAGE:return 2; + } + return 0; +} + +//------------------------------------ +char* tostring1(int value) +{ + switch (value) + { + case 0: return "zero"; + case 1: return "one"; + } + return "undefined"; +} + +char* tostring2(int value) +{ + switch (value) + { + case 2: return "two"; + case 3: return "three"; + } + return "undefined"; +}