blob: e297f4e102a9daa2ddb0a5bc4715201cdb6f5e6d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2013 Andrew Gvozdev 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:
* Andrew Gvozdev - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.internal.language.settings.providers;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.AbstractExecutableExtensionBase;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
import org.eclipse.cdt.core.cdtvariables.ICdtVariableManager;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsBroadcastingProvider;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsStorage;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICFileDescription;
import org.eclipse.cdt.core.settings.model.ICFolderDescription;
import org.eclipse.cdt.core.settings.model.ICLanguageSetting;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.cdt.core.settings.model.ICPathEntry;
import org.eclipse.cdt.core.settings.model.ICResourceDescription;
import org.eclipse.cdt.core.settings.model.ICSettingBase;
import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
/**
* Implementation of language settings provider for CDT Managed Build System.
*/
public class MBSLanguageSettingsProvider extends AbstractExecutableExtensionBase
implements ILanguageSettingsBroadcastingProvider {
@Override
public List<ICLanguageSettingEntry> getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc,
String languageId) {
if (cfgDescription == null || rc == null) {
return null;
}
IPath projectPath = rc.getProjectRelativePath();
ICLanguageSetting[] languageSettings = null;
if (rc instanceof IFile) {
ICLanguageSetting ls = cfgDescription.getLanguageSettingForFile(projectPath, true);
if (ls != null) {
languageSettings = new ICLanguageSetting[] { ls };
} else {
return getSettingEntries(cfgDescription, rc.getParent(), languageId);
}
} else {
ICResourceDescription rcDescription = cfgDescription.getResourceDescription(projectPath, false);
languageSettings = getLanguageSettings(rcDescription);
}
// this list is allowed to contain duplicate entries, cannot be LinkedHashSet
List<ICLanguageSettingEntry> list = new ArrayList<>();
if (languageSettings != null) {
for (ICLanguageSetting langSetting : languageSettings) {
if (langSetting != null) {
String id = langSetting.getLanguageId();
if (id == languageId || (id != null && id.equals(languageId))) {
int kindsBits = langSetting.getSupportedEntryKinds();
for (int kind = 1; kind <= kindsBits; kind <<= 1) {
if ((kindsBits & kind) != 0) {
List<ICLanguageSettingEntry> additions = langSetting.getSettingEntriesList(kind);
for (ICLanguageSettingEntry entry : additions) {
if (entry instanceof ICPathEntry) {
// have to use getName() rather than getLocation() and not use IPath operations to avoid collapsing ".."
String pathStr = ((ICPathEntry) entry).getName();
if (!new Path(pathStr).isAbsolute()) {
// We need to add project-rooted entry for relative path as MBS counts it this way in some UI
// The relative entry below also should be added for indexer to resolve from source file locations
ICdtVariableManager varManager = CCorePlugin.getDefault()
.getCdtVariableManager();
try {
// Substitute build/environment variables
String location = varManager.resolveValue(pathStr, "", null, //$NON-NLS-1$
cfgDescription);
if (!new Path(location).isAbsolute()) {
IStringVariableManager mngr = VariablesPlugin.getDefault()
.getStringVariableManager();
String projectRootedPath = mngr.generateVariableExpression(
"workspace_loc", rc.getProject().getName()) + Path.SEPARATOR //$NON-NLS-1$
+ pathStr;
// clear "RESOLVED" flag
int flags = entry.getFlags() & ~(ICSettingEntry.RESOLVED
| ICSettingEntry.VALUE_WORKSPACE_PATH);
ICLanguageSettingEntry projectRootedEntry = (ICLanguageSettingEntry) CDataUtil
.createEntry(kind, projectRootedPath, projectRootedPath,
null, flags);
if (!list.contains(projectRootedEntry)) {
list.add(projectRootedEntry);
}
}
} catch (CdtVariableException e) {
// Swallow exceptions but also log them
ManagedBuilderCorePlugin.log(e);
}
}
}
if (!list.contains(entry)) {
list.add(entry);
}
}
}
}
}
}
}
}
return LanguageSettingsStorage.getPooledList(list);
}
/**
* Get language settings for resource description.
*/
private ICLanguageSetting[] getLanguageSettings(ICResourceDescription rcDescription) {
ICLanguageSetting[] array = null;
switch (rcDescription.getType()) {
case ICSettingBase.SETTING_PROJECT:
case ICSettingBase.SETTING_CONFIGURATION:
case ICSettingBase.SETTING_FOLDER:
ICFolderDescription foDes = (ICFolderDescription) rcDescription;
array = foDes.getLanguageSettings();
break;
case ICSettingBase.SETTING_FILE:
ICFileDescription fiDes = (ICFileDescription) rcDescription;
ICLanguageSetting ls = fiDes.getLanguageSetting();
if (ls != null) {
array = new ICLanguageSetting[] { ls };
}
}
if (array == null) {
array = new ICLanguageSetting[0];
}
return array;
}
@Override
public LanguageSettingsStorage copyStorage() {
class PretendStorage extends LanguageSettingsStorage {
@Override
public boolean isEmpty() {
return false;
}
@Override
public LanguageSettingsStorage clone() throws CloneNotSupportedException {
return this;
}
@Override
public boolean equals(Object obj) {
// Note that this always triggers change event even if nothing changed in MBS
return false;
}
}
return new PretendStorage();
}
}