/*******************************************************************************
* Copyright (c) 2009, 2011 Alena Laskavaia
* 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:
* Alena Laskavaia - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.codan.internal.core;
import java.util.Map;
import org.eclipse.cdt.codan.core.CodanCorePlugin;
import org.eclipse.cdt.codan.core.Messages;
import org.eclipse.cdt.codan.core.model.CheckerLaunchMode;
import org.eclipse.cdt.codan.core.model.Checkers;
import org.eclipse.cdt.codan.core.model.IChecker;
import org.eclipse.cdt.codan.core.model.ICheckerInvocationContext;
import org.eclipse.cdt.codan.core.model.ICodanBuilder;
import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
/**
* Implementation of {@link ICodanBuilder}
*/
public class CodanBuilder extends IncrementalProjectBuilder implements ICodanBuilder {
/**
* Codan builder id
*/
public static final String BUILDER_ID = "org.eclipse.cdt.codan.core.codanBuilder"; //$NON-NLS-1$
private class CodanDeltaVisitor implements IResourceDeltaVisitor {
private IProgressMonitor monitor;
/**
* @param monitor
*/
public CodanDeltaVisitor(IProgressMonitor monitor) {
this.monitor = monitor;
}
public boolean visit(IResourceDelta delta) throws CoreException {
IResource resource = delta.getResource();
switch (delta.getKind()) {
case IResourceDelta.ADDED:
// handle added resource
processResourceDelta(resource, monitor);
break;
case IResourceDelta.REMOVED:
// handle removed resource
break;
case IResourceDelta.CHANGED:
// handle changed resource
processResourceDelta(resource, monitor);
break;
}
// return true to continue visiting children.
return true;
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.internal.events.InternalBuilder#build(int,
* java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
*/
@SuppressWarnings("rawtypes")
@Override
protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException {
if (kind == FULL_BUILD) {
fullBuild(monitor);
} else {
IResourceDelta delta = getDelta(getProject());
if (delta == null) {
fullBuild(monitor);
} else {
incrementalBuild(delta, monitor);
}
}
return null;
}
public void processResource(IResource resource, IProgressMonitor monitor) {
processResource(resource, monitor, null, CheckerLaunchMode.RUN_ON_FULL_BUILD);
}
/**
* Run code analysis on given resource in a given mode
*
* @param resource - resource to process
* @param monitor - progress monitor
* @param mode - launch mode, @see {@link CheckerLaunchMode}
* @since 2.0
*/
public void processResource(IResource resource, IProgressMonitor monitor, CheckerLaunchMode mode) {
processResource(resource, monitor, null, mode);
}
private void processResourceDelta(IResource resource, IProgressMonitor monitor) {
processResource(resource, monitor, CheckerLaunchMode.RUN_ON_INC_BUILD);
}
protected void processResource(IResource resource, IProgressMonitor monitor, Object model, CheckerLaunchMode checkerLaunchMode) {
CheckersRegistry chegistry = CheckersRegistry.getInstance();
int checkers = chegistry.getCheckersSize();
int memsize = 0;
if (resource instanceof IContainer) {
try {
IResource[] members = ((IContainer) resource).members();
memsize = members.length;
} catch (CoreException e) {
CodanCorePlugin.log(e);
}
}
int tick = 1000;
// System.err.println("processing " + resource);
monitor.beginTask(Messages.CodanBuilder_Code_Analysis_On + resource, checkers + memsize * tick);
try {
CheckersTimeStats.getInstance().checkerStart(CheckersTimeStats.ALL);
ICheckerInvocationContext context = new CheckerInvocationContext(resource);
try {
for (IChecker checker : chegistry) {
try {
if (monitor.isCanceled())
return;
if (doesCheckerSupportLaunchMode(checker, checkerLaunchMode)
&& checker.enabledInContext(resource)
&& chegistry.isCheckerEnabledForLaunchMode(checker, resource, checkerLaunchMode)) {
synchronized (checker) {
try {
checker.before(resource);
if (chegistry.isCheckerEnabled(checker, resource)) {
try {
CheckersTimeStats.getInstance().checkerStart(checker.getClass().getName());
if (checkerLaunchMode == CheckerLaunchMode.RUN_AS_YOU_TYPE) {
((IRunnableInEditorChecker) checker).processModel(model, context);
} else {
checker.processResource(resource, context);
}
} finally {
CheckersTimeStats.getInstance().checkerStop(checker.getClass().getName());
}
}
} finally {
checker.after(resource);
}
}
}
monitor.worked(1);
} catch (OperationCanceledException e) {
return;
} catch (Throwable e) {
CodanCorePlugin.log(e);
}
}
} finally {
context.dispose();
CheckersTimeStats.getInstance().checkerStop(CheckersTimeStats.ALL);
//CheckersTimeStats.getInstance().printStats();
}
if (resource instanceof IContainer
&& (checkerLaunchMode == CheckerLaunchMode.RUN_ON_FULL_BUILD || checkerLaunchMode == CheckerLaunchMode.RUN_ON_DEMAND)) {
try {
IResource[] members = ((IContainer) resource).members();
for (int i = 0; i < members.length; i++) {
if (monitor.isCanceled())
return;
IResource member = members[i];
processResource(member, new SubProgressMonitor(monitor, tick));
}
} catch (CoreException e) {
CodanCorePlugin.log(e);
}
}
} finally {
monitor.done();
}
}
private boolean doesCheckerSupportLaunchMode(IChecker checker, CheckerLaunchMode mode) {
if (mode == CheckerLaunchMode.RUN_AS_YOU_TYPE)
return Checkers.canCheckerRunAsYouType(checker);
return true;
}
protected void fullBuild(final IProgressMonitor monitor) throws CoreException {
processResource(getProject(), monitor);
}
protected void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) throws CoreException {
// the visitor does the work.
delta.accept(new CodanDeltaVisitor(monitor));
}
/**
* Run all checkers that support "check as you type" mode
*
* @param model - model of given resource such as ast
* @param resource - resource to process
* @param monitor - progress monitor
*/
public void runInEditor(Object model, IResource resource, IProgressMonitor monitor) {
if (model == null)
return;
processResource(resource, monitor, model, CheckerLaunchMode.RUN_AS_YOU_TYPE);
}
}