Skip to content

Commit

Permalink
34422: Combined 'skip sequences'-related flags
Browse files Browse the repository at this point in the history
The --ignore-sequences option now optionally takes an argument specifying which 'ignore sequence' strategies should be applied. Multiple strategies can be enabled by providing the option multiple times.

The existing behavior of --ignore-sequences without a parameter (defaulting to 'ignore literal and identifier sequences') and --ignore-literal-sequences is preserved.
  • Loading branch information
brouwers-tiobe committed Nov 1, 2024
1 parent 441e91c commit e15bffe
Show file tree
Hide file tree
Showing 13 changed files with 256 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.mutable.MutableBoolean;
import org.checkerframework.checker.nullness.qual.NonNull;

import net.sourceforge.pmd.cli.commands.typesupport.internal.CpdIgnoreTypeSupport;
import net.sourceforge.pmd.cli.commands.typesupport.internal.CpdLanguageTypeSupport;
import net.sourceforge.pmd.cli.internal.CliExitCode;
import net.sourceforge.pmd.cpd.CPDConfiguration;
import net.sourceforge.pmd.cpd.CPDSequenceIgnoreType;
import net.sourceforge.pmd.cpd.CpdAnalysis;
import net.sourceforge.pmd.cpd.internal.CpdLanguagePropertiesDefaults;
import net.sourceforge.pmd.internal.LogMessages;
Expand Down Expand Up @@ -65,8 +69,13 @@ public class CpdCommand extends AbstractAnalysisPmdSubcommand<CPDConfiguration>
@Option(names = "--ignore-literal-sequences", description = "Ignore sequences of literals such as list initializers.")
private boolean ignoreLiteralSequences;

@Option(names = "--ignore-sequences", description = "Ignore sequences of identifiers and literals")
private boolean ignoreIdentifierAndLiteralSequences;
@Option(names = "--ignore-sequences",
arity = "0..1",
description = "Types of sequences to exclude from duplication.%nValid values: ${COMPLETION-CANDIDATES}",
converter = CpdIgnoreTypeSupport.class,
completionCandidates = CpdIgnoreTypeSupport.class,
fallbackValue = "literals-identifiers")
private Set<CPDSequenceIgnoreType> sequenceIgnoreTypes = new HashSet<>();

