blob: 0da310f22e2a05b6a29eeced306dd3f02be6e6fa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 GK Software AG, 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
*
* This is an implementation of an early-draft specification developed under the Java
* Community Process (JCP) and is made available for testing and evaluation purposes
* only. The code is not compatible with any specification of the JCP.
*
* Contributors:
* Stephan Herrmann - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaModelStatusConstants;
import org.eclipse.jdt.core.IModuleDescription;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.env.IModuleAwareNameEnvironment;
import org.eclipse.jdt.internal.compiler.env.IUpdatableModule;
import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.UpdateKind;
import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.UpdatesByKind;
import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
import org.eclipse.jdt.internal.core.util.Util;
/**
* An instance of this class collects <code>add-exports</code> and <code>add-reads</code> options from
* a project's class path entries, and performs the corresponding updates when requested by the compiler.
* <p>For <code>patch-module</code> and <code>limit-modules</code> see
* org.eclipse.jdt.internal.core.builder.ModuleEntryProcessor.</p>
*/
public class ModuleUpdater {
private JavaProject javaProoject;
private Map<String,UpdatesByKind> moduleUpdates = new HashMap<>();
public ModuleUpdater(JavaProject javaProject) {
this.javaProoject = javaProject;
}
/**
* Detects any ADD_EXPORTS or ADD_READS classpath attributes, parses the value,
* and collects the resulting module updates.
* @param entry a classpath entry of the current project.
* @throws JavaModelException
*/
public void computeModuleUpdates(IClasspathEntry entry) throws JavaModelException {
for (IClasspathAttribute attribute : entry.getExtraAttributes()) {
String attributeName = attribute.getName();
String values = attribute.getValue(); // the attributes considered here may have multiple values separated by ':'
if (attributeName.equals(IClasspathAttribute.ADD_EXPORTS)) {
for (String value : values.split(":")) { // format: <source-module>/<package>=<target-module>(,<target-module>)* //$NON-NLS-1$
int slash = value.indexOf('/');
int equals = value.indexOf('=');
if (slash != -1 && equals != -1) {
String modName = value.substring(0, slash);
char[] packName = value.substring(slash+1, equals).toCharArray();
char[][] targets = CharOperation.splitOn(',', value.substring(equals+1).toCharArray());
addModuleUpdate(modName, m -> m.addExports(packName, targets), UpdateKind.PACKAGE);
} else {
Util.log(IStatus.WARNING, "Invalid argument to add-exports: "+value); //$NON-NLS-1$
}
}
} else if (attributeName.equals(IClasspathAttribute.ADD_READS)) {
for (String value : values.split(":")) { // format: <source-module>=<target-module> //$NON-NLS-1$
int equals = value.indexOf('=');
if (equals != -1) {
String srcMod = value.substring(0, equals);
char[] targetMod = value.substring(equals+1).toCharArray();
addModuleUpdate(srcMod, m -> m.addReads(targetMod), UpdateKind.MODULE);
} else {
Util.log(IStatus.WARNING, "Invalid argument to add-reads: "+value); //$NON-NLS-1$
}
}
} else if (attributeName.equals(IClasspathAttribute.MODULE_MAIN_CLASS)) {
IModuleDescription module = this.javaProoject.getModuleDescription();
if (module == null)
throw new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST));
addModuleUpdate(module.getElementName(), m -> m.setMainClassName(values.toCharArray()), UpdateKind.MODULE);
}
}
}
public void addModuleUpdate(String moduleName, Consumer<IUpdatableModule> update, UpdateKind kind) {
UpdatesByKind updates = this.moduleUpdates.get(moduleName);
if (updates == null) {
this.moduleUpdates.put(moduleName, updates = new UpdatesByKind());
}
updates.getList(kind, true).add(update);
}
/**
* @see IModuleAwareNameEnvironment#applyModuleUpdates(IUpdatableModule, UpdateKind)
*/
public void applyModuleUpdates(IUpdatableModule compilerModule, UpdateKind kind) {
char[] name = compilerModule.name();
if (name != ModuleBinding.UNNAMED) { // can't update the unnamed module
UpdatesByKind updates = this.moduleUpdates.get(String.valueOf(name));
if (updates != null) {
for (Consumer<IUpdatableModule> update : updates.getList(kind, false))
update.accept(compilerModule);
}
}
}
}