aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/tools/android/java/com/google/devtools/build/android/desugar/DependencyCollector.java
blob: 272a273598a976ed0ae1104d38670aee37529bab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.android.desugar;

import javax.annotation.Nullable;

/**
 * Interface for collecting desugaring metadata that we can use to double-check correct desugaring
 * at the binary level by looking at the metadata written for all Jars on the runtime classpath
 * (b/65645388). Use {@link NoWriteCollectors} for "no-op" collectors and {@link
 * com.google.devtools.build.android.desugar.dependencies.MetadataCollector} for writing out
 * metadata files.
 */
// TODO(kmb): There could conceivably be a "self-contained" version where we check at the end that
// we actually saw all the companion classes (in recordDefaultMethods) that we "assumed"; useful
// for one-shot runs over an entire binary.
@SuppressWarnings("unused") // default implementations consist of empty method stubs
public interface DependencyCollector {

  /** Class name suffix used for interface companion classes. */
  public String INTERFACE_COMPANION_SUFFIX = "$$CC";

  /**
   * Records that {@code origin} depends on companion class {@code target}.  For the resulting
   * binary to be valid, {@code target} needs to exist, which isn't the case if the corresponding
   * interface is only available as a compile-time ("neverlink") dependency.
   */
  default void assumeCompanionClass(String origin, String target) {}

  /**
   * Records that {@code origin} transitively implements {@code target} but {@code target} isn't
   * in the classpath.  This can lead to wrong desugarings if {@code target} or an interface it
   * extends defines default methods.
   */
  default void missingImplementedInterface(String origin, String target) {}

  /**
   * Records that the given interface extends the given interfaces.
   *
   * <p>This information is useful reference to double-check {@link #missingImplementedInterface}s
   * without reading and parsing .class files, specifically if default methods are defined in
   * interfaces that a missing interface transitively extends.
   */
  default void recordExtendedInterfaces(String origin, String... targets) {}

  /**
   * Records that the given interface has a companion class that includes the given number of
   * default methods (0 if there were only static methods).  This method should not be called for
   * purely abstract interfaces, to allow verifying available companion classes against this.
   *
   * <p>This information is useful reference to double-check {@link #missingImplementedInterface}s
   * without reading and parsing .class files with better precision than just looking for
   * companion classes on the runtime classpath (which may only contain static methods).
   */
  default void recordDefaultMethods(String origin, int count) {}

  /**
   * Returns metadata to include into the desugaring output or {@code null} if none.  Returning
   * anything but {@code null} will cause an extra file to be written into the output, including
   * an empty array.
   */
  @Nullable public byte[] toByteArray();

  /** Simple collectors that don't collect any information. */
  public enum NoWriteCollectors implements DependencyCollector {
    /** Singleton instance that does nothing. */
    NOOP,
    /**
     * Singleton instance that does nothing besides throwing if {@link #missingImplementedInterface}
     * is called.
     */
    FAIL_ON_MISSING {
      @Override
      public void missingImplementedInterface(String origin, String target) {
        throw new IllegalStateException(
            String.format(
                "Couldn't find interface %s on the classpath for desugaring %s", target, origin));
      }
    };

    @Override
    @Nullable
    public final byte[] toByteArray() {
      return null;
    }
  }
}