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