blob: 57ce070e92b37223ef97850635cdd7f2af7511c6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2011 QNX Software Systems 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:
* QNX Software Systems - Initial API and implementation
* James Blackburn (Broadcom Corp.)
*******************************************************************************/
package org.eclipse.cdt.make.core;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.ICDescriptor;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.IIncludeEntry;
import org.eclipse.cdt.core.model.IMacroEntry;
import org.eclipse.cdt.core.model.IPathEntry;
import org.eclipse.cdt.core.parser.IScannerInfo;
import org.eclipse.cdt.core.resources.ScannerProvider;
import org.eclipse.cdt.core.settings.model.ICStorageElement;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.QualifiedName;
import org.w3c.dom.Element;
/**
* @deprecated @author DInglis
*
* @noextend This class is not intended to be subclassed by clients.
* @noinstantiate This class is not intended to be instantiated by clients.
*/
@Deprecated
public class MakeScannerProvider extends ScannerProvider {
// This is the id of the IScannerInfoProvider extension point entry
public static final String INTERFACE_IDENTITY = MakeCorePlugin.getUniqueIdentifier() + ".MakeScannerProvider"; //$NON-NLS-1$
// Name we will use to store build property with the project
private static final QualifiedName scannerInfoProperty = new QualifiedName(MakeCorePlugin.getUniqueIdentifier(),
"makeBuildInfo"); //$NON-NLS-1$
static final String CDESCRIPTOR_ID = MakeCorePlugin.getUniqueIdentifier() + ".makeScannerInfo"; //$NON-NLS-1$
public static final String INCLUDE_PATH = "includePath"; //$NON-NLS-1$
public static final String PATH = "path"; //$NON-NLS-1$
public static final String DEFINED_SYMBOL = "definedSymbol"; //$NON-NLS-1$
public static final String SYMBOL = "symbol"; //$NON-NLS-1$
private static MakeScannerProvider defaultProvider;
public static MakeScannerProvider getDefault() {
if (defaultProvider == null) {
defaultProvider = new MakeScannerProvider();
}
return defaultProvider;
}
public MakeScannerInfo getMakeScannerInfo(IProject project, boolean cacheInfo) throws CoreException {
MakeScannerInfo scannerInfo = null;
// See if there's already one associated with the resource for this
// session
scannerInfo = (MakeScannerInfo) project.getSessionProperty(scannerInfoProperty);
// Try to load one for the project
if (scannerInfo == null) {
scannerInfo = loadScannerInfo(project);
} else {
return scannerInfo;
}
// There is nothing persisted for the session, or saved in a file so
// create a build info object
if (scannerInfo != null && cacheInfo == true) {
project.setSessionProperty(scannerInfoProperty, scannerInfo);
}
// migrate to new C Path Entries
if (scannerInfo != null) {
updateScannerInfo(scannerInfo);
}
ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project);
descriptor.remove(CCorePlugin.BUILD_SCANNER_INFO_UNIQ_ID); // remove scanner provider which will fallback to default cpath
// provider.
return scannerInfo;
}
@Override
public IScannerInfo getScannerInformation(IResource resource) {
try {
getMakeScannerInfo(resource.getProject(), true);
} catch (CoreException e) {
}
return super.getScannerInformation(resource);
}
/*
* Loads the build file and parses the nodes for build information. The information is then associated with the resource for the
* duration of the session.
*/
private MakeScannerInfo loadScannerInfo(IProject project) throws CoreException {
ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project);
ICStorageElement storage = descriptor.getProjectStorageElement(CDESCRIPTOR_ID);
ArrayList<String> includes = new ArrayList<>();
ArrayList<String> symbols = new ArrayList<>();
for (ICStorageElement child : storage.getChildren()) {
if (child.getName().equals(INCLUDE_PATH)) {
// Add the path to the property list
includes.add(((Element) child).getAttribute(PATH));
} else if (child.getName().equals(DEFINED_SYMBOL)) {
// Add the symbol to the symbol list
symbols.add(((Element) child).getAttribute(SYMBOL));
}
}
MakeScannerInfo info = new MakeScannerInfo(project);
info.setIncludePaths(includes.toArray(new String[includes.size()]));
info.setPreprocessorSymbols(symbols.toArray(new String[symbols.size()]));
return info;
}
static void migrateToCPathEntries(MakeScannerInfo info) throws CoreException {
Map<String, String> symbols = info.getDefinedSymbols();
String[] includes = info.getIncludePaths();
ICProject cProject = CoreModel.getDefault().create(info.getProject());
IPathEntry[] entries = cProject.getRawPathEntries();
List<IPathEntry> cPaths = new ArrayList<>(Arrays.asList(entries));
Iterator<IPathEntry> cpIter = cPaths.iterator();
while (cpIter.hasNext()) {
int kind = cpIter.next().getEntryKind();
if (kind == IPathEntry.CDT_INCLUDE || kind == IPathEntry.CDT_MACRO) {
cpIter.remove();
}
}
for (int i = 0; i < includes.length; i++) {
IIncludeEntry include = CoreModel.newIncludeEntry(info.getProject().getFullPath(), null,
new Path(includes[i]), true);
if (!cPaths.contains(include)) {
cPaths.add(include);
}
}
Iterator<Entry<String, String>> syms = symbols.entrySet().iterator();
while (syms.hasNext()) {
Entry<String, String> entry = syms.next();
IMacroEntry sym = CoreModel.newMacroEntry(info.getProject().getFullPath(), entry.getKey(),
entry.getValue());
if (!cPaths.contains(sym)) {
cPaths.add(sym);
}
}
cProject.setRawPathEntries(cPaths.toArray(new IPathEntry[cPaths.size()]), null);
}
/**
* The build model manager for standard builds only caches the build information for a resource on a per-session basis. This
* method allows clients of the build model manager to programmatically remove the association between the resource and the
* information while the reource is still open or in the workspace. The Eclipse core will take care of removing it if a resource
* is closed or deleted.
*/
public static void removeScannerInfo(IResource resource) {
try {
resource.getProject().setSessionProperty(scannerInfoProperty, null);
} catch (CoreException e) {
}
}
/**
* Persists build-specific information in the build file. Build information for standard make projects consists of preprocessor
* symbols and includes paths. Other project-related information is stored in the persistent properties of the project.
*/
public static void updateScannerInfo(final MakeScannerInfo scannerInfo) throws CoreException {
ResourcesPlugin.getWorkspace().run(new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
IProject project = scannerInfo.getProject();
ICDescriptor descriptor = CCorePlugin.getDefault().getCProjectDescription(project);
ICStorageElement rootElement = descriptor.getProjectStorageElement(CDESCRIPTOR_ID);
// Clear out all current children
// Note: Probably would be a better idea to merge in the data
rootElement.clear();
descriptor.saveProjectData();
migrateToCPathEntries(scannerInfo);
}
}, null);
}
}