/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.core.internal.builder;
import com.google.dart.engine.context.AnalysisContext;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.core.DartCoreDebug;
import com.google.dart.tools.core.analysis.model.Project;
import com.google.dart.tools.core.analysis.model.ProjectManager;
import com.google.dart.tools.core.analysis.model.PubFolder;
import com.google.dart.tools.core.builder.BuildEvent;
import com.google.dart.tools.core.builder.BuildParticipant;
import com.google.dart.tools.core.builder.BuildVisitor;
import com.google.dart.tools.core.builder.CleanEvent;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceProxy;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import static org.eclipse.core.resources.IResource.DEPTH_INFINITE;
/**
* Performs source analysis using instances of {@link AnalysisContext}.
*
* @coverage dart.tools.core.builder
*/
public class AnalysisEngineParticipant implements BuildParticipant {
/**
* The marker manager used to translate errors to Eclipse markers (not {@code null}).
*/
private final AnalysisMarkerManager markerManager;
/**
* The project manager (not {@code null}) responsible for caching project information and from
* which the receiver obtains the project to be analyzed.
*/
private final ProjectManager projectManager;
/**
* The project being analyzed by this build participant or {@code null} if it has not been
* initialized yet.
*/
private Project project;
public AnalysisEngineParticipant() {
this(DartCore.getProjectManager(), AnalysisMarkerManager.getInstance());
}
public AnalysisEngineParticipant(ProjectManager projectManager,
AnalysisMarkerManager markerManager) {
if (projectManager == null) {
throw new IllegalArgumentException();
}
this.projectManager = projectManager;
this.markerManager = markerManager;
}
/**
* Traverse and analyze resources
*/
@Override
public void build(BuildEvent event, IProgressMonitor monitor) throws CoreException {
if (monitor.isCanceled()) {
return;
}
final ProjectUpdater updater = new ProjectUpdater();
final IndexUpdater indexUpdater = new IndexUpdater(projectManager.getIndex());
// Traverse resources specified by the build event
event.traverse(new BuildVisitor() {
@Override
public boolean visit(IResourceDelta delta, IProgressMonitor monitor) throws CoreException {
IProject resource = (IProject) delta.getResource();
if (project == null) {
project = projectManager.getProject(resource);
}
DeltaProcessor processor = createProcessor(project);
IgnoreResourceFilter filter = new IgnoreResourceFilter();
filter.addDeltaListener(updater);
filter.addDeltaListener(indexUpdater);
processor.addDeltaListener(filter);
processor.traverse(delta);
return false;
}
@Override
public boolean visit(IResourceProxy proxy, IProgressMonitor monitor) throws CoreException {
IProject resource = (IProject) proxy.requestResource();
if (project == null) {
project = projectManager.getProject(resource);
}
DeltaProcessor processor = createProcessor(project);
IgnoreResourceFilter filter = new IgnoreResourceFilter();
filter.addDeltaListener(updater);
filter.addDeltaListener(indexUpdater);
processor.addDeltaListener(filter);
processor.traverse(resource);
return false;
}
}, false);
// Apply the changes to the project
updater.applyChanges();
if (monitor.isCanceled()) {
return;
}
// Perform analysis on each context in the project
if (!DartCoreDebug.ENABLE_ANALYSIS_SERVER) {
if (project != null) {
// TODO We probably don't need this null check if the visitor above covers all cases.
for (PubFolder pubFolder : project.getPubFolders()) {
analyzeContext(pubFolder.getContext(), monitor);
}
if (project.getPubFolder(project.getResource()) == null) {
analyzeContext(project.getDefaultContext(), monitor);
}
}
}
if (monitor.isCanceled()) {
return;
}
}
/**
* Discard all markers and cached analysis
*/
@Override
public void clean(CleanEvent event, IProgressMonitor monitor) throws CoreException {
if (monitor.isCanceled()) {
return;
}
if (project != null) {
project.discardContextsIn(event.getProject());
project = null;
}
event.getProject().deleteMarkers(DartCore.DART_PROBLEM_MARKER_TYPE, true, DEPTH_INFINITE);
event.getProject().deleteMarkers(DartCore.DART_TASK_MARKER_TYPE, true, DEPTH_INFINITE);
}
/**
* Initialize the delta processor associated with this builder. Overridden when testing this
* class.
*
* @param project the project for which the processor is created (not {@code null})
* @return the delta processor (not {@code null})
*/
protected DeltaProcessor createProcessor(Project project) {
return new DeltaProcessor(project);
}
/**
* Perform analysis using the specified worker.
*
* @param worker the worker (not {@code null})
*/
protected void performAnalysis(AnalysisWorker worker) {
worker.performAnalysisInBackground();
}
/**
* Perform analysis on the specified context.
*
* @param context the context to analyze (not {@code null})
* @param monitor the progress monitor (not {@code null})
*/
private void analyzeContext(AnalysisContext context, IProgressMonitor monitor) {
performAnalysis(new AnalysisWorker(
project,
context,
projectManager,
projectManager.getResourceMap(context),
markerManager));
}
}