Skip to content
This repository has been archived by the owner on Apr 21, 2023. It is now read-only.

Commit

Permalink
[bug 407161]: resolved
Browse files Browse the repository at this point in the history
Change-Id: I26213881c3d5029392b99d42ec5b9e4f02816853
Signed-off-by: akosyakov <anton.kosyakov@itemis.de>
  • Loading branch information
akosyakov committed Sep 24, 2013
1 parent d1700b5 commit c0d5cdb
Show file tree
Hide file tree
Showing 7 changed files with 500 additions and 69 deletions.
1 change: 1 addition & 0 deletions plugins/org.eclipse.xtext.builder/.classpath
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="xtend-gen"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
Expand Down
3 changes: 2 additions & 1 deletion plugins/org.eclipse.xtext.builder/build.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
source.. = emf-gen/,\
src/
src/,\
xtend-gen/
bin.includes = META-INF/,\
.,\
plugin.xml,\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,28 @@
*******************************************************************************/
package org.eclipse.xtext.builder.impl;

import java.lang.reflect.Field;
import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IStorage;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.builder.StringSet;
import org.eclipse.xtext.builder.impl.javasupport.UnconfirmedStructuralChangesDelta;
import org.eclipse.xtext.naming.QualifiedName;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.resource.impl.ChangedResourceDescriptionDelta;
import org.eclipse.xtext.ui.XtextProjectHelper;
import org.eclipse.xtext.ui.resource.IStorage2UriMapper;
import org.eclipse.xtext.util.Pair;
Expand All @@ -26,6 +37,7 @@
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Singleton;

Expand All @@ -35,37 +47,146 @@
@Singleton
public class QueuedBuildData {

private static final Logger LOG = Logger.getLogger(QueuedBuildData.class);

private class JavaBuilderState {

long lastStructuralBuildTime = -1;

int buildNumber = -1;

Set<QualifiedName> structurallyChangedTypes = Sets.newHashSet();

@Override
public String toString() {
return "[buildNo=" + buildNumber + ";lastStructuralBuildTime=" + lastStructuralBuildTime
+ ";structurallyChangedTypes=" + structurallyChangedTypes + "]";
}

}

private Collection<IResourceDescription.Delta> deltas;
private Collection<UnconfirmedStructuralChangesDelta> unconfirmedDeltas;
private LinkedList<URI> uris;
private Map<String, LinkedList<URI>> projectNameToChangedResource;

private Map<String, JavaBuilderState> javaBuildState;

@Inject
private IStorage2UriMapper mapper;

public QueuedBuildData() {
deltas = Lists.newArrayList();
reset();
}

public void reset() {
uris = Lists.newLinkedList();
deltas = Lists.newArrayList();
unconfirmedDeltas = Lists.newArrayList();
javaBuildState = Maps.newHashMap();
projectNameToChangedResource = Maps.newHashMap();
}

public Collection<UnconfirmedStructuralChangesDelta> getUnconfirmedDeltas() {
return Collections.unmodifiableCollection(unconfirmedDeltas);
}

protected Object readField(Object obj, String field, Object defaultValue) {
try {
Field f = obj.getClass().getDeclaredField(field);
f.setAccessible(true);
Object object = f.get(obj);
if (object != null)
return object;
return defaultValue;
} catch (Exception e) {
if (LOG.isEnabledFor(Level.ERROR)) {
LOG.error(e);
}
return defaultValue;
}
}

protected boolean namesIntersect(IResourceDescription desc, Set<QualifiedName> names) {
if (desc != null)
for (IEObjectDescription name : desc.getExportedObjects())
if (names.contains(name.getQualifiedName()))
return true;
return false;
}

protected JavaBuilderState readJavaBuilderState(IProject project) {
JavaBuilderState state = new JavaBuilderState();
Object jdtState = JavaModelManager.getJavaModelManager().getLastBuiltState(project, null);
if (jdtState != null) {
StringSet types = (StringSet) readField(jdtState, "structurallyChangedTypes", null);
if (types != null)
for (String name : types.values)
if (name != null)
state.structurallyChangedTypes.add(QualifiedName.create(name.split("/")));
state.lastStructuralBuildTime = (Long) readField(jdtState, "lastStructuralBuildTime", -1l);
state.buildNumber = (Integer) readField(jdtState, "buildNumber", -1);
}
return state;
}

public synchronized boolean tryConfirmAllChanges(IProject project) {
JavaBuilderState oldState = javaBuildState.get(project.getName());
JavaBuilderState newState = readJavaBuilderState(project);
if (oldState == null || oldState.lastStructuralBuildTime != newState.lastStructuralBuildTime) {
Iterator<UnconfirmedStructuralChangesDelta> iterator = unconfirmedDeltas.iterator();
while (iterator.hasNext()) {
UnconfirmedStructuralChangesDelta unconfirmed = iterator.next();
if (unconfirmed.getBuildNumber() < newState.buildNumber && unconfirmed.getProject().equals(project)) {
iterator.remove();
if (namesIntersect(unconfirmed.getNew(), newState.structurallyChangedTypes)
|| namesIntersect(unconfirmed.getOld(), newState.structurallyChangedTypes))
deltas.add(new ChangedResourceDescriptionDelta(unconfirmed.getOld(), unconfirmed.getNew()));
}
}
} else {
Iterator<UnconfirmedStructuralChangesDelta> iterator = unconfirmedDeltas.iterator();
while (iterator.hasNext()) {
UnconfirmedStructuralChangesDelta unconfirmed = iterator.next();
if (unconfirmed.getBuildNumber() < newState.buildNumber && unconfirmed.getProject().equals(project))
iterator.remove();
}
}
javaBuildState.put(project.getName(), newState);
return unconfirmedDeltas.isEmpty();
}

public synchronized void queueChanges(Collection<IResourceDescription.Delta> deltas) {
if (deltas != null && !deltas.isEmpty()) {
this.deltas.addAll(deltas);
for (IResourceDescription.Delta delta : deltas) {
if (delta instanceof UnconfirmedStructuralChangesDelta) {
UnconfirmedStructuralChangesDelta unconfirmend = (UnconfirmedStructuralChangesDelta) delta;
IProject project = unconfirmend.getProject();
JavaBuilderState state = javaBuildState.get(project.getName());
if (state == null) {
javaBuildState.put(project.getName(), state = readJavaBuilderState(project));
}
unconfirmend.setBuildNumber(state.buildNumber);
this.unconfirmedDeltas.add(unconfirmend);
} else {
this.deltas.add(delta);
}
}
}
}

public synchronized void queueURIs(Collection<URI> uris) {
if (uris != null && !uris.isEmpty()) {
for(URI uri: uris) {
for (URI uri : uris) {
queueURI(uri);
}
}
}

@Inject
private IStorage2UriMapper mapper;


public void queueURI(URI uri) {
Iterable<Pair<IStorage, IProject>> iterable = mapper.getStorages(uri);
boolean associatedWithProject = false;
for(Pair<IStorage, IProject> pair: iterable) {
for (Pair<IStorage, IProject> pair : iterable) {
IProject project = pair.getSecond();
if (XtextProjectHelper.hasNature(project) && XtextProjectHelper.hasBuilder(project)) {
String projectName = project.getName();
Expand All @@ -88,7 +209,7 @@ public Collection<IResourceDescription.Delta> getAndRemovePendingDeltas() {
deltas = Lists.newArrayList();
return result;
}

public boolean isEmpty(String projectName) {
return deltas.isEmpty() && getQueue(projectName).isEmpty();
}
Expand Down Expand Up @@ -134,15 +255,15 @@ public Iterable<URI> getAllRemainingURIs() {
protected IStorage2UriMapper getMapper() {
return mapper;
}

protected Collection<IResourceDescription.Delta> getDeltas() {
return deltas;
}

protected Map<String, LinkedList<URI>> getProjectNameToChangedResource() {
return projectNameToChangedResource;
}

protected LinkedList<URI> getUris() {
return uris;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ private String getKindAsString(int kind) {
protected void incrementalBuild(IResourceDelta delta, final IProgressMonitor monitor) throws CoreException {
final SubMonitor progress = SubMonitor.convert(monitor, Messages.XtextBuilder_CollectingResources, 10);
progress.subTask(Messages.XtextBuilder_CollectingResources);

if (!queuedBuildData.tryConfirmAllChanges(getProject())) {
needRebuild();
}

final ToBeBuilt toBeBuilt = new ToBeBuilt();
IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*******************************************************************************
* Copyright (c) 2013 itemis AG (http://www.itemis.eu) and others.
* 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.eclipse.xtext.builder.impl.javasupport

import com.google.common.base.Preconditions
import com.google.inject.Inject
import java.util.List
import org.eclipse.core.resources.IProject
import org.eclipse.jdt.core.ICompilationUnit
import org.eclipse.jdt.core.IJavaElementDelta
import org.eclipse.jdt.core.IType
import org.eclipse.xtext.common.types.access.jdt.TypeURIHelper
import org.eclipse.xtext.common.types.ui.notification.DeltaConverter
import org.eclipse.xtext.naming.IQualifiedNameConverter
import org.eclipse.xtext.resource.IResourceDescription
import org.eclipse.xtext.resource.IResourceDescription.Delta
import org.eclipse.xtext.resource.impl.DefaultResourceDescriptionDelta

/**
* @author Anton Kosyakov - Initial contribution and API
*/
class BuilderDeltaConverter extends DeltaConverter {

@Inject
new(IQualifiedNameConverter nameConverter, TypeURIHelper uriHelper) {
super(nameConverter, uriHelper)
}

override protected convertCompilationUnit(IJavaElementDelta delta, List<Delta> result) {
super.convertCompilationUnit(delta, result)
if (delta.primaryWorkingCopy && !delta.fineGrainedDelta && !delta.coarseGrainedDelta) {
val type = getPrimaryTypeFrom(delta.element as ICompilationUnit)
if (type != null) {
result.add(new RollbackResourceDescriptionDelta(type))
}
}
}

private def isPrimaryWorkingCopy(IJavaElementDelta delta) {
delta.flags.bitwiseAnd(IJavaElementDelta.F_PRIMARY_WORKING_COPY) != 0
}

override protected createResourceDescriptionDelta(IProject project, String primaryTypeName,
IResourceDescription oldDescription, IResourceDescription newDescription) {
if (oldDescription == null || newDescription == null) {
return new UnsubmittedResourceDescriptionDelta(primaryTypeName, oldDescription, newDescription);
}
return new UnconfirmedStructuralChangesDelta(project, primaryTypeName, oldDescription, newDescription)
}

}

/**
* <p>
* Intances of this delta type are used to rollback unsubmitted deltas for the given primary type.
* </p>
*/
class RollbackResourceDescriptionDelta implements IResourceDescription.Delta {

IType primaryType

new(IType primaryType) {
Preconditions.checkNotNull(primaryType)
this.primaryType = primaryType
}

def getPrimaryTypeName() {
primaryType.fullyQualifiedName
}

override getNew() {
null
}

override getOld() {
null
}

override getUri() {
null
}

override haveEObjectDescriptionsChanged() {
false
}

}

/**
* <p>
* Instances of this delta type are collected for the given primary type during reconcilation.
* </p>
*/
class UnsubmittedResourceDescriptionDelta extends DefaultResourceDescriptionDelta {

val String primaryTypeName

new(String primaryTypeName, IResourceDescription old, IResourceDescription _new) {
super(old, _new)
Preconditions.checkNotNull(primaryTypeName)
this.primaryTypeName = primaryTypeName
}

def getPrimaryTypeName() {
primaryTypeName
}

}

/**
* <p>
* Instances of this delta type could be rejected during confirmation of structural changes.
* </p>
*/
class UnconfirmedStructuralChangesDelta extends UnsubmittedResourceDescriptionDelta {

var buildNumber = -1

val IProject project

new(IProject project, String primaryTypeName, IResourceDescription old, IResourceDescription _new) {
super(primaryTypeName, old, _new)
Preconditions.checkNotNull(project)
Preconditions.checkNotNull(old)
Preconditions.checkNotNull(_new)
this.project = project
}

def getBuildNumber() {
buildNumber
}

def setBuildNumber(int buildNumber) {
this.buildNumber = buildNumber
}

def getProject() {
project
}

}

0 comments on commit c0d5cdb

Please sign in to comment.