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   * @since 0.26.0
24   */
25  public final class UseCollectionsSingletonListRule
26      extends AbstractJavaRulechainRule {
27  
28      /**
29       * Matcher for any invocation of {@code java.util.Arrays.asList}.
30       */
31      private static final InvocationMatcher AS_LIST =
32          InvocationMatcher.parse("java.util.Arrays#asList(_*)");
33  
34      public UseCollectionsSingletonListRule() {
35          super(ASTMethodCall.class);
36      }
37  
38      @Override
39      public Object visit(final ASTMethodCall call, final Object data) {
40          if (UseCollectionsSingletonListRule.shouldUseSingletonList(call)) {
41              this.asCtx(data).addViolation(call);
42          }
43          return data;
44      }
45  
46      private static boolean shouldUseSingletonList(final ASTMethodCall call) {
47          boolean result = false;
48          if (UseCollectionsSingletonListRule.AS_LIST.matchesCall(call)) {
49              final ASTArgumentList args = call.getArguments();
50              result = args.size() == 1
51                  && !args.get(0).getTypeMirror().isArray();
52          }
53          return result;
54      }
55  }