/*******************************************************************************
* Copyright (c) 2000, 2016 QNX Software Systems 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
*
* Contributors:
* QNX Software Systems - Initial API and implementation
* IBM Corporation
* James Blackburn (Broadcom Corp.)
*******************************************************************************/
package org.eclipse.cdt.core.resources;
import java.net.URI;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CCorePreferenceConstants;
import org.eclipse.cdt.core.IMarkerGenerator;
import org.eclipse.cdt.core.ProblemMarkerInfo;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICModelMarker;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.osgi.util.NLS;
public abstract class ACBuilder extends IncrementalProjectBuilder implements IMarkerGenerator {
private static final String CONTENTS_CONFIGURATION_IDS = "org.eclipse.cdt.make.core.configurationIds"; //$NON-NLS-1$
private static final IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID);
/** @since 5.2 */ // set to true to print build events on the console in debug mode
protected static final boolean DEBUG_EVENTS = false;
private IProject currentProject;
/**
* Constructor for ACBuilder
*/
public ACBuilder() {
super();
}
/**
* Set the current project that this builder is running.
*
* @since 5.11
*/
protected void setCurrentProject(IProject project) {
this.currentProject = project;
}
/**
* Returns the current project that this builder is running.
*
* @return the project
* @since 5.11
*/
protected IProject getCurrentProject() {
if (currentProject != null) {
return currentProject;
}
return super.getProject();
}
@Override
public void addMarker(IResource file, int lineNumber, String errorDesc, int severity, String errorVar) {
ProblemMarkerInfo problemMarkerInfo = new ProblemMarkerInfo(file, lineNumber, errorDesc, severity, errorVar, null);
addMarker(problemMarkerInfo);
}
/**
* Callback from Output Parser
*/
@Override
public void addMarker(ProblemMarkerInfo problemMarkerInfo) {
try {
IProject project = getCurrentProject();
IResource markerResource = problemMarkerInfo.file;
if (markerResource == null) {
markerResource = project;
}
String externalLocation = null;
if (problemMarkerInfo.externalPath != null && ! problemMarkerInfo.externalPath.isEmpty()) {
externalLocation = problemMarkerInfo.externalPath.toOSString();
}
// Try to find matching markers and don't put in duplicates
IMarker[] markers = markerResource.findMarkers(ICModelMarker.C_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_ONE);
for (IMarker m : markers) {
int line = m.getAttribute(IMarker.LINE_NUMBER, -1);
int sev = m.getAttribute(IMarker.SEVERITY, -1);
String msg = (String) m.getAttribute(IMarker.MESSAGE);
if (line == problemMarkerInfo.lineNumber && sev == mapMarkerSeverity(problemMarkerInfo.severity) && msg.equals(problemMarkerInfo.description)) {
String extloc = (String) m.getAttribute(ICModelMarker.C_MODEL_MARKER_EXTERNAL_LOCATION);
if (extloc == externalLocation || (extloc != null && extloc.equals(externalLocation))) {
if (project == null || project.equals(markerResource.getProject())) {
return;
}
String source = (String) m.getAttribute(IMarker.SOURCE_ID);
if (project.getName().equals(source)) {
return;
}
}
}
}
String type = problemMarkerInfo.getType();
if (type == null) {
type = ICModelMarker.C_MODEL_PROBLEM_MARKER;
}
IMarker marker = markerResource.createMarker(type);
marker.setAttribute(IMarker.MESSAGE, problemMarkerInfo.description);
marker.setAttribute(IMarker.SEVERITY, mapMarkerSeverity(problemMarkerInfo.severity));
marker.setAttribute(IMarker.LINE_NUMBER, problemMarkerInfo.lineNumber);
marker.setAttribute(IMarker.CHAR_START, problemMarkerInfo.startChar);
marker.setAttribute(IMarker.CHAR_END, problemMarkerInfo.endChar);
if (problemMarkerInfo.variableName != null) {
marker.setAttribute(ICModelMarker.C_MODEL_MARKER_VARIABLE, problemMarkerInfo.variableName);
}
if (externalLocation != null) {
URI uri = URIUtil.toURI(externalLocation);
if (uri.getScheme()!=null) {
marker.setAttribute(ICModelMarker.C_MODEL_MARKER_EXTERNAL_LOCATION, externalLocation);
String locationText = NLS.bind(CCorePlugin.getResourceString("ACBuilder.ProblemsView.Location"), //$NON-NLS-1$
problemMarkerInfo.lineNumber, externalLocation);
marker.setAttribute(IMarker.LOCATION, locationText);
}
} else if (problemMarkerInfo.lineNumber==0){
marker.setAttribute(IMarker.LOCATION, " "); //$NON-NLS-1$
}
// Set source attribute only if the marker is being set to a file from different project
if (project != null && !project.equals(markerResource.getProject())) {
marker.setAttribute(IMarker.SOURCE_ID, project.getName());
}
// Add all other client defined attributes.
Map<String, String> attributes = problemMarkerInfo.getAttributes();
if (attributes != null){
for (Entry<String, String> entry : attributes.entrySet()) {
marker.setAttribute(entry.getKey(), entry.getValue());
}
}
}
catch (CoreException e) {
CCorePlugin.log(e.getStatus());
}
}
private int mapMarkerSeverity(int severity) {
switch (severity) {
case SEVERITY_ERROR_BUILD :
case SEVERITY_ERROR_RESOURCE :
return IMarker.SEVERITY_ERROR;
case SEVERITY_INFO :
return IMarker.SEVERITY_INFO;
case SEVERITY_WARNING :
return IMarker.SEVERITY_WARNING;
}
return IMarker.SEVERITY_ERROR;
}
public static boolean needAllConfigBuild() {
return prefs.getBoolean(CCorePreferenceConstants.PREF_BUILD_ALL_CONFIGS, false);
}
public static void setAllConfigBuild(boolean enable) {
prefs.putBoolean(CCorePreferenceConstants.PREF_BUILD_ALL_CONFIGS, enable);
}
/**
* Preference for building configurations only when there are resource changes within Eclipse or
* when there are changes in its references.
* @return true if configurations will be build when project resource changes within Eclipse
* false otherwise
* @since 5.1
*/
public static boolean buildConfigResourceChanges() {
//bug 219337
return prefs.getBoolean(CCorePreferenceConstants.PREF_BUILD_CONFIGS_RESOURCE_CHANGES, false);
}
/**
* Preference for building configurations only when there are resource changes within Eclipse or
* when there are changes in its references.
* @param enable
* @since 5.1
*/
public static void setBuildConfigResourceChanges(boolean enable) {
prefs.putBoolean(CCorePreferenceConstants.PREF_BUILD_CONFIGS_RESOURCE_CHANGES, enable);
}
@SuppressWarnings("nls")
private static String kindToString(int kind) {
return (kind==IncrementalProjectBuilder.AUTO_BUILD ? "AUTO_BUILD"
: kind==IncrementalProjectBuilder.CLEAN_BUILD ? "CLEAN_BUILD"
: kind==IncrementalProjectBuilder.FULL_BUILD ? "FULL_BUILD"
: kind==IncrementalProjectBuilder.INCREMENTAL_BUILD ? "INCREMENTAL_BUILD"
: "[unknown kind]")+"="+kind;
}
@SuppressWarnings("nls")
private String cfgIdToNames(String strIds) {
IProject project = getCurrentProject();
ICProjectDescription prjDesc = CoreModel.getDefault().getProjectDescription(project, false);
if (prjDesc == null) {
return strIds;
}
if (strIds == null) {
return "Active=" + prjDesc.getActiveConfiguration().getName();
}
String[] ids = strIds.split("\\|");
String names="";
for (String id : ids) {
ICConfigurationDescription cfgDesc = prjDesc.getConfigurationById(id);
String name;
if (cfgDesc != null) {
name = cfgDesc.getName();
} else {
name = id;
}
if (names.length() >0 ) {
names=names+",";
}
names = names + name;
}
if (names.isEmpty()) {
return strIds;
}
return names;
}
/**
* For debugging purpose only. Prints events on the debug console.
*
* @since 5.2
*/
@SuppressWarnings("nls")
protected void printEvent(int kind, Map<String, String> args) {
if (DEBUG_EVENTS) {
String ids = args!=null ? args.get(CONTENTS_CONFIGURATION_IDS) : null;
System.out.println("t"+Thread.currentThread().getId()+": "
+ kindToString(kind)
+ ", " + getCurrentProject()
+ "[" + cfgIdToNames(ids) +"]"
+ ", " + this.getClass().getSimpleName()
);
}
}
@Override
// This method is overridden with no purpose but to track events in debug mode
protected void clean(IProgressMonitor monitor) throws CoreException {
super.clean(monitor);
if (DEBUG_EVENTS) {
printEvent(IncrementalProjectBuilder.CLEAN_BUILD, null);
}
}
/**
* Default ACBuilder shouldn't require locking the workspace during a CDT Project build.
*
* Note this may have a detrimental effect on #getDelta(). Derived builders which rely
* on #getDelta(...) being accurate should return a WorkspaceRoot scheduling rule.
* @since 5.2
*/
@Override
@SuppressWarnings("rawtypes")
public ISchedulingRule getRule(int trigger, Map args) {
return null;
}
}