View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.pmd.rules;
6   
7   import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
8   import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
9   import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
10  import net.sourceforge.pmd.lang.java.types.InvocationMatcher;
11  
12  /**
13   * Rule to flag {@code Arrays.asList} invocations that are passed a single
14   * non-array argument. {@code Arrays.asList(x)} where {@code x} is a scalar
15   * (e.g. an {@code int}, a {@code String} or any non-array reference) ends
16   * up allocating a backing one-element array via varargs and a wrapper list
17   * around it. {@code Collections.singletonList(x)} expresses the same intent
18   * with a single, immutable, fixed-size list and no implicit array
19   * allocation. A single array argument is not flagged because that form
20   * either spreads the array's elements (for reference arrays) or wraps the
21   * array itself in a one-element list (for primitive arrays), and either
22   * behaviour may be intentional.
23   *
24   * @since 0.26.0
25   */
26  public final class UseCollectionsSingletonListRule
27      extends AbstractJavaRulechainRule {
28  
29      /**
30       * Matcher for any invocation of {@code java.util.Arrays.asList}.
31       */
32      private static final InvocationMatcher AS_LIST =
33          InvocationMatcher.parse("java.util.Arrays#asList(_*)");
34  
35      /**
36       * Default constructor.
37       */
38      public UseCollectionsSingletonListRule() {
39          super(ASTMethodCall.class);
40      }
41  
42      @Override
43      public Object visit(final ASTMethodCall call, final Object data) {
44          if (UseCollectionsSingletonListRule.shouldUseSingletonList(call)) {
45              this.asCtx(data).addViolation(call);
46          }
47          return data;
48      }
49  
50      private static boolean shouldUseSingletonList(final ASTMethodCall call) {
51          boolean result = false;
52          if (UseCollectionsSingletonListRule.AS_LIST.matchesCall(call)) {
53              final ASTArgumentList args = call.getArguments();
54              result = args.size() == 1
55                  && !args.get(0).getTypeMirror().isArray();
56          }
57          return result;
58      }
59  }