| /******************************************************************************* |
| * Copyright (c) 2018 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * |
| *******************************************************************************/ |
| package org.aspectj.org.eclipse.jdt.internal.compiler.apt.model; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.lang.model.element.Element; |
| import javax.lang.model.element.ElementKind; |
| import javax.lang.model.element.ElementVisitor; |
| import javax.lang.model.element.Modifier; |
| import javax.lang.model.element.ModuleElement; |
| import javax.lang.model.element.Name; |
| import javax.lang.model.element.PackageElement; |
| import javax.lang.model.element.TypeElement; |
| |
| import org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.PackageBinding; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.SplitPackageBinding; |
| import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding; |
| |
| public class ModuleElementImpl extends ElementImpl implements ModuleElement { |
| |
| ModuleBinding binding; |
| private List<Directive> directives; |
| private static List<Directive> EMPTY_DIRECTIVES = Collections.emptyList(); |
| |
| /** |
| * In general, clients should call |
| * {@link Factory#newDeclaredType(org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)} or |
| * {@link Factory#newElement(org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding)} |
| * to create new instances. |
| */ |
| ModuleElementImpl(BaseProcessingEnvImpl env, ModuleBinding binding) { |
| super(env, binding); |
| this.binding = binding; |
| } |
| |
| private PackageBinding getModulesPackageBinding(PackageBinding binding) { |
| if (binding instanceof SplitPackageBinding) { |
| return ((SplitPackageBinding) binding).getIncarnation(this.binding); |
| } |
| return binding; |
| } |
| |
| @Override |
| public ElementKind getKind() { |
| return ElementKind.MODULE; |
| } |
| |
| @Override |
| public Set<Modifier> getModifiers() { |
| int modifiers = this.binding.modifiers; |
| return Factory.getModifiers(modifiers, getKind(), false); |
| } |
| |
| @Override |
| public Name getQualifiedName() { |
| return new NameImpl(this.binding.moduleName); |
| } |
| |
| @Override |
| public Name getSimpleName() { |
| return new NameImpl(this.binding.moduleName); |
| } |
| |
| @Override |
| public List<? extends Element> getEnclosedElements() { |
| ModuleBinding module = this.binding; |
| PackageBinding[] packs = module.declaredPackages.valueTable; |
| Set<PackageBinding> unique = new HashSet<>(); |
| for (PackageBinding p : packs) { |
| if (p == null) |
| continue; |
| if (!p.hasCompilationUnit(true)) |
| continue; |
| unique.add(getModulesPackageBinding(p)); |
| } |
| if (module.isUnnamed()) { |
| PackageBinding def = module.environment.defaultPackage; |
| // FIXME: Does it have any impact for unnamed modules - default package combo? |
| if (def != null && def.hasCompilationUnit(true)) { |
| unique.add(def); |
| } |
| } else { |
| packs = this.binding.getExports(); |
| for (PackageBinding pBinding : packs) { |
| unique.add(getModulesPackageBinding(pBinding)); |
| } |
| packs = this.binding.getOpens(); |
| for (PackageBinding pBinding : packs) { |
| unique.add(getModulesPackageBinding(pBinding)); |
| } |
| } |
| List<Element> enclosed = new ArrayList<>(unique.size()); |
| for (PackageBinding p : unique) { |
| PackageElement pElement = (PackageElement) _env.getFactory().newElement(p); |
| enclosed.add(pElement); |
| } |
| return Collections.unmodifiableList(enclosed); |
| } |
| |
| @Override |
| public boolean isOpen() { |
| return (this.binding.modifiers & ClassFileConstants.ACC_OPEN) != 0; |
| } |
| |
| @Override |
| public boolean isUnnamed() { |
| return this.binding.moduleName.length == 0; |
| } |
| |
| @Override |
| public Element getEnclosingElement() { |
| // As of today, modules have no enclosing element |
| return null; |
| } |
| |
| @Override |
| public List<? extends Directive> getDirectives() { |
| if (isUnnamed()) { |
| return EMPTY_DIRECTIVES; |
| } |
| if (this.directives == null) |
| this.directives = new ArrayList<>(); |
| |
| PackageBinding[] packs = this.binding.getExports(); |
| for (PackageBinding exp : packs) { |
| exp = getModulesPackageBinding(exp); |
| this.directives.add(new ExportsDirectiveImpl(exp)); |
| } |
| Set<ModuleBinding> transitive = new HashSet<>(); |
| for (ModuleBinding mBinding : this.binding.getRequiresTransitive()) { |
| transitive.add(mBinding); |
| } |
| ModuleBinding[] required = this.binding.getRequires(); |
| for (ModuleBinding mBinding : required) { |
| if (transitive.contains(mBinding)) { |
| this.directives.add(new RequiresDirectiveImpl(mBinding, true)); |
| } else { |
| this.directives.add(new RequiresDirectiveImpl(mBinding, false)); |
| } |
| } |
| |
| TypeBinding[] tBindings = this.binding.getUses(); |
| for (TypeBinding tBinding : tBindings) { |
| this.directives.add(new UsesDirectiveImpl(tBinding)); |
| } |
| tBindings = this.binding.getServices(); |
| for (TypeBinding tBinding : tBindings) { |
| this.directives.add(new ProvidesDirectiveImpl(tBinding)); |
| } |
| packs = this.binding.getOpens(); |
| for (PackageBinding exp : packs) { |
| exp = getModulesPackageBinding(exp); |
| this.directives.add(new OpensDirectiveImpl(exp)); |
| } |
| return this.directives; |
| } |
| |
| @Override |
| public <R, P> R accept(ElementVisitor<R, P> visitor, P param) { |
| return visitor.visitModule(this, param); |
| } |
| @Override |
| protected AnnotationBinding[] getAnnotationBindings() { |
| return ((ModuleBinding) _binding).getAnnotations(); |
| } |
| |
| abstract class PackageDirectiveImpl { |
| PackageBinding binding; |
| List<ModuleElement> targets; |
| |
| PackageDirectiveImpl(PackageBinding pBinding) { |
| this.binding = pBinding; |
| } |
| |
| public PackageElement getPackage() { |
| return _env.getFactory().newPackageElement(binding); |
| } |
| |
| public List<? extends ModuleElement> getTargetModules(String[] restrictions) { |
| if(this.targets != null) { |
| return targets; |
| } |
| if (restrictions.length == 0) { |
| return (this.targets = null); |
| } |
| List<ModuleElement> targets = new ArrayList<>(restrictions.length); |
| for (String string : restrictions) { |
| ModuleBinding target = ModuleElementImpl.this.binding.environment.getModule(string.toCharArray()); |
| if (target != null) { |
| ModuleElement element = ((ModuleElement) _env.getFactory().newElement(target)); |
| targets.add(element); |
| } |
| } |
| return (this.targets = Collections.unmodifiableList(targets)); |
| } |
| } |
| |
| class ExportsDirectiveImpl extends PackageDirectiveImpl implements ModuleElement.ExportsDirective { |
| |
| ExportsDirectiveImpl(PackageBinding pBinding) { |
| super(pBinding); |
| } |
| |
| @Override |
| public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) { |
| return visitor.visitExports(this, param); |
| } |
| |
| @Override |
| public javax.lang.model.element.ModuleElement.DirectiveKind getKind() { |
| return DirectiveKind.EXPORTS; |
| } |
| |
| @Override |
| public PackageElement getPackage() { |
| return _env.getFactory().newPackageElement(binding); |
| } |
| @Override |
| public List<? extends ModuleElement> getTargetModules() { |
| if(this.targets != null) { |
| return targets; |
| } |
| return getTargetModules(ModuleElementImpl.this.binding.getExportRestrictions(this.binding)); |
| } |
| |
| } |
| |
| class RequiresDirectiveImpl implements ModuleElement.RequiresDirective { |
| ModuleBinding dependency; |
| boolean transitive; |
| |
| RequiresDirectiveImpl(ModuleBinding dependency, boolean transitive) { |
| this.dependency = dependency; |
| this.transitive = transitive; |
| } |
| |
| @Override |
| public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) { |
| return visitor.visitRequires(this, param); |
| } |
| |
| @Override |
| public javax.lang.model.element.ModuleElement.DirectiveKind getKind() { |
| return DirectiveKind.REQUIRES; |
| } |
| |
| @Override |
| public ModuleElement getDependency() { |
| return (ModuleElement) _env.getFactory().newElement(dependency, ElementKind.MODULE); |
| } |
| |
| @Override |
| public boolean isStatic() { |
| // TODO: Yet to see this in ModuleBinding. Check again. |
| return false; |
| } |
| |
| @Override |
| public boolean isTransitive() { |
| return this.transitive; |
| } |
| } |
| |
| class OpensDirectiveImpl extends PackageDirectiveImpl implements ModuleElement.OpensDirective { |
| |
| OpensDirectiveImpl(PackageBinding pBinding) { |
| super(pBinding); |
| } |
| |
| @Override |
| public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) { |
| return visitor.visitOpens(this, param); |
| } |
| |
| @Override |
| public javax.lang.model.element.ModuleElement.DirectiveKind getKind() { |
| return DirectiveKind.OPENS; |
| } |
| @Override |
| public List<? extends ModuleElement> getTargetModules() { |
| if(this.targets != null) { |
| return targets; |
| } |
| return getTargetModules(ModuleElementImpl.this.binding.getOpenRestrictions(this.binding)); |
| } |
| } |
| |
| class UsesDirectiveImpl implements ModuleElement.UsesDirective { |
| TypeBinding binding = null; |
| |
| UsesDirectiveImpl(TypeBinding binding) { |
| this.binding = binding; |
| } |
| |
| @Override |
| public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) { |
| return visitor.visitUses(this, param); |
| } |
| |
| @Override |
| public DirectiveKind getKind() { |
| return DirectiveKind.USES; |
| } |
| |
| @Override |
| public TypeElement getService() { |
| return (TypeElement) _env.getFactory().newElement(binding); |
| } |
| |
| } |
| |
| class ProvidesDirectiveImpl implements ModuleElement.ProvidesDirective { |
| |
| TypeBinding service; |
| public List<? extends TypeElement> implementations; |
| |
| ProvidesDirectiveImpl(TypeBinding service) { |
| this.service = service; |
| } |
| |
| @Override |
| public <R, P> R accept(DirectiveVisitor<R, P> visitor, P param) { |
| return visitor.visitProvides(this, param); |
| } |
| |
| @Override |
| public DirectiveKind getKind() { |
| return DirectiveKind.PROVIDES; |
| } |
| |
| @Override |
| public List<? extends TypeElement> getImplementations() { |
| if (this.implementations != null) |
| return this.implementations; |
| |
| TypeBinding[] implementations2 = ModuleElementImpl.this.binding.getImplementations(this.service); |
| if (implementations2.length == 0) { |
| return (this.implementations = Collections.emptyList()); |
| } |
| |
| List<TypeElement> list = new ArrayList<>(implementations2.length); |
| Factory factory = _env.getFactory(); |
| for (TypeBinding type: implementations2) { |
| TypeElement element = (TypeElement) factory.newElement(type); |
| list.add(element); |
| } |
| return Collections.unmodifiableList(list); |
| } |
| |
| @Override |
| public TypeElement getService() { |
| return (TypeElement) _env.getFactory().newElement(this.service); |
| } |
| } |
| } |