• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.turbine.binder;
18 
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.ImmutableSet;
21 import com.google.common.collect.ListMultimap;
22 import com.google.common.collect.MultimapBuilder;
23 import com.google.turbine.binder.bound.SourceTypeBoundClass;
24 import com.google.turbine.binder.env.Env;
25 import com.google.turbine.binder.env.SimpleEnv;
26 import com.google.turbine.binder.sym.ClassSymbol;
27 import com.google.turbine.model.TurbineFlag;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Set;
31 
32 final class PermitsBinder {
33 
34   /**
35    * Given the classes in the current compilation, finds implicit permitted subtypes of sealed
36    * classes.
37    *
38    * <p>See JLS §8.1.1.2 for details of implicit permits.
39    *
40    * @param syms the set of classes being compiled in this compilation unit
41    * @param tenv the environment of the current compilation unit only. Dependencies from the
42    *     classpath or bootclasspath are not required by this pass, because any implicitly permitted
43    *     subtypes are required to be in the same compilation unit as their supertype.
44    */
bindPermits( ImmutableSet<ClassSymbol> syms, Env<ClassSymbol, SourceTypeBoundClass> tenv)45   static Env<ClassSymbol, SourceTypeBoundClass> bindPermits(
46       ImmutableSet<ClassSymbol> syms, Env<ClassSymbol, SourceTypeBoundClass> tenv) {
47     Set<ClassSymbol> sealedClassesWithoutExplicitPermits = new HashSet<>();
48     for (ClassSymbol sym : syms) {
49       SourceTypeBoundClass info = tenv.getNonNull(sym);
50       if (((info.access() & TurbineFlag.ACC_SEALED) == TurbineFlag.ACC_SEALED)
51           && info.permits().isEmpty()) {
52         sealedClassesWithoutExplicitPermits.add(sym);
53       }
54     }
55     if (sealedClassesWithoutExplicitPermits.isEmpty()) {
56       // fast path if there were no sealed types with an empty 'permits' clause
57       return tenv;
58     }
59     ListMultimap<ClassSymbol, ClassSymbol> permits =
60         MultimapBuilder.hashKeys().arrayListValues().build();
61     for (ClassSymbol sym : syms) {
62       SourceTypeBoundClass info = tenv.getNonNull(sym);
63       // Check if the current class has a direct supertype that is a sealed class with an empty
64       // 'permits' clause.
65       ClassSymbol superclass = info.superclass();
66       if (superclass != null && sealedClassesWithoutExplicitPermits.contains(superclass)) {
67         permits.put(superclass, sym);
68       }
69       for (ClassSymbol i : info.interfaces()) {
70         if (sealedClassesWithoutExplicitPermits.contains(i)) {
71           permits.put(i, sym);
72         }
73       }
74     }
75     SimpleEnv.Builder<ClassSymbol, SourceTypeBoundClass> builder = SimpleEnv.builder();
76     for (ClassSymbol sym : syms) {
77       List<ClassSymbol> thisPermits = permits.get(sym);
78       SourceTypeBoundClass base = tenv.getNonNull(sym);
79       if (thisPermits.isEmpty()) {
80         builder.put(sym, base);
81       } else {
82         builder.put(
83             sym,
84             new SourceTypeBoundClass(
85                 /* interfaceTypes= */ base.interfaceTypes(),
86                 /* permits= */ ImmutableList.copyOf(thisPermits),
87                 /* superClassType= */ base.superClassType(),
88                 /* typeParameterTypes= */ base.typeParameterTypes(),
89                 /* access= */ base.access(),
90                 /* components= */ base.components(),
91                 /* methods= */ base.methods(),
92                 /* fields= */ base.fields(),
93                 /* owner= */ base.owner(),
94                 /* kind= */ base.kind(),
95                 /* children= */ base.children(),
96                 /* typeParameters= */ base.typeParameters(),
97                 /* enclosingScope= */ base.enclosingScope(),
98                 /* scope= */ base.scope(),
99                 /* memberImports= */ base.memberImports(),
100                 /* annotationMetadata= */ base.annotationMetadata(),
101                 /* annotations= */ base.annotations(),
102                 /* source= */ base.source(),
103                 /* decl= */ base.decl()));
104       }
105     }
106     return builder.build();
107   }
108 
PermitsBinder()109   private PermitsBinder() {}
110 }
111