blob: 71c3448a5bb49fb0ed2a07d22a13512dcfb8f596 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 - 2018 BEA Systems, Inc and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* wharley@bea.com - initial API and implementation
* Fabian Steeg <steeg@hbz-nrw.de> - Pass automatically provided options to Java 6 processors - https://bugs.eclipse.org/341298
*******************************************************************************/
package org.eclipse.jdt.internal.apt.pluggable.core.dispatch;
import static java.util.stream.Collectors.partitioningBy;
import static java.util.stream.Collectors.toMap;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.lang.model.element.Element;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.apt.core.env.Phase;
import org.eclipse.jdt.apt.core.internal.AptCompilationParticipant;
import org.eclipse.jdt.apt.core.internal.AptPlugin;
import org.eclipse.jdt.apt.core.internal.AptProject;
import org.eclipse.jdt.apt.core.internal.generatedfile.FileGenerationResult;
import org.eclipse.jdt.apt.core.util.AptConfig;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl;
import org.eclipse.jdt.internal.compiler.Compiler;
import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
import org.eclipse.jdt.internal.compiler.apt.model.IElementInfo;
/**
* Implementation of ProcessingEnvironment when running inside IDE.
* The lifetime of this object corresponds to the lifetime of the
* {@link IdeAnnotationProcessorManager} that owns it.
* @see org.eclipse.jdt.internal.compiler.apt.dispatch.BatchProcessingEnvImpl
*/
public abstract class IdeProcessingEnvImpl extends BaseProcessingEnvImpl {
private final IdeAnnotationProcessorManager _dispatchManager;
private final IJavaProject _javaProject;
protected final AptProject _aptProject;
private final boolean _isTestCode;
public IdeProcessingEnvImpl(IdeAnnotationProcessorManager dispatchManager,
IJavaProject jproject, Compiler compiler, boolean isTestCode)
{
_dispatchManager = dispatchManager;
_javaProject = jproject;
_compiler = compiler;
this._isTestCode = isTestCode;
_aptProject = AptPlugin.getAptProject(jproject);
_filer = new IdeFilerImpl(_dispatchManager, this);
_messager = new IdeMessagerImpl(_dispatchManager, this);
}
/* (non-Javadoc)
* @see javax.annotation.processing.ProcessingEnvironment#getLocale()
*/
@Override
public Locale getLocale() {
return Locale.getDefault();
}
@Override
public Map<String, String> getOptions() {
if (null == _processorOptions) {
// Java 5 processor options include items on the command line such as -s,
// -classpath, etc., but Java 6 options only include the options specified
// with -A, which will have been parsed into key/value pairs with no dash.
Map<String, String> allOptions = AptConfig.getProcessorOptions(_javaProject, isTestCode());
// But we make them available as variables in processor options configured by users
// (e.g. %classpath% in an option value is replaced with the value of -classpath):
Map<Boolean, List<Entry<String, String>>> isCommandLineOption = allOptions.entrySet().stream()
.collect(partitioningBy(option -> option.getKey().startsWith("-")));
Map<String, String> commandLineOptions = isCommandLineOption.get(true).stream()
.collect(toMap(e -> e.getKey().substring(1), Entry::getValue));
Map<String, String> processorOptions = isCommandLineOption.get(false).stream()
.collect(toMap(Entry::getKey, replacePlaceholdersUsing(commandLineOptions)));
processorOptions.put("phase", getPhase().toString()); //$NON-NLS-1$
_processorOptions = Collections.unmodifiableMap(processorOptions);
}
return _processorOptions;
}
private Function<Entry<String, String>, String> replacePlaceholdersUsing(Map<String, String> commandLineOptions) {
return option -> {
String variable, replacement, optionValue = option.getValue();
Matcher placeholder = Pattern.compile("%([^%]+)%").matcher(optionValue);
if (placeholder.find() && (variable = placeholder.group(1)) != null
&& (replacement = commandLineOptions.get(variable)) != null) {
optionValue = optionValue.replace("%" + variable + "%", replacement);
}
return optionValue;
};
}
public AptProject getAptProject() {
return _aptProject;
}
public IJavaProject getJavaProject() {
return _javaProject;
}
public IProject getProject() {
return _javaProject.getProject();
}
/**
* @return whether this environment supports building or reconciling.
*/
public abstract Phase getPhase();
/**
* Get the IFile that contains or represents the specified source element.
* If the element is a package, get the IFile corresponding to its
* package-info.java file. If the element is a top-level type, get the
* IFile corresponding to its type. If the element is a nested element
* of some sort (nested type, method, etc.) then get the IFile corresponding
* to the containing top-level type.
* If the element is not a source type at all, then return null.
* @param elem
* @return may be null
*/
public IFile getEnclosingIFile(Element elem) {
// if this cast fails it could be that a non-Eclipse element got passed in somehow.
IElementInfo impl = (IElementInfo)elem;
String name = impl.getFileName();
if (name == null) {
return null;
}
// The name will be workspace-relative, e.g., /project/src/packages/File.java.
IFile file = _javaProject.getProject().getParent().getFile(new Path(name));
return file;
}
/**
* Inform the environment that a new Java file has been generated.
* @param result must be non-null
*/
public void addNewUnit(FileGenerationResult result) {
AptCompilationParticipant.getInstance().addJava6GeneratedFile(result.getFile());
addNewUnit(_dispatchManager.findCompilationUnit(result.getFile()));
}
/**
* Inform the environment that a new non-Java file has been generated.
* This file will not be submitted to a subsequent round of processing in
* the current build, even if the file happens to be in a source location
* and named with a Java-like name. However, its dependencies will be
* tracked in the same manner as Java files, e.g., it will be deleted
* if changes in source cause it to no longer be generated.
* @param file must be non-null
*/
public void addNewResource(IFile file) {
AptCompilationParticipant.getInstance().addJava6GeneratedFile(file);
}
public boolean currentProcessorSupportsRTTG()
{
// Reconcile time type generation is not currently enabled for Java 6 processors
return false;
}
public boolean isTestCode() {
return _isTestCode;
}
public Compiler getCompiler() {
return _compiler;
}
}