/********************************************************************** * Copyright (c) 2005-2009 ant4eclipse project team. * * 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: * Nils Hartmann, Daniel Kasmeroglu, Gerd Wuetherich **********************************************************************/ package org.ant4eclipse.ant.jdt.ecj; import java.io.File; import java.util.Map; import java.util.Map.Entry; import org.ant4eclipse.lib.core.Assure; import org.ant4eclipse.lib.core.exception.Ant4EclipseException; import org.ant4eclipse.lib.core.logging.A4ELogging; import org.ant4eclipse.lib.core.util.StringMap; import org.ant4eclipse.lib.core.util.Utilities; import org.ant4eclipse.lib.jdt.ecj.EcjExceptionCodes; import org.apache.tools.ant.taskdefs.Javac; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.util.Util; /** * <p> * The {@link CompilerOptionsProvider} is a utility class that computes compiler options based on ant's javac task as * well as an (optional) project specific and an (optional) global compiler options file. * </p> * * @author Gerd Wütherich (gerd@gerd-wuetherich.de) */ public class CompilerOptionsProvider { /** * This property enables the javadoc parsing in ECJ (same as <tt>-enableJavadoc</tt> on the command line) */ public static final String ENABLE_JAVADOC_SUPPORT = "org.eclipse.jdt.core.compiler.doc.comment.support"; public static final String FORBIDDEN_REFERENCE = "org.eclipse.jdt.core.compiler.problem.forbiddenReference"; /** prefix used for the exported preferences */ private static final String PREFS_INSTANCE = "/instance/"; /** we're only interested in jdt settings */ private static final String PREFS_JDTTYPE = "org.eclipse.jdt.core/"; /** * <p> * Creates the compiler options for the JDT compiler. * </p> * <p> * The compiler options are defined here: * <ul> * <li><a href="http://help.eclipse.org/galileo/topic/org.eclipse.jdt.doc.isv/guide/jdt_api_options.htm">JDT Core * options</a></li> * <li><a href= * "http://help.eclipse.org/galileo/topic/org.eclipse.jdt.doc.user/reference/preferences/java/ref-preferences-compiler.htm" * >Java Compiler Preferences </a></li> * <li><a href="http://help.eclipse.org/galileo/topic/org.eclipse.jdt.doc.user/reference/preferences/java/compiler/ref-preferences-errors-warnings.htm" * >Java Compiler Errors/Warnings Preferences</a></li> * </ul> * </p> * * @param javac * the javac task * @param projectCompilerOptionsFile * the project specific compiler options file. * @param globalCompilerOptionsFile * the global compiler options file. * * @return the map with the merged compiler options. */ @SuppressWarnings("unchecked") public static final StringMap getCompilerOptions(Javac javac, String projectCompilerOptionsFile, String globalCompilerOptionsFile) { Assure.notNull("javac", javac); // get the project options StringMap projectOptions = getFileCompilerOptions(projectCompilerOptionsFile); if (A4ELogging.isTraceingEnabled()) { A4ELogging.trace("Read projectOptions from '%s': '%s'.", projectCompilerOptionsFile, projectOptions); } // get the default options StringMap defaultOptions = getFileCompilerOptions(globalCompilerOptionsFile); if (A4ELogging.isTraceingEnabled()) { A4ELogging.trace("Read defaultOptions from '%s': '%s'.", globalCompilerOptionsFile, defaultOptions); } // get the javac options StringMap javacOptions = getJavacCompilerOptions(javac); if (A4ELogging.isTraceingEnabled()) { A4ELogging.trace("javacOptions: '%s'.", javacOptions); } // merge the map StringMap mergedMap = mergeCompilerOptions(projectOptions, defaultOptions, javacOptions); if (A4ELogging.isTraceingEnabled()) { A4ELogging.trace("mergedMap: '%s'.", mergedMap); } // [AE-201] If not enabled/disabled explicitly, enable ECJ javadoc parsing support // to find references inside javadoc if (!mergedMap.containsKey(ENABLE_JAVADOC_SUPPORT)) { mergedMap.put(ENABLE_JAVADOC_SUPPORT, "enabled"); } // If not enabled/disabled explicitly, set ECJ forbidden reference to 'error if (!mergedMap.containsKey(FORBIDDEN_REFERENCE)) { mergedMap.put(FORBIDDEN_REFERENCE, "error"); } // create result CompilerOptions compilerOptions = new CompilerOptions(mergedMap); // verbose option compilerOptions.verbose = javac.getVerbose(); // debug the compiler options if (A4ELogging.isDebuggingEnabled()) { A4ELogging.debug("Using the following compile options:\n %s", compilerOptions.toString()); } // return the compiler options StringMap result = new StringMap(); result.putAll(compilerOptions.getMap()); return result; } /** * <p> * Returns the compiler options specified in the javac task. * </p> * * @param javac * the javac task * @return the compiler options specified in the javac task. */ @SuppressWarnings("unchecked") private static final StringMap getJavacCompilerOptions(Javac javac) { StringMap result = new StringMap(); /* * set the source option */ if (Utilities.hasText(javac.getSource())) { // get the source String source = javac.getSource(); // set the source if (source.equals("1.3")) { result.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3); } else if (source.equals("1.4")) { result.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4); } else if (source.equals("1.5") || source.equals("5") || source.equals("5.0")) { result.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5); } else if (source.equals("1.6") || source.equals("6") || source.equals("6.0")) { result.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6); } else if (source.equals("1.7") || source.equals("7") || source.equals("7.0")) { result.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_7); } else if (source.equals("1.8") || source.equals("8") || source.equals("8.0")) { result.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_8); } else { throw new Ant4EclipseException(EcjExceptionCodes.UNKNOWN_JAVA_SOURCE_OPTION_EXCEPTION, source); } } /* * set the target option */ if (Utilities.hasText(javac.getTarget())) { // get the target String target = javac.getTarget(); // set the target if (target.equals("1.3")) { result.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_3); result.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3); } else if (target.equals("1.4")) { result.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); result.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4); } else if (target.equals("1.5") || target.equals("5") || target.equals("5.0")) { result.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5); result.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5); } else if (target.equals("1.6") || target.equals("6") || target.equals("6.0")) { result.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); result.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_6); } else if (target.equals("1.7") || target.equals("7") || target.equals("7.0")) { result.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7); result.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_7); } else if (target.equals("1.8") || target.equals("8") || target.equals("8.0")) { result.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8); result.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_8); } else { throw new Ant4EclipseException(EcjExceptionCodes.UNKNOWN_JAVA_TARGET_OPTION_EXCEPTION, target); } } /* * set the debug options */ if (javac.getDebug()) { String debugLevel = javac.getDebugLevel(); if (debugLevel != null) { result.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); result.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.DO_NOT_GENERATE); result.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.DO_NOT_GENERATE); if (debugLevel.length() != 0) { if (debugLevel.indexOf("vars") != -1) { result.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); } if (debugLevel.indexOf("lines") != -1) { result.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE); } if (debugLevel.indexOf("source") != -1) { result.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE); } } } else { result.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); result.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE); result.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE); } } else { result.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); result.put(CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.DO_NOT_GENERATE); result.put(CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.DO_NOT_GENERATE); } /* * Handle the nowarn option. If none, then we generate all warnings. */ if (javac.getNowarn()) { // disable all warnings Map.Entry<String, String>[] entries = result.entrySet().toArray(new Map.Entry[result.size()]); for (Entry<String, String> entrie : entries) { Map.Entry<String, String> entry = entrie; if (entry.getValue().equals(CompilerOptions.WARNING)) { result.put(entry.getKey(), CompilerOptions.IGNORE); } } result.put(CompilerOptions.OPTION_TaskTags, Util.EMPTY_STRING); if (javac.getDeprecation()) { result.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING); result.put(CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode, CompilerOptions.ENABLED); result.put(CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod, CompilerOptions.ENABLED); } } else if (javac.getDeprecation()) { result.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING); result.put(CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode, CompilerOptions.ENABLED); result.put(CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod, CompilerOptions.ENABLED); } else { result.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE); result.put(CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode, CompilerOptions.DISABLED); result.put(CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod, CompilerOptions.DISABLED); } /* * set the encoding option */ if (javac.getEncoding() != null) { result.put(CompilerOptions.OPTION_Encoding, javac.getEncoding()); } // return result return result; } /** * <p> * Returns the compiler options for the given compiler options file. * </p> * <p> * If fileName is null or empty no file is read. * </p> * * @param fileName * the compiler options file. Might be null or empty string * @return the map with the compiler options. */ private static final StringMap getFileCompilerOptions(String fileName) { if (Utilities.hasText(fileName)) { try { File compilerOptionsFile = new File(fileName); if (compilerOptionsFile.exists() && compilerOptionsFile.isFile()) { StringMap compilerOptionsMap = new StringMap(compilerOptionsFile); compilerOptionsMap = convertPreferences(compilerOptionsMap); return compilerOptionsMap; } } catch (Exception e) { A4ELogging.warn("Could not read compiler options file '%s'.\nReason: '%s'", fileName, e.getMessage()); return null; } } return null; } /** * This function alters the supplied options so exported preferences containing jdt compiler settings will be altered * while removing the preference related prefix. * * @param options * The options currently used. Maybe an exported preferences file. Not <code>null</code>. * * @return The altered settings. Not <code>null</code>. */ private static final StringMap convertPreferences(StringMap options) { StringMap result = new StringMap(); for (Map.Entry<String, String> entry : options.entrySet()) { if (entry.getKey().startsWith(PREFS_INSTANCE)) { // this is an exported preferences key String key = entry.getKey().substring(PREFS_INSTANCE.length()); if (key.startsWith(PREFS_JDTTYPE)) { // we've got a jdt related setting, so use it key = key.substring(PREFS_JDTTYPE.length()); result.put(key, entry.getValue()); } } else { // not recognized as a preferences key result.put(entry.getKey(), entry.getValue()); } } return result; } /** * <p> * </p> * * @param options_1 * @param options_2 * @param options_3 * @return */ private static final StringMap mergeCompilerOptions(StringMap options_1, StringMap options_2, StringMap options_3) { StringMap result = new StringMap(); if (options_3 != null) { result.putAll(options_3); } if (options_2 != null) { result.putAll(options_2); } if (options_1 != null) { result.putAll(options_1); } return result; } }