/**
* @deprecated Use {@link #failOnError} instead.
Expand Down Expand Up @@ -115,8 +124,9 @@ protected CPDConfiguration toConfiguration() {
configuration.setIgnoreAnnotations(ignoreAnnotations);
configuration.setIgnoreIdentifiers(ignoreIdentifiers);
configuration.setIgnoreLiterals(ignoreLiterals);
configuration.setIgnoreLiteralSequences(ignoreLiteralSequences);
configuration.setIgnoreIdentifierAndLiteralSequences(ignoreIdentifierAndLiteralSequences);
configuration.setIgnoreLiteralSequences(ignoreLiteralSequences || sequenceIgnoreTypes.contains(CPDSequenceIgnoreType.LITERALS));
configuration.setIgnoreIdentifierAndLiteralSequences(sequenceIgnoreTypes.contains(CPDSequenceIgnoreType.LITERALS_IDENTIFIERS));
configuration.setIgnoreSequenceInitializations(sequenceIgnoreTypes.contains(CPDSequenceIgnoreType.INITIALIZATIONS));
configuration.setIgnoreUsings(ignoreUsings);
configuration.setOnlyRecognizeLanguage(language);
configuration.setMinimumTileSize(minimumTokens);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/

package net.sourceforge.pmd.cli.commands.typesupport.internal;

import java.util.Arrays;
import java.util.Iterator;

import net.sourceforge.pmd.cpd.CPDSequenceIgnoreType;

import picocli.CommandLine.ITypeConverter;
import picocli.CommandLine.TypeConversionException;

public class CpdIgnoreTypeSupport implements ITypeConverter<CPDSequenceIgnoreType>, Iterable<String> {

@Override
public Iterator<String> iterator() {
return Arrays.stream(CPDSequenceIgnoreType.values()).map(CPDSequenceIgnoreType::getName).iterator();
}

@Override
public CPDSequenceIgnoreType convert(String s) {
return Arrays.stream(CPDSequenceIgnoreType.values())
.filter(t -> t.getName().equalsIgnoreCase(s))
.findFirst()
.orElseThrow(() -> new TypeConversionException("Invalid ignore option: " + s));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import net.sourceforge.pmd.cpd.CPDConfiguration;
import net.sourceforge.pmd.util.CollectionUtil;
Expand Down Expand Up @@ -59,6 +64,81 @@ private void assertMultipleDirs(final CpdCommand result) {
assertEquals(listOf("a", "b"), CollectionUtil.map(config.getInputPathList(), Path::toString));
}

@ParameterizedTest
@MethodSource("ignoreArgs")
void testIgnoreOption(String[] args, ExpectedIgnoreOptions ignore) {
final CpdCommand cmd = setupAndParse(args);
CPDConfiguration config = cmd.toConfiguration();
assertIgnore(config, ignore);
}

static Collection<Arguments> ignoreArgs() {
Collection<Arguments> args = new ArrayList<Arguments>();
args.add(Arguments.of(
new String[] {
"--ignore-sequences",
"literals",
},
new ExpectedIgnoreOptions(false, true, false, false)
));
args.add(Arguments.of(
new String[] {
"--ignore-sequences",
"literals-identifiers",
},
new ExpectedIgnoreOptions(false, false, true, false)
));
args.add(Arguments.of(
new String[] {
"--ignore-sequences",
"initializations",
},
new ExpectedIgnoreOptions(false, false, false, true)
));
args.add(Arguments.of(
new String[] {
"--ignore-sequences",
"literals-identifiers",
"--ignore-sequences",
"initializations",
},
new ExpectedIgnoreOptions(false, false, true, true)
));
args.add(Arguments.of(
new String[] {
"--ignore-sequences",
},
new ExpectedIgnoreOptions(false, false, true, false)
));
return args;
}

static class ExpectedIgnoreOptions {
boolean annotations;
boolean literalSequences;
boolean identifierSequences;
boolean arrayInitializations;

ExpectedIgnoreOptions(
boolean annotations,
boolean literalSequences,
boolean identifierSequences,
boolean arrayInitializations
) {
this.annotations = annotations;
this.literalSequences = literalSequences;
this.identifierSequences = identifierSequences;
this.arrayInitializations = arrayInitializations;
}
}

void assertIgnore(CPDConfiguration config, ExpectedIgnoreOptions exp) {
assertEquals(config.isIgnoreLiteralSequences(), exp.literalSequences, "Expected isIgnoreLiteralSequences() to be " + exp.literalSequences);
assertEquals(config.isIgnoreIdentifierAndLiteralSequences(), exp.identifierSequences, "Expected isIgnoreLiteralAndIdentifierSequences() to be " + exp.identifierSequences);
assertEquals(config.isIgnoreSequenceInitializations(), exp.arrayInitializations, "Expected isIgnoreArrayInitializations() to be " + exp.arrayInitializations);
}


@Override
protected CpdCommand createCommand() {
return new CpdCommand();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,7 @@ public class CPDConfiguration extends AbstractConfiguration {

private boolean ignoreUsings;

private boolean ignoreLiteralSequences = false;

private boolean ignoreIdentifierAndLiteralSequences = false;
private CPDSequenceIgnoreSetting ignoreSequences = new CPDSequenceIgnoreSetting();

@Deprecated
// Note: The default value was false until up to 7.3.0 and is true since 7.4.0
Expand Down Expand Up @@ -181,6 +179,10 @@ void setRenderer(CPDReportRenderer renderer) {
this.cpdReportRenderer = renderer;
}

public void setIgnoreSequences(CPDSequenceIgnoreSetting value) {
this.ignoreSequences = value;
}

public boolean isIgnoreLiterals() {
return ignoreLiterals;
}
Expand Down Expand Up @@ -214,19 +216,27 @@ public void setIgnoreUsings(boolean ignoreUsings) {
}

public boolean isIgnoreLiteralSequences() {
return ignoreLiteralSequences;
return ignoreSequences.getValue(CPDSequenceIgnoreType.LITERALS);
}

public void setIgnoreLiteralSequences(boolean ignoreLiteralSequences) {
this.ignoreLiteralSequences = ignoreLiteralSequences;
ignoreSequences.setValue(CPDSequenceIgnoreType.LITERALS, ignoreLiteralSequences);
}

public boolean isIgnoreIdentifierAndLiteralSequences() {
return ignoreIdentifierAndLiteralSequences;
return ignoreSequences.getValue(CPDSequenceIgnoreType.LITERALS_IDENTIFIERS);
}

public void setIgnoreIdentifierAndLiteralSequences(boolean ignoreIdentifierAndLiteralSequences) {
this.ignoreIdentifierAndLiteralSequences = ignoreIdentifierAndLiteralSequences;
ignoreSequences.setValue(CPDSequenceIgnoreType.LITERALS_IDENTIFIERS, ignoreIdentifierAndLiteralSequences);
}

public boolean isIgnoreSequenceInitializations() {
return ignoreSequences.getValue(CPDSequenceIgnoreType.INITIALIZATIONS);
}

public void setIgnoreSequenceInitializations(boolean ignoreSequenceInitializations) {
ignoreSequences.setValue(CPDSequenceIgnoreType.INITIALIZATIONS, ignoreSequenceInitializations);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/

package net.sourceforge.pmd.cpd;

public class CPDSequenceIgnoreSetting {
private int setting = 0;

public void setValue(CPDSequenceIgnoreType type, boolean value) {
int index = type.ordinal();
if (value) {
setting |= (1 << index);
} else {
setting &= ~(1 << index);
}
}

public boolean getValue(CPDSequenceIgnoreType type) {
return (setting & (1 << type.ordinal())) != 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/

package net.sourceforge.pmd.cpd;

/**
* Options for skipping/ignoring tokens in CPD
*/
public enum CPDSequenceIgnoreType {
LITERALS("literals"),
LITERALS_IDENTIFIERS("literals-identifiers"),
INITIALIZATIONS("initializations");

private final String name;

CPDSequenceIgnoreType(String name) {
this.name = name;
}

public String getName() {
return name;
}

@Override
public String toString() {
return name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ private void setLanguageProperties(Language language, CPDConfiguration configura
setPropertyIfMissing(CpdLanguageProperties.CPD_IGNORE_IMPORTS, props, configuration.isIgnoreUsings());
setPropertyIfMissing(CpdLanguageProperties.CPD_IGNORE_LITERAL_SEQUENCES, props, configuration.isIgnoreLiteralSequences());
setPropertyIfMissing(CpdLanguageProperties.CPD_IGNORE_LITERAL_AND_IDENTIFIER_SEQUENCES, props, configuration.isIgnoreIdentifierAndLiteralSequences());
setPropertyIfMissing(CpdLanguageProperties.CPD_IGNORE_SEQUENCE_INITIALIZATION, props, configuration.isIgnoreSequenceInitializations());
if (!configuration.isNoSkipBlocks()) {
// see net.sourceforge.pmd.lang.cpp.CppLanguageModule.CPD_SKIP_BLOCKS
PropertyDescriptor<String> skipBlocks = (PropertyDescriptor) props.getPropertyDescriptor("cpdSkipBlocksPattern");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,9 @@ private CpdLanguageProperties() {
.defaultValue(false)
.desc("Ignore metadata such as Java annotations or C# attributes.")
.build();
public static final PropertyDescriptor<Boolean> CPD_IGNORE_SEQUENCE_INITIALIZATION =
PropertyFactory.booleanProperty("cpdIgnoreSequenceInitialization")
.defaultValue(false)
.desc("Ignore sequence initializations.")
.build();
}
25 changes: 19 additions & 6 deletions pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ public boolean canIgnoreIdentifierAndLiteralSequences() {
return getLanguage().newPropertyBundle().hasDescriptor(CpdLanguageProperties.CPD_IGNORE_LITERAL_AND_IDENTIFIER_SEQUENCES);
}

public boolean canIgnoreSequenceInitalization() {
return getLanguage().newPropertyBundle().hasDescriptor(CpdLanguageProperties.CPD_IGNORE_SEQUENCE_INITIALIZATION);
}
}

private static final List<LanguageConfig> LANGUAGE_SETS;
Expand Down Expand Up @@ -334,6 +337,7 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole
private final JCheckBox ignoreUsingsCheckbox = new JCheckBox("", false);
private final JCheckBox ignoreLiteralSequencesCheckbox = new JCheckBox("", false);
private final JCheckBox ignoreIdentifierAndLiteralSequencesCheckbox = new JCheckBox("", false);
private final JCheckBox ignoreSequenceInitalizationsCheckbox = new JCheckBox("", false);
private final JComboBox<String> languageBox = new JComboBox<>();
private final JTextField extensionField = new JTextField();
private final JLabel extensionLabel = new JLabel("Extension:", SwingConstants.RIGHT);
Expand Down Expand Up @@ -427,6 +431,7 @@ private void adjustLanguageControlsFor(LanguageConfig current) {
ignoreUsingsCheckbox.setEnabled(current.canIgnoreUsings());
ignoreLiteralSequencesCheckbox.setEnabled(current.canIgnoreLiteralSequences());
ignoreIdentifierAndLiteralSequencesCheckbox.setEnabled(current.canIgnoreIdentifierAndLiteralSequences());
ignoreSequenceInitalizationsCheckbox.setEnabled(current.canIgnoreSequenceInitalization());
boolean enableExtension = current.canUseCustomExtension();
if (enableExtension) {
extensionField.setText("");
Expand Down Expand Up @@ -492,22 +497,29 @@ private JPanel makeSettingsPanel(JButton browseButton, JButton goButton, JButton
helper.nextRow();
helper.addLabel("Ignore literal sequences?");
helper.add(ignoreLiteralSequencesCheckbox);
helper.add(goButton);
helper.add(cxButton);
helper.addLabel("");
helper.addLabel("");
helper.nextRow();

helper.nextRow();
helper.addLabel("Ignore identifier and literal sequences?");
helper.add(ignoreIdentifierAndLiteralSequencesCheckbox);
helper.add(goButton);
helper.add(cxButton);
helper.addLabel("");
helper.addLabel("");
helper.nextRow();

helper.nextRow();
helper.addLabel("Ignore sequence initalizations?");
helper.add(ignoreSequenceInitalizationsCheckbox);
helper.addLabel("");
helper.addLabel("");
helper.nextRow();

helper.addLabel("File encoding (defaults based upon locale):");
encodingField.setColumns(1);
helper.add(encodingField);
helper.addLabel("");
helper.addLabel("");
helper.add(goButton);
helper.add(cxButton);
helper.nextRow();
// settingsPanel.setBorder(BorderFactory.createTitledBorder("Settings"));
return settingsPanel;
Expand Down Expand Up @@ -660,6 +672,7 @@ private void go() {
config.setIgnoreUsings(ignoreUsingsCheckbox.isSelected());
config.setIgnoreLiteralSequences(ignoreLiteralSequencesCheckbox.isSelected());
config.setIgnoreIdentifierAndLiteralSequences(ignoreIdentifierAndLiteralSequencesCheckbox.isSelected());
config.setIgnoreSequenceInitializations(ignoreSequenceInitalizationsCheckbox.isSelected());
if (extensionField.isEnabled()) {
CUSTOM_EXTENSION_LANG.setExtension(extensionField.getText());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public LanguagePropertyBundle newPropertyBundle() {
LanguagePropertyBundle bundle = super.newPropertyBundle();
bundle.definePropertyDescriptor(CpdLanguageProperties.CPD_IGNORE_LITERAL_SEQUENCES);
bundle.definePropertyDescriptor(CpdLanguageProperties.CPD_IGNORE_LITERAL_AND_IDENTIFIER_SEQUENCES);
bundle.definePropertyDescriptor(CpdLanguageProperties.CPD_IGNORE_SEQUENCE_INITIALIZATION);
bundle.definePropertyDescriptor(CPD_SKIP_BLOCKS);
return bundle;
}
Expand Down
Loading

0 comments on commit e15bffe

Please sign in to comment.