package com.mobilesorcery.sdk.molint;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICContainer;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICElementVisitor;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import com.mobilesorcery.sdk.core.CoreMoSyncPlugin;
import com.mobilesorcery.sdk.core.IBuildVariant;
import com.mobilesorcery.sdk.core.MoSyncBuilder;
import com.mobilesorcery.sdk.core.MoSyncProject;
public abstract class CPPASTMolintRule extends AbstractMolintRule {
private class AnalyzeVisitor implements ICElementVisitor {
private IProgressMonitor monitor;
private CPPASTMolintRule rule;
private IIndex index;
private List<IMarker> result;
private IBuildVariant variant;
public AnalyzeVisitor(IProgressMonitor monitor, IIndex index,
IBuildVariant variant, CPPASTMolintRule rule) {
this.monitor = monitor;
this.index = index;
this.variant = variant;
this.rule = rule;
result = new ArrayList<IMarker>();
}
@Override
public boolean visit(ICElement element) throws CoreException {
if (element instanceof ICContainer) {
return shouldVisit(((ICContainer) element).getResource());
}
if (element instanceof ITranslationUnit) {
ITranslationUnit tu = (ITranslationUnit) element;
boolean shouldVisit = shouldVisit(tu.getResource());
if (shouldVisit) {
IASTTranslationUnit ast = tu.getAST(index,
ITranslationUnit.AST_SKIP_ALL_HEADERS);
if (CoreMoSyncPlugin.getDefault().isDebugging()) {
CoreMoSyncPlugin.trace("Parsing translation unit {0}",
ast.getFilePath());
}
if (ast != null) {
List<IMarker> partialResult = rule.analyze(MoSyncProject.create(tu.getResource().getProject()), variant, tu, ast);
if (partialResult != null) {
result.addAll(partialResult);
}
}
}
return !isCancelled() && shouldVisit;
}
return !isCancelled();
}
private boolean isCancelled() {
return monitor != null && monitor.isCanceled();
}
public List<IMarker> getResult() {
return result;
}
}
protected CPPASTMolintRule(String id, String name) {
super(id, name);
}
private boolean shouldVisit(IResource resource) {
return resource != null
&& !MoSyncBuilder.isInOutput(resource.getProject(), resource);
}
@Override
public List<IMarker> analyze(IProgressMonitor monitor, MoSyncProject mosyncProject, IBuildVariant variant) throws CoreException {
IProject project = mosyncProject.getWrappedProject();
ICProject cProject = CoreModel.getDefault().create(project);
monitor.beginTask(
MessageFormat.format("Analyzing {0}", project.getName()), 1);
monitor.worked(1);
IIndex index = CCorePlugin.getIndexManager().getIndex(cProject);
try {
index.acquireReadLock();
} catch (InterruptedException e) {
throw new CoreException(new Status(IStatus.ERROR,
CoreMoSyncPlugin.PLUGIN_ID, e.getMessage(), e));
}
try {
AnalyzeVisitor visitor = new AnalyzeVisitor(monitor, index, variant, this);
cProject.accept(visitor);
// Since we only get C/C++ Problem markers, no need to clear
// markers (this is done in the compilation step).
return visitor.getResult();
} finally {
index.releaseReadLock();
monitor.done();
}
}
/**
* Returns problem markers from the analysis.
* @param tu
* @param ast
* @return Problem markers, all being of the 'C/C++ Problem' type
* @throws CoreException
*/
protected abstract List<IMarker> analyze(MoSyncProject project, IBuildVariant variant, ITranslationUnit tu, IASTTranslationUnit ast) throws CoreException;
}