/*******************************************************************************
* Copyright (c) 2013 The PDT Extension Group (https://github.com/pdt-eg)
* 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
******************************************************************************/
package org.pdtextensions.internal.semanticanalysis.integration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import javax.inject.Inject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.dltk.ast.declarations.ModuleDeclaration;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.IType;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.builder.IBuildContext;
import org.eclipse.dltk.core.builder.IBuildParticipant;
import org.eclipse.dltk.core.builder.IBuildParticipantExtension3;
import org.eclipse.dltk.core.builder.IBuildState;
import org.eclipse.dltk.internal.core.ModelManager;
import org.eclipse.php.internal.core.PHPCorePlugin;
import org.eclipse.php.core.compiler.ast.nodes.UsePart;
import org.eclipse.php.core.compiler.ast.visitor.PHPASTVisitor;
import org.pdtextensions.core.log.Logger;
import org.pdtextensions.core.util.PDTModelUtils;
import org.pdtextensions.internal.semanticanalysis.validation.ValidatorContext;
import org.pdtextensions.semanticanalysis.PEXAnalysisPlugin;
import org.pdtextensions.semanticanalysis.model.validators.Validator;
import org.pdtextensions.semanticanalysis.validation.IValidatorManager;
import org.pdtextensions.semanticanalysis.validation.IValidatorParticipant;
/**
* Build participant for semantic validators
*
* @author Dawid zulus Pakula <zulus@w3des.net>
*/
@SuppressWarnings("restriction")
public class BuildParticipant implements IBuildParticipant, IBuildParticipantExtension3 {
@Inject
private IValidatorManager manager;
private Map<String, Files> tmpTypes = new HashMap<String, Files>();
@Override
public void build(IBuildContext context) throws CoreException {
if (!context.getSourceModule().getScriptProject().isOnBuildpath(context.getSourceModule().getResource())
|| !manager.isEnabled(context.getSourceModule().getScriptProject())) {
return;
}
if (context.getBuildType() != IBuildContext.RECONCILE_BUILD) {
ModelManager.getModelManager().getIndexManager().waitUntilReady();
}
ISourceModule workingCopy = context.getSourceModule();
//if (context.getBuildType() == IBuildContext.RECONCILE_BUILD) {
//try {
//workingCopy = context.getSourceModule().getWorkingCopy(null);
//} catch (ModelException e) {
// Logger.logException(e);
//}
//}
for (Validator validator : manager.getValidators(context.getSourceModule().getScriptProject())) {
final ValidatorContext validatorContext = new ValidatorContext(validator, workingCopy, context, manager);
validate(validatorContext, validator.getValidatorFactory().getValidatorParticipant(validatorContext.getProject()));
}
// dependency report
if (context.getBuildType() == IBuildContext.RECONCILE_BUILD) {
return;
}
final ModuleDeclaration moduleDeclaration = (ModuleDeclaration) context.get(IBuildContext.ATTR_MODULE_DECLARATION);
if (moduleDeclaration != null) {
try {
moduleDeclaration.traverse(new UsageVisitor(context));
} catch (Exception e) {
PEXAnalysisPlugin.error("Exception during dependency detection", e); //$NON-NLS-1$
}
}
}
private void validate(final ValidatorContext validatorContext, final IValidatorParticipant validatorParticipant) {
// if null ignore
if (validatorParticipant == null) {
return;
}
if (validatorContext.isDerived() && !validatorParticipant.allowDerived()) {
return;
}
try {
validatorParticipant.validate(validatorContext);
} catch (Exception e) {
PEXAnalysisPlugin.error("Exception during validation", e); //$NON-NLS-1$
}
}
/**
* Do not run if toolkit is not ready
*/
@Override
public boolean beginBuild(int buildType) {
return PHPCorePlugin.toolkitInitialized;
}
@Override
public void endBuild(IProgressMonitor monitor) {
}
@Override
public void clean() {
tmpTypes.clear();
}
/**
* TODO: Detect real use (not only imports)
*/
private class UsageVisitor extends PHPASTVisitor {
final private IBuildContext context;
final private ISourceModule module;
public UsageVisitor(final IBuildContext context) {
this.context = context;
this.module = context.getSourceModule();
}
@Override
public boolean visit(UsePart s) throws Exception {
final String searchString = s.getNamespace().getFullyQualifiedName();
if (!tmpTypes.containsKey(searchString)) {
final Files files = new Files();
tmpTypes.put(searchString, files);
resolve(searchString, files);
}
final Files files = tmpTypes.get(searchString);
for (IPath f : files) {
if (context.getFile().getFullPath().equals(f)) {
continue;
}
context.recordDependency(f, IBuildState.STRUCTURAL); // mark as dependecy as structural
}
return true;
}
private void resolve(String searchString, Files files) throws ModelException {
registerTypes(PDTModelUtils.findTypes(module.getScriptProject(), searchString), files);
}
private void registerTypes(IType[] types, Files files) {
for (IType type : types) {
if (!getModulePath().equals(getTypePath(type))) {
files.add(getTypePath(type));
}
}
}
private IPath getModulePath() {
return module.getResource().getFullPath();
}
private IPath getTypePath(IType type) {
return type.getResource() == null ? type.getPath() : type.getResource().getFullPath();
}
}
private class Files extends HashSet<IPath> {
private static final long serialVersionUID = -4757183524417278724L;
}
}