package com.redhat.ceylon.eclipse.core.typechecker; import java.util.Iterator; import java.util.List; import java.util.WeakHashMap; import org.antlr.runtime.CommonToken; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import com.redhat.ceylon.compiler.typechecker.TypeChecker; import com.redhat.ceylon.compiler.typechecker.analyzer.ModuleSourceMapper; import com.redhat.ceylon.compiler.typechecker.analyzer.ModuleSourceMapper.ModuleDependencyAnalysisError; import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit; import com.redhat.ceylon.compiler.typechecker.context.PhasedUnits; import com.redhat.ceylon.compiler.typechecker.context.TypecheckerUnit; import com.redhat.ceylon.compiler.typechecker.tree.Message; import com.redhat.ceylon.compiler.typechecker.tree.Node; import com.redhat.ceylon.compiler.typechecker.tree.Tree; import com.redhat.ceylon.compiler.typechecker.tree.Tree.CompilationUnit; import com.redhat.ceylon.compiler.typechecker.tree.Visitor; import com.redhat.ceylon.eclipse.core.model.JDTModule; import com.redhat.ceylon.eclipse.core.model.ProjectSourceFile; import com.redhat.ceylon.eclipse.core.vfs.vfsJ2C; import com.redhat.ceylon.ide.common.vfs.ResourceVirtualFile; import com.redhat.ceylon.model.typechecker.model.Package; import com.redhat.ceylon.model.typechecker.util.ModuleManager; public class ProjectPhasedUnit extends ModifiablePhasedUnit { private IFolder sourceFolderResource; private WeakHashMap<EditedPhasedUnit, String> workingCopies = new WeakHashMap<EditedPhasedUnit, String>(); public ProjectPhasedUnit(ResourceVirtualFile<IResource, IFolder, IFile> unitFile, ResourceVirtualFile<IResource, IFolder, IFile> srcDir, CompilationUnit cu, Package p, ModuleManager moduleManager, ModuleSourceMapper moduleSourceMapper, TypeChecker typeChecker, List<CommonToken> tokenStream) { super(unitFile, srcDir, cu, p, moduleManager, moduleSourceMapper, typeChecker, tokenStream); sourceFolderResource = (IFolder) srcDir.getNativeResource(); srcDir.getNativeResource().getProject(); } public ProjectPhasedUnit(PhasedUnit other) { super(other); } @Override public IFile getResourceFile() { return (IFile) vfsJ2C.getIFileVirtualFile(getUnitFile()).getNativeResource(); } @Override public IFolder getResourceRootFolder() { return sourceFolderResource; } @Override public IProject getResourceProject() { return sourceFolderResource.getProject(); } @Override protected TypecheckerUnit newUnit() { return new ProjectSourceFile(this); } public void addWorkingCopy(EditedPhasedUnit workingCopy) { synchronized (workingCopies) { String fullPath = workingCopy.getUnit() != null ? workingCopy.getUnit().getFullPath() : null; Iterator<String> itr = workingCopies.values().iterator(); while (itr.hasNext()) { String workingCopyPath = itr.next(); if (workingCopyPath.equals(fullPath)) { itr.remove(); } } workingCopies.put(workingCopy, fullPath); } } public Iterator<EditedPhasedUnit> getWorkingCopies() { return workingCopies.keySet().iterator(); } public void install() { TypeChecker typechecker = getTypeChecker(); if (typechecker == null) { return; } PhasedUnits phasedUnits = typechecker.getPhasedUnits(); ProjectPhasedUnit oldPhasedUnit = (ProjectPhasedUnit) phasedUnits.getPhasedUnitFromRelativePath(getPathRelativeToSrcDir()); if (oldPhasedUnit == this) { return; // Nothing to do : the PhasedUnit is already installed in the typechecker } if (oldPhasedUnit != null) { ProjectSourceFile oldSourceFile = (ProjectSourceFile) oldPhasedUnit.getUnit(); getUnit().getDependentsOf().addAll(oldSourceFile.getDependentsOf()); Iterator<EditedPhasedUnit> workingCopies = oldPhasedUnit.getWorkingCopies(); while (workingCopies.hasNext()) { addWorkingCopy(workingCopies.next()); } final Tree.CompilationUnit newCompilationUnit = getCompilationUnit(); new Visitor() { @Override public void visitAny(Node node) { super.visitAny(node); for (Message error: node.getErrors()) { if (error instanceof ModuleDependencyAnalysisError) { newCompilationUnit.addError(error); } } } }.visit(oldPhasedUnit.getCompilationUnit()); oldPhasedUnit.remove(); // pour les ICrossProjectReference, le but c'est d'enlever ce qu'il y avait (binaires ou source) // Ensuite pour les éléments nouveaux , dans le cas binaire il seront normalement trouvés si le // classpath est normalement remis à jour, et pour les éléments source, on parcourt tous les projets // } phasedUnits.addPhasedUnit(getUnitFile(), this); JDTModule module = (JDTModule) getPackage().getModule(); for (JDTModule moduleInReferencingProject : module.getModuleInReferencingProjects()) { moduleInReferencingProject.addedOriginalUnit(getPathRelativeToSrcDir()); } // Pour tous les projets dépendants, on appelle addPhasedUnit () sur le module correspondant, qui doit être un module source externe // Attention : penser à ajouter une étape de retypecheck des modules dépendants à la compil incrémentale. De toute manière ceux qui sont déjà faits ne seront pas refaits. } public void remove() { TypeChecker typechecker = getTypeChecker(); if (typechecker == null) { return; } PhasedUnits phasedUnits = typechecker.getPhasedUnits(); phasedUnits.removePhasedUnitForRelativePath(getPathRelativeToSrcDir()); // remove also the ProjectSourceFile (unit) from the Package JDTModule module = (JDTModule) getPackage().getModule(); for (JDTModule moduleInReferencingProject : module.getModuleInReferencingProjects()) { moduleInReferencingProject.removedOriginalUnit(getPathRelativeToSrcDir()); } } }