View | Details | Raw Unified | Return to bug 21606
Collapse All | Expand All

(-)model/org/eclipse/jdt/internal/core/builder/AbstractImageBuilder.java (-411 / +416 lines)
Lines 1-412 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
2
 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3
 * All rights reserved. This program and the accompanying materials 
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v0.5 
4
 * are made available under the terms of the Common Public License v0.5 
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v05.html
6
 * http://www.eclipse.org/legal/cpl-v05.html
7
 * 
7
 * 
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.jdt.internal.core.builder;
11
package org.eclipse.jdt.internal.core.builder;
12
12
13
import org.eclipse.core.runtime.*;
13
import org.eclipse.core.runtime.*;
14
import org.eclipse.core.resources.*;
14
import org.eclipse.core.resources.*;
15
15
16
import org.eclipse.jdt.core.*;
16
import org.eclipse.jdt.core.*;
17
import org.eclipse.jdt.core.compiler.IProblem;
17
import org.eclipse.jdt.core.compiler.IProblem;
18
import org.eclipse.jdt.internal.compiler.*;
18
import org.eclipse.jdt.internal.compiler.*;
19
import org.eclipse.jdt.internal.compiler.ClassFile;
19
import org.eclipse.jdt.internal.compiler.ClassFile;
20
import org.eclipse.jdt.internal.compiler.Compiler;
20
import org.eclipse.jdt.internal.compiler.Compiler;
21
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
21
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
22
import org.eclipse.jdt.internal.compiler.problem.*;
22
import org.eclipse.jdt.internal.compiler.problem.*;
23
import org.eclipse.jdt.internal.compiler.util.CharOperation;
23
import org.eclipse.jdt.internal.compiler.util.CharOperation;
24
import org.eclipse.jdt.internal.core.*;
24
import org.eclipse.jdt.internal.core.*;
25
25
26
import java.io.*;
26
import java.io.*;
27
import java.util.*;
27
import java.util.*;
28
28
29
/**
29
/**
30
 * The abstract superclass of image builders.
30
 * The abstract superclass of image builders.
31
 * Provides the building and compilation mechanism
31
 * Provides the building and compilation mechanism
32
 * in common with the batch and incremental builders.
32
 * in common with the batch and incremental builders.
33
 */
33
 */
34
public abstract class AbstractImageBuilder implements ICompilerRequestor {
34
public abstract class AbstractImageBuilder implements ICompilerRequestor {
35
35
36
protected JavaBuilder javaBuilder;
36
protected JavaBuilder javaBuilder;
37
protected State newState;
37
protected State newState;
38
38
39
// local copies
39
// local copies
40
protected IContainer outputFolder;
40
protected IContainer outputFolder;
41
protected IContainer[] sourceFolders;
41
protected IContainer[] sourceFolders;
42
protected BuildNotifier notifier;
42
protected BuildNotifier notifier;
43
43
44
protected boolean hasSeparateOutputFolder;
44
protected boolean hasSeparateOutputFolder;
45
protected NameEnvironment nameEnvironment;
45
protected NameEnvironment nameEnvironment;
46
protected Compiler compiler;
46
protected Compiler compiler;
47
protected WorkQueue workQueue;
47
protected WorkQueue workQueue;
48
protected ArrayList problemTypeLocations;
48
protected ArrayList problemTypeLocations;
49
protected boolean compiledAllAtOnce;
49
protected boolean compiledAllAtOnce;
50
50
51
private boolean inCompiler;
51
private boolean inCompiler;
52
52
53
public static int MAX_AT_ONCE = 1000;
53
public static int MAX_AT_ONCE = 1000;
54
54
55
protected AbstractImageBuilder(JavaBuilder javaBuilder) {
55
protected AbstractImageBuilder(JavaBuilder javaBuilder) {
56
	this.javaBuilder = javaBuilder;
56
	this.javaBuilder = javaBuilder;
57
	this.newState = new State(javaBuilder);
57
	this.newState = new State(javaBuilder);
58
58
59
	// local copies
59
	// local copies
60
	this.outputFolder = javaBuilder.outputFolder;
60
	this.outputFolder = javaBuilder.outputFolder;
61
	this.sourceFolders = javaBuilder.sourceFolders;
61
	this.sourceFolders = javaBuilder.sourceFolders;
62
	this.notifier = javaBuilder.notifier;
62
	this.notifier = javaBuilder.notifier;
63
63
64
	// only perform resource copying if the output location does not match a source folder
64
	// only perform resource copying if the output location does not match a source folder
65
	// corresponds to: project == src == bin, or several source folders are contributing resources,
65
	// corresponds to: project == src == bin, or several source folders are contributing resources,
66
	// but one is the output location too (and would get populated with other source folder resources).
66
	// but one is the output location too (and would get populated with other source folder resources).
67
	IPath outputPath = outputFolder.getFullPath();
67
	IPath outputPath = outputFolder.getFullPath();
68
	int index = sourceFolders.length;
68
	int index = sourceFolders.length;
69
	if (index == 0) {
69
	if (index == 0) {
70
		// handle case of the last source folder is removed... so no source folders exist but the output folder must still be scrubbed
70
		// handle case of the last source folder is removed... so no source folders exist but the output folder must still be scrubbed
71
		this.hasSeparateOutputFolder = !outputPath.equals(javaBuilder.currentProject.getFullPath());
71
		this.hasSeparateOutputFolder = !outputPath.equals(javaBuilder.currentProject.getFullPath());
72
	} else {
72
	} else {
73
		this.hasSeparateOutputFolder = true;
73
		this.hasSeparateOutputFolder = true;
74
		while (this.hasSeparateOutputFolder && --index >= 0)
74
		while (this.hasSeparateOutputFolder && --index >= 0)
75
			this.hasSeparateOutputFolder = !outputPath.equals(sourceFolders[index].getFullPath());
75
			this.hasSeparateOutputFolder = !outputPath.equals(sourceFolders[index].getFullPath());
76
	}
76
	}
77
77
78
	this.nameEnvironment = new NameEnvironment(javaBuilder.classpath);
78
	this.nameEnvironment = new NameEnvironment(javaBuilder.classpath);
79
	this.compiler = newCompiler();
79
	this.compiler = newCompiler();
80
	this.workQueue = new WorkQueue();
80
	this.workQueue = new WorkQueue();
81
	this.problemTypeLocations = new ArrayList(3);
81
	this.problemTypeLocations = new ArrayList(3);
82
}
82
}
83
83
84
public void acceptResult(CompilationResult result) {
84
public void acceptResult(CompilationResult result) {
85
	// In Batch mode, we write out the class files, hold onto the dependency info
85
	// In Batch mode, we write out the class files, hold onto the dependency info
86
	// & additional types and report problems.
86
	// & additional types and report problems.
87
87
88
	// In Incremental mode, when writing out a class file we need to compare it
88
	// In Incremental mode, when writing out a class file we need to compare it
89
	// against the previous file, remembering if structural changes occured.
89
	// against the previous file, remembering if structural changes occured.
90
	// Before reporting the new problems, we need to update the problem count &
90
	// Before reporting the new problems, we need to update the problem count &
91
	// remove the old problems. Plus delete additional class files that no longer exist.
91
	// remove the old problems. Plus delete additional class files that no longer exist.
92
92
93
	// only need to find resource for the sourceLocation when problems need to be reported against it
93
	// only need to find resource for the sourceLocation when problems need to be reported against it
94
	String sourceLocation = new String(result.getFileName()); // the full filesystem path "d:/xyz/eclipse/src1/Test/p1/p2/A.java"
94
	String sourceLocation = new String(result.getFileName()); // the full filesystem path "d:/xyz/eclipse/src1/Test/p1/p2/A.java"
95
	if (!workQueue.isCompiled(sourceLocation)) {
95
	if (!workQueue.isCompiled(sourceLocation)) {
96
		try {
96
		try {
97
			workQueue.finished(sourceLocation);
97
			workQueue.finished(sourceLocation);
98
			updateProblemsFor(sourceLocation, result); // record compilation problems before potentially adding duplicate errors
98
			updateProblemsFor(sourceLocation, result); // record compilation problems before potentially adding duplicate errors
99
99
100
			ICompilationUnit compilationUnit = result.getCompilationUnit();
100
			ICompilationUnit compilationUnit = result.getCompilationUnit();
101
			ClassFile[] classFiles = result.getClassFiles();
101
			ClassFile[] classFiles = result.getClassFiles();
102
			int length = classFiles.length;
102
			int length = classFiles.length;
103
			ArrayList duplicateTypeNames = null;
103
			ArrayList duplicateTypeNames = null;
104
			ArrayList definedTypeNames = new ArrayList(length);
104
			ArrayList definedTypeNames = new ArrayList(length);
105
			for (int i = 0; i < length; i++) {
105
			for (int i = 0; i < length; i++) {
106
				ClassFile classFile = classFiles[i];
106
				ClassFile classFile = classFiles[i];
107
				char[][] compoundName = classFile.getCompoundName();
107
				char[][] compoundName = classFile.getCompoundName();
108
				char[] typeName = compoundName[compoundName.length - 1];
108
				char[] typeName = compoundName[compoundName.length - 1];
109
				boolean isNestedType = CharOperation.contains('$', typeName);
109
				boolean isNestedType = CharOperation.contains('$', typeName);
110
110
111
				// Look for a possible collision, if one exists, report an error but do not write the class file
111
				// Look for a possible collision, if one exists, report an error but do not write the class file
112
				if (isNestedType) {
112
				if (isNestedType) {
113
					String qualifiedTypeName = new String(classFile.outerMostEnclosingClassFile().fileName());
113
					String qualifiedTypeName = new String(classFile.outerMostEnclosingClassFile().fileName());
114
					if (newState.isDuplicateLocation(qualifiedTypeName, sourceLocation))
114
					if (newState.isDuplicateLocation(qualifiedTypeName, sourceLocation))
115
						continue;
115
						continue;
116
				} else {
116
				} else {
117
					String qualifiedTypeName = new String(classFile.fileName()); // the qualified type name "p1/p2/A"
117
					String qualifiedTypeName = new String(classFile.fileName()); // the qualified type name "p1/p2/A"
118
					if (newState.isDuplicateLocation(qualifiedTypeName, sourceLocation)) {
118
					if (newState.isDuplicateLocation(qualifiedTypeName, sourceLocation)) {
119
						if (duplicateTypeNames == null)
119
						if (duplicateTypeNames == null)
120
							duplicateTypeNames = new ArrayList();
120
							duplicateTypeNames = new ArrayList();
121
						duplicateTypeNames.add(compoundName);
121
						duplicateTypeNames.add(compoundName);
122
						createErrorFor(resourceForLocation(sourceLocation), Util.bind("build.duplicateClassFile", new String(typeName))); //$NON-NLS-1$
122
						createErrorFor(resourceForLocation(sourceLocation), Util.bind("build.duplicateClassFile", new String(typeName))); //$NON-NLS-1$
123
						continue;
123
						continue;
124
					}
124
					}
125
					newState.recordLocationForType(qualifiedTypeName, sourceLocation);
125
					newState.recordLocationForType(qualifiedTypeName, sourceLocation);
126
				}
126
				}
127
				definedTypeNames.add(writeClassFile(classFile, !isNestedType));
127
				definedTypeNames.add(writeClassFile(classFile, !isNestedType));
128
			}
128
			}
129
129
130
			finishedWith(sourceLocation, result, compilationUnit.getMainTypeName(), definedTypeNames, duplicateTypeNames);
130
			finishedWith(sourceLocation, result, compilationUnit.getMainTypeName(), definedTypeNames, duplicateTypeNames);
131
			notifier.compiled(compilationUnit);
131
			notifier.compiled(compilationUnit);
132
		} catch (CoreException e) {
132
		} catch (CoreException e) {
133
			Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
133
			Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
134
			createErrorFor(resourceForLocation(sourceLocation), Util.bind("build.inconsistentClassFile")); //$NON-NLS-1$
134
			createErrorFor(resourceForLocation(sourceLocation), Util.bind("build.inconsistentClassFile")); //$NON-NLS-1$
135
		}
135
		}
136
	}
136
	}
137
}
137
}
138
138
139
protected void cleanUp() {
139
protected void cleanUp() {
140
	this.nameEnvironment.cleanup();
140
	this.nameEnvironment.cleanup();
141
141
142
	this.javaBuilder = null;
142
	this.javaBuilder = null;
143
	this.outputFolder = null;
143
	this.outputFolder = null;
144
	this.sourceFolders = null;
144
	this.sourceFolders = null;
145
	this.notifier = null;
145
	this.notifier = null;
146
	this.compiler = null;
146
	this.compiler = null;
147
	this.nameEnvironment = null;
147
	this.nameEnvironment = null;
148
	this.workQueue = null;
148
	this.workQueue = null;
149
	this.problemTypeLocations = null;
149
	this.problemTypeLocations = null;
150
}
150
}
151
151
152
/* Compile the given elements, adding more elements to the work queue 
152
/* Compile the given elements, adding more elements to the work queue 
153
* if they are affected by the changes.
153
* if they are affected by the changes.
154
*/
154
*/
155
protected void compile(String[] filenames, String[] initialTypeNames) {
155
protected void compile(String[] filenames, String[] initialTypeNames) {
156
	int toDo = filenames.length;
156
	int toDo = filenames.length;
157
	if (this.compiledAllAtOnce = toDo <= MAX_AT_ONCE) {
157
	if (this.compiledAllAtOnce = toDo <= MAX_AT_ONCE) {
158
		// do them all now
158
		// do them all now
159
		SourceFile[] toCompile = new SourceFile[toDo];
159
		SourceFile[] toCompile = new SourceFile[toDo];
160
		for (int i = 0; i < toDo; i++) {
160
		for (int i = 0; i < toDo; i++) {
161
			String filename = filenames[i];
161
			String filename = filenames[i];
162
			if (JavaBuilder.DEBUG)
162
			if (JavaBuilder.DEBUG)
163
				System.out.println("About to compile " + filename); //$NON-NLS-1$
163
				System.out.println("About to compile " + filename); //$NON-NLS-1$
164
			toCompile[i] = new SourceFile(filename, initialTypeNames[i]);
164
			toCompile[i] = new SourceFile(filename, initialTypeNames[i]);
165
		}
165
		}
166
		compile(toCompile, initialTypeNames, null);
166
		compile(toCompile, initialTypeNames, null);
167
	} else {
167
	} else {
168
		int i = 0;
168
		int i = 0;
169
		boolean compilingFirstGroup = true;
169
		boolean compilingFirstGroup = true;
170
		while (i < toDo) {
170
		while (i < toDo) {
171
			int doNow = toDo < MAX_AT_ONCE ? toDo : MAX_AT_ONCE;
171
			int doNow = toDo < MAX_AT_ONCE ? toDo : MAX_AT_ONCE;
172
			int index = 0;
172
			int index = 0;
173
			SourceFile[] toCompile = new SourceFile[doNow];
173
			SourceFile[] toCompile = new SourceFile[doNow];
174
			String[] initialNamesInLoop = new String[doNow];
174
			String[] initialNamesInLoop = new String[doNow];
175
			while (i < toDo && index < doNow) {
175
			while (i < toDo && index < doNow) {
176
				String filename = filenames[i];
176
				String filename = filenames[i];
177
				// Although it needed compiling when this method was called, it may have
177
				// Although it needed compiling when this method was called, it may have
178
				// already been compiled when it was referenced by another unit.
178
				// already been compiled when it was referenced by another unit.
179
				if (compilingFirstGroup || workQueue.isWaiting(filename)) {
179
				if (compilingFirstGroup || workQueue.isWaiting(filename)) {
180
					if (JavaBuilder.DEBUG)
180
					if (JavaBuilder.DEBUG)
181
						System.out.println("About to compile " + filename);//$NON-NLS-1$
181
						System.out.println("About to compile " + filename);//$NON-NLS-1$
182
					String initialTypeName = initialTypeNames[i];
182
					String initialTypeName = initialTypeNames[i];
183
					initialNamesInLoop[index] = initialTypeName;
183
					initialNamesInLoop[index] = initialTypeName;
184
					toCompile[index++] = new SourceFile(filename, initialTypeName);
184
					toCompile[index++] = new SourceFile(filename, initialTypeName);
185
				}
185
				}
186
				i++;
186
				i++;
187
			}
187
			}
188
			if (index < doNow) {
188
			if (index < doNow) {
189
				System.arraycopy(toCompile, 0, toCompile = new SourceFile[index], 0, index);
189
				System.arraycopy(toCompile, 0, toCompile = new SourceFile[index], 0, index);
190
				System.arraycopy(initialNamesInLoop, 0, initialNamesInLoop = new String[index], 0, index);
190
				System.arraycopy(initialNamesInLoop, 0, initialNamesInLoop = new String[index], 0, index);
191
			}
191
			}
192
			String[] additionalFilenames = new String[toDo - i];
192
			String[] additionalFilenames = new String[toDo - i];
193
			System.arraycopy(filenames, i, additionalFilenames, 0, additionalFilenames.length);
193
			System.arraycopy(filenames, i, additionalFilenames, 0, additionalFilenames.length);
194
			compilingFirstGroup = false;
194
			compilingFirstGroup = false;
195
			compile(toCompile, initialNamesInLoop, additionalFilenames);
195
			compile(toCompile, initialNamesInLoop, additionalFilenames);
196
		}
196
		}
197
	}
197
	}
198
}
198
}
199
199
200
void compile(SourceFile[] units, String[] initialTypeNames, String[] additionalFilenames) {
200
void compile(SourceFile[] units, String[] initialTypeNames, String[] additionalFilenames) {
201
	if (units.length == 0) return;
201
	if (units.length == 0) return;
202
	notifier.aboutToCompile(units[0]); // just to change the message
202
	notifier.aboutToCompile(units[0]); // just to change the message
203
203
204
	// extend additionalFilenames with all hierarchical problem types found during this entire build
204
	// extend additionalFilenames with all hierarchical problem types found during this entire build
205
	if (!problemTypeLocations.isEmpty()) {
205
	if (!problemTypeLocations.isEmpty()) {
206
		int toAdd = problemTypeLocations.size();
206
		int toAdd = problemTypeLocations.size();
207
		int length = additionalFilenames == null ? 0 : additionalFilenames.length;
207
		int length = additionalFilenames == null ? 0 : additionalFilenames.length;
208
		if (length == 0)
208
		if (length == 0)
209
			additionalFilenames = new String[toAdd];
209
			additionalFilenames = new String[toAdd];
210
		else
210
		else
211
			System.arraycopy(additionalFilenames, 0, additionalFilenames = new String[length + toAdd], 0, length);
211
			System.arraycopy(additionalFilenames, 0, additionalFilenames = new String[length + toAdd], 0, length);
212
		for (int i = 0; i < toAdd; i++)
212
		for (int i = 0; i < toAdd; i++)
213
			additionalFilenames[length + i] = (String) problemTypeLocations.get(i);
213
			additionalFilenames[length + i] = (String) problemTypeLocations.get(i);
214
	}
214
	}
215
	nameEnvironment.setNames(initialTypeNames, additionalFilenames);
215
	nameEnvironment.setNames(initialTypeNames, additionalFilenames);
216
	notifier.checkCancel();
216
	notifier.checkCancel();
217
	try {
217
	try {
218
		inCompiler = true;
218
		inCompiler = true;
219
		compiler.compile(units);
219
		compiler.compile(units);
220
	} finally {
220
	} finally {
221
		inCompiler = false;
221
		inCompiler = false;
222
	}
222
	}
223
	// Check for cancel immediately after a compile, because the compiler may
223
	// Check for cancel immediately after a compile, because the compiler may
224
	// have been cancelled but without propagating the correct exception
224
	// have been cancelled but without propagating the correct exception
225
	notifier.checkCancel();
225
	notifier.checkCancel();
226
}
226
}
227
227
228
protected void createErrorFor(IResource resource, String message) {
228
protected void createErrorFor(IResource resource, String message) {
229
	try {
229
	try {
230
		IMarker marker = resource.createMarker(JavaBuilder.ProblemMarkerTag);
230
		IMarker marker = resource.createMarker(JavaBuilder.ProblemMarkerTag);
231
		marker.setAttributes(
231
		marker.setAttributes(
232
			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.CHAR_START, IMarker.CHAR_END},
232
			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.CHAR_START, IMarker.CHAR_END},
233
			new Object[] {message, new Integer(IMarker.SEVERITY_ERROR), new Integer(0), new Integer(1)});
233
			new Object[] {message, new Integer(IMarker.SEVERITY_ERROR), new Integer(0), new Integer(1)});
234
	} catch (CoreException e) {
234
	} catch (CoreException e) {
235
		throw internalException(e);
235
		throw internalException(e);
236
	}
236
	}
237
}
237
}
238
238
239
protected String extractTypeNameFrom(String sourceLocation) {
239
protected String extractTypeNameFrom(String sourceLocation) {
240
	for (int j = 0, k = sourceFolders.length; j < k; j++) {
240
	for (int j = 0, k = sourceFolders.length; j < k; j++) {
241
		String folderLocation = sourceFolders[j].getLocation().addTrailingSeparator().toString();
241
		String folderLocation = sourceFolders[j].getLocation().addTrailingSeparator().toString();
242
		if (sourceLocation.startsWith(folderLocation))
242
		if (sourceLocation.startsWith(folderLocation))
243
			return sourceLocation.substring(folderLocation.length(), sourceLocation.length() - 5); // length of ".java"
243
			return sourceLocation.substring(folderLocation.length(), sourceLocation.length() - 5); // length of ".java"
244
	}
244
	}
245
	return sourceLocation; // should not reach here
245
	return sourceLocation; // should not reach here
246
}
246
}
247
247
248
protected void finishedWith(String sourceLocation, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) throws CoreException {
248
protected void finishedWith(String sourceLocation, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) throws CoreException {
249
	if (duplicateTypeNames == null) {
249
	if (duplicateTypeNames == null) {
250
		newState.record(sourceLocation, result.qualifiedReferences, result.simpleNameReferences, mainTypeName, definedTypeNames);
250
		newState.record(sourceLocation, result.qualifiedReferences, result.simpleNameReferences, mainTypeName, definedTypeNames);
251
		return;
251
		return;
252
	}
252
	}
253
253
254
	char[][][] qualifiedRefs = result.qualifiedReferences;
254
	char[][][] qualifiedRefs = result.qualifiedReferences;
255
	char[][] simpleRefs = result.simpleNameReferences;
255
	char[][] simpleRefs = result.simpleNameReferences;
256
	// for each duplicate type p1.p2.A, add the type name A (package was already added)
256
	// for each duplicate type p1.p2.A, add the type name A (package was already added)
257
	next : for (int i = 0, dLength = duplicateTypeNames.size(); i < dLength; i++) {
257
	next : for (int i = 0, dLength = duplicateTypeNames.size(); i < dLength; i++) {
258
		char[][] compoundName = (char[][]) duplicateTypeNames.get(i);
258
		char[][] compoundName = (char[][]) duplicateTypeNames.get(i);
259
		char[] typeName = compoundName[compoundName.length - 1];
259
		char[] typeName = compoundName[compoundName.length - 1];
260
		int sLength = simpleRefs.length;
260
		int sLength = simpleRefs.length;
261
		for (int j = 0; j < sLength; j++)
261
		for (int j = 0; j < sLength; j++)
262
			if (CharOperation.equals(simpleRefs[j], typeName))
262
			if (CharOperation.equals(simpleRefs[j], typeName))
263
				continue next;
263
				continue next;
264
		System.arraycopy(simpleRefs, 0, simpleRefs = new char[sLength + 1][], 0, sLength);
264
		System.arraycopy(simpleRefs, 0, simpleRefs = new char[sLength + 1][], 0, sLength);
265
		simpleRefs[sLength] = typeName;
265
		simpleRefs[sLength] = typeName;
266
	}
266
	}
267
	newState.record(sourceLocation, qualifiedRefs, simpleRefs, mainTypeName, definedTypeNames);
267
	newState.record(sourceLocation, qualifiedRefs, simpleRefs, mainTypeName, definedTypeNames);
268
}
268
}
269
269
270
protected IContainer getOutputFolder(IPath packagePath) throws CoreException {
270
protected IContainer getOutputFolder(IPath packagePath) throws CoreException {
271
	IFolder folder = outputFolder.getFolder(packagePath);
271
	IFolder folder = outputFolder.getFolder(packagePath);
272
	if (!folder.exists()) {
272
	if (!folder.exists()) {
273
		getOutputFolder(packagePath.removeLastSegments(1));
273
		getOutputFolder(packagePath.removeLastSegments(1));
274
		folder.create(true, true, null);
274
		folder.create(true, true, null);
275
		folder.setDerived(true);
275
		folder.setDerived(true);
276
	}
276
	}
277
	return folder;
277
	return folder;
278
}
278
}
279
279
280
protected RuntimeException internalException(CoreException t) {
280
protected RuntimeException internalException(CoreException t) {
281
	ImageBuilderInternalException imageBuilderException = new ImageBuilderInternalException(t);
281
	ImageBuilderInternalException imageBuilderException = new ImageBuilderInternalException(t);
282
	if (inCompiler)
282
	if (inCompiler)
283
		return new AbortCompilation(true, imageBuilderException);
283
		return new AbortCompilation(true, imageBuilderException);
284
	return imageBuilderException;
284
	return imageBuilderException;
285
}
285
}
286
286
287
protected Compiler newCompiler() {
287
protected Compiler newCompiler() {
288
	// called once when the builder is initialized... can override if needed
288
	// called once when the builder is initialized... can override if needed
289
	return new Compiler(
289
	return new Compiler(
290
		nameEnvironment,
290
		nameEnvironment,
291
		DefaultErrorHandlingPolicies.proceedWithAllProblems(),
291
		DefaultErrorHandlingPolicies.proceedWithAllProblems(),
292
		JavaCore.getOptions(),
292
		JavaCore.getOptions(),
293
		this,
293
		this,
294
		ProblemFactory.getProblemFactory(Locale.getDefault()));
294
		ProblemFactory.getProblemFactory(Locale.getDefault()));
295
}
295
}
296
296
297
protected IResource resourceForLocation(String sourceLocation) {
297
protected IResource resourceForLocation(String sourceLocation) {
298
	return javaBuilder.workspaceRoot.getFileForLocation(new Path(sourceLocation));
298
	return javaBuilder.workspaceRoot.getFileForLocation(new Path(sourceLocation));
299
}
299
}
300
300
301
/**
301
/**
302
 * Creates a marker from each problem and adds it to the resource.
302
 * Creates a marker from each problem and adds it to the resource.
303
 * The marker is as follows:
303
 * The marker is as follows:
304
 *   - its type is T_PROBLEM
304
 *   - its type is T_PROBLEM
305
 *   - its plugin ID is the JavaBuilder's plugin ID
305
 *   - its plugin ID is the JavaBuilder's plugin ID
306
 *	 - its message is the problem's message
306
 *	 - its message is the problem's message
307
 *	 - its priority reflects the severity of the problem
307
 *	 - its priority reflects the severity of the problem
308
 *	 - its range is the problem's range
308
 *	 - its range is the problem's range
309
 *	 - it has an extra attribute "ID" which holds the problem's id
309
 *	 - it has an extra attribute "ID" which holds the problem's id
310
 */
310
 */
311
protected void storeProblemsFor(IResource resource, IProblem[] problems) throws CoreException {
311
protected void storeProblemsFor(IResource resource, IProblem[] problems) throws CoreException {
312
	if (resource == null || problems == null || problems.length == 0) return;
312
	if (resource == null || problems == null || problems.length == 0) return;
313
313
314
	String missingClassFile = null;
314
	String missingClassFile = null;
315
	for (int i = 0, length = problems.length; i < length; i++) {
315
	for (int i = 0, length = problems.length; i < length; i++) {
316
		IProblem problem = problems[i];
316
		IProblem problem = problems[i];
317
		int id = problem.getID();
317
		int id = problem.getID();
318
		switch (id) {
318
		switch (id) {
319
			case IProblem.IsClassPathCorrect :
319
			case IProblem.IsClassPathCorrect :
320
				JavaBuilder.removeProblemsFor(javaBuilder.currentProject); // make this the only problem for this project
320
				JavaBuilder.removeProblemsFor(javaBuilder.currentProject); // make this the only problem for this project
321
				String[] args = problem.getArguments();
321
				String[] args = problem.getArguments();
322
				missingClassFile = args[0];
322
				missingClassFile = args[0];
323
				break;
323
				break;
324
			case IProblem.SuperclassMustBeAClass :
324
			case IProblem.SuperclassMustBeAClass :
325
			case IProblem.SuperInterfaceMustBeAnInterface :
325
			case IProblem.SuperInterfaceMustBeAnInterface :
326
			case IProblem.HierarchyCircularitySelfReference :
326
			case IProblem.HierarchyCircularitySelfReference :
327
			case IProblem.HierarchyCircularity :
327
			case IProblem.HierarchyCircularity :
328
			case IProblem.HierarchyHasProblems :
328
			case IProblem.HierarchyHasProblems :
329
			case IProblem.SuperclassNotFound :
329
			case IProblem.SuperclassNotFound :
330
			case IProblem.SuperclassNotVisible :
330
			case IProblem.SuperclassNotVisible :
331
			case IProblem.SuperclassAmbiguous :
331
			case IProblem.SuperclassAmbiguous :
332
			case IProblem.SuperclassInternalNameProvided :
332
			case IProblem.SuperclassInternalNameProvided :
333
			case IProblem.SuperclassInheritedNameHidesEnclosingName :
333
			case IProblem.SuperclassInheritedNameHidesEnclosingName :
334
			case IProblem.InterfaceNotFound :
334
			case IProblem.InterfaceNotFound :
335
			case IProblem.InterfaceNotVisible :
335
			case IProblem.InterfaceNotVisible :
336
			case IProblem.InterfaceAmbiguous :
336
			case IProblem.InterfaceAmbiguous :
337
			case IProblem.InterfaceInternalNameProvided :
337
			case IProblem.InterfaceInternalNameProvided :
338
			case IProblem.InterfaceInheritedNameHidesEnclosingName :
338
			case IProblem.InterfaceInheritedNameHidesEnclosingName :
339
				// ensure that this file is always retrieved from source for the rest of the build
339
				// ensure that this file is always retrieved from source for the rest of the build
340
				String fileLocation = resource.getLocation().toString();
340
				String fileLocation = resource.getLocation().toString();
341
				if (!problemTypeLocations.contains(fileLocation))
341
				if (!problemTypeLocations.contains(fileLocation))
342
					problemTypeLocations.add(fileLocation);
342
					problemTypeLocations.add(fileLocation);
343
		}
343
		}
344
344
345
		IMarker marker = resource.createMarker(JavaBuilder.ProblemMarkerTag);
345
		IMarker marker = resource.createMarker(JavaBuilder.ProblemMarkerTag);
346
		marker.setAttributes(
346
		marker.setAttributes(
347
			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.ID, IMarker.CHAR_START, IMarker.CHAR_END, IMarker.LINE_NUMBER, IJavaModelMarker.ARGUMENTS},
347
			new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.ID, IMarker.CHAR_START, IMarker.CHAR_END, IMarker.LINE_NUMBER, IJavaModelMarker.ARGUMENTS},
348
			new Object[] { 
348
			new Object[] { 
349
				problem.getMessage(),
349
				problem.getMessage(),
350
				new Integer(problem.isError() ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING), 
350
				new Integer(problem.isError() ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING), 
351
				new Integer(id),
351
				new Integer(id),
352
				new Integer(problem.getSourceStart()),
352
				new Integer(problem.getSourceStart()),
353
				new Integer(problem.getSourceEnd() + 1),
353
				new Integer(problem.getSourceEnd() + 1),
354
				new Integer(problem.getSourceLineNumber()),
354
				new Integer(problem.getSourceLineNumber()),
355
				Util.getProblemArgumentsForMarker(problem.getArguments())
355
				Util.getProblemArgumentsForMarker(problem.getArguments())
356
			});
356
			});
357
357
358
		// compute a user-friendly location
358
		// compute a user-friendly location
359
		IJavaElement element = JavaCore.create(resource);
359
		IJavaElement element = JavaCore.create(resource);
360
		if (element instanceof org.eclipse.jdt.core.ICompilationUnit) { // try to find a finer grain element
360
		if (element instanceof org.eclipse.jdt.core.ICompilationUnit) { // try to find a finer grain element
361
			org.eclipse.jdt.core.ICompilationUnit unit = (org.eclipse.jdt.core.ICompilationUnit) element;
361
			org.eclipse.jdt.core.ICompilationUnit unit = (org.eclipse.jdt.core.ICompilationUnit) element;
362
			IJavaElement fragment = unit.getElementAt(problem.getSourceStart());
362
			IJavaElement fragment = unit.getElementAt(problem.getSourceStart());
363
			if (fragment != null) element = fragment;
363
			if (fragment != null) element = fragment;
364
		}
364
		}
365
		String location = null;
365
		String location = null;
366
		if (element instanceof JavaElement)
366
		if (element instanceof JavaElement)
367
			location = ((JavaElement) element).readableName();
367
			location = ((JavaElement) element).readableName();
368
		if (location != null)
368
		if (location != null)
369
			marker.setAttribute(IMarker.LOCATION, location);
369
			marker.setAttribute(IMarker.LOCATION, location);
370
		if (missingClassFile != null)
370
		if (missingClassFile != null)
371
			throw new MissingClassFileException(missingClassFile);
371
			throw new MissingClassFileException(missingClassFile);
372
	}
372
	}
373
}
373
}
374
374
375
protected void updateProblemsFor(String sourceLocation, CompilationResult result) throws CoreException {
375
protected void updateProblemsFor(String sourceLocation, CompilationResult result) throws CoreException {
376
	IProblem[] problems = result.getProblems();
376
	IProblem[] problems = result.getProblems();
377
	if (problems == null || problems.length == 0) return;
377
	if (problems == null || problems.length == 0) return;
378
378
379
	notifier.updateProblemCounts(problems);
379
	notifier.updateProblemCounts(problems);
380
	storeProblemsFor(resourceForLocation(sourceLocation), problems);
380
	storeProblemsFor(resourceForLocation(sourceLocation), problems);
381
}
381
}
382
382
383
protected char[] writeClassFile(ClassFile classFile, boolean isSecondaryType) throws CoreException {
383
protected char[] writeClassFile(ClassFile classFile, boolean isSecondaryType) throws CoreException {
384
	// Before writing out the class file, compare it to the previous file
384
	// Before writing out the class file, compare it to the previous file
385
	// If structural changes occured then add dependent source files
385
	// If structural changes occured then add dependent source files
386
	String fileName = new String(classFile.fileName()); // the qualified type name "p1/p2/A"
386
	String fileName = new String(classFile.fileName()); // the qualified type name "p1/p2/A"
387
	IPath filePath = new Path(fileName);			
387
	IPath filePath = new Path(fileName);			
388
	IContainer container = outputFolder;
388
	IContainer container = outputFolder;
389
	if (filePath.segmentCount() > 1) {
389
	if (filePath.segmentCount() > 1) {
390
		container = getOutputFolder(filePath.removeLastSegments(1));
390
		container = getOutputFolder(filePath.removeLastSegments(1));
391
		filePath = new Path(filePath.lastSegment());
391
		filePath = new Path(filePath.lastSegment());
392
	}
392
	}
393
393
394
	IFile file = container.getFile(filePath.addFileExtension(JavaBuilder.CLASS_EXTENSION));
394
	IFile file = container.getFile(filePath.addFileExtension(JavaBuilder.CLASS_EXTENSION));
395
	byte[] bytes = classFile.getBytes();
395
	byte[] bytes = classFile.getBytes();
396
	if (writeClassFileCheck(file, fileName, bytes, isSecondaryType)) {
396
	boolean exists= file.exists();
397
		if (JavaBuilder.DEBUG)
397
	if (writeClassFileCheck(file, fileName, bytes, isSecondaryType, exists)) {
398
			System.out.println("Writing class file " + file.getName());//$NON-NLS-1$
398
		if (JavaBuilder.DEBUG)
399
		file.create(new ByteArrayInputStream(bytes), IResource.FORCE, null);
399
			System.out.println("Writing class file " + file.getName());//$NON-NLS-1$
400
		file.setDerived(true);
400
		if (!exists) {
401
	} else if (JavaBuilder.DEBUG) {
401
			file.create(new ByteArrayInputStream(bytes), IResource.FORCE, null);
402
		System.out.println("Skipped over unchanged class file " + file.getName());//$NON-NLS-1$
402
		} else {
403
	}
403
			file.setContents(new ByteArrayInputStream(bytes), true, false, null);
404
	// answer the name of the class file as in Y or Y$M
404
		}
405
	return filePath.lastSegment().toCharArray();
405
		file.setDerived(true);
406
}
406
	} else if (JavaBuilder.DEBUG) {
407
407
		System.out.println("Skipped over unchanged class file " + file.getName());//$NON-NLS-1$
408
protected boolean writeClassFileCheck(IFile file, String fileName, byte[] bytes, boolean isSecondaryType) throws CoreException {
408
	}
409
	// In Incremental mode, compare the bytes against the previous file for structural changes
409
	// answer the name of the class file as in Y or Y$M
410
	return true;
410
	return filePath.lastSegment().toCharArray();
411
}
411
}
412
413
protected boolean writeClassFileCheck(IFile file, String fileName, byte[] bytes, boolean isSecondaryType, boolean exists) throws CoreException {
414
	// In Incremental mode, compare the bytes against the previous file for structural changes
415
	return true;
416
}
412
}
417
}
(-)model/org/eclipse/jdt/internal/core/builder/IncrementalImageBuilder.java (-568 / +568 lines)
Lines 1-569 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
2
 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3
 * All rights reserved. This program and the accompanying materials 
3
 * All rights reserved. This program and the accompanying materials 
4
 * are made available under the terms of the Common Public License v0.5 
4
 * are made available under the terms of the Common Public License v0.5 
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/cpl-v05.html
6
 * http://www.eclipse.org/legal/cpl-v05.html
7
 * 
7
 * 
8
 * Contributors:
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
9
 *     IBM Corporation - initial API and implementation
10
 ******************************************************************************/
10
 ******************************************************************************/
11
package org.eclipse.jdt.internal.core.builder;
11
package org.eclipse.jdt.internal.core.builder;
12
12
13
import org.eclipse.core.resources.*;
13
import org.eclipse.core.resources.*;
14
import org.eclipse.core.runtime.*;
14
import org.eclipse.core.runtime.*;
15
15
16
import org.eclipse.jdt.core.compiler.IProblem;
16
import org.eclipse.jdt.core.compiler.IProblem;
17
import org.eclipse.jdt.internal.compiler.*;
17
import org.eclipse.jdt.internal.compiler.*;
18
import org.eclipse.jdt.internal.compiler.classfmt.*;
18
import org.eclipse.jdt.internal.compiler.classfmt.*;
19
import org.eclipse.jdt.internal.compiler.util.CharOperation;
19
import org.eclipse.jdt.internal.compiler.util.CharOperation;
20
import org.eclipse.jdt.internal.core.Util;
20
import org.eclipse.jdt.internal.core.Util;
21
21
22
import java.util.*;
22
import java.util.*;
23
23
24
/**
24
/**
25
 * The incremental image builder
25
 * The incremental image builder
26
 */
26
 */
27
public class IncrementalImageBuilder extends AbstractImageBuilder {
27
public class IncrementalImageBuilder extends AbstractImageBuilder {
28
28
29
protected ArrayList locations;
29
protected ArrayList locations;
30
protected ArrayList previousLocations;
30
protected ArrayList previousLocations;
31
protected ArrayList typeNames;
31
protected ArrayList typeNames;
32
protected ArrayList qualifiedStrings;
32
protected ArrayList qualifiedStrings;
33
protected ArrayList simpleStrings;
33
protected ArrayList simpleStrings;
34
protected ArrayList secondaryTypesToRemove;
34
protected ArrayList secondaryTypesToRemove;
35
35
36
public static int MaxCompileLoop = 5; // perform a full build if it takes more than ? incremental compile loops
36
public static int MaxCompileLoop = 5; // perform a full build if it takes more than ? incremental compile loops
37
37
38
protected IncrementalImageBuilder(JavaBuilder javaBuilder) {
38
protected IncrementalImageBuilder(JavaBuilder javaBuilder) {
39
	super(javaBuilder);
39
	super(javaBuilder);
40
	this.nameEnvironment.tagAsIncrementalBuild();
40
	this.nameEnvironment.tagAsIncrementalBuild();
41
	this.newState.copyFrom(javaBuilder.lastState);
41
	this.newState.copyFrom(javaBuilder.lastState);
42
42
43
	this.locations = new ArrayList(33);
43
	this.locations = new ArrayList(33);
44
	this.previousLocations = null;
44
	this.previousLocations = null;
45
	this.typeNames = new ArrayList(33);
45
	this.typeNames = new ArrayList(33);
46
	this.qualifiedStrings = new ArrayList(33);
46
	this.qualifiedStrings = new ArrayList(33);
47
	this.simpleStrings = new ArrayList(33);
47
	this.simpleStrings = new ArrayList(33);
48
}
48
}
49
49
50
public boolean build(SimpleLookupTable deltas) {
50
public boolean build(SimpleLookupTable deltas) {
51
	// initialize builder
51
	// initialize builder
52
	// walk this project's deltas, find changed source files
52
	// walk this project's deltas, find changed source files
53
	// walk prereq projects' deltas, find changed class files & add affected source files
53
	// walk prereq projects' deltas, find changed class files & add affected source files
54
	//   use the build state # to skip the deltas for certain prereq projects
54
	//   use the build state # to skip the deltas for certain prereq projects
55
	//   ignore changed zip/jar files since they caused a full build
55
	//   ignore changed zip/jar files since they caused a full build
56
	// compile the source files & acceptResult()
56
	// compile the source files & acceptResult()
57
	// compare the produced class files against the existing ones on disk
57
	// compare the produced class files against the existing ones on disk
58
	// recompile all dependent source files of any type with structural changes or new/removed secondary type
58
	// recompile all dependent source files of any type with structural changes or new/removed secondary type
59
	// keep a loop counter to abort & perform a full build
59
	// keep a loop counter to abort & perform a full build
60
60
61
	if (JavaBuilder.DEBUG)
61
	if (JavaBuilder.DEBUG)
62
		System.out.println("INCREMENTAL build"); //$NON-NLS-1$
62
		System.out.println("INCREMENTAL build"); //$NON-NLS-1$
63
63
64
	try {
64
	try {
65
		resetCollections();
65
		resetCollections();
66
66
67
		notifier.subTask(Util.bind("build.analyzingDeltas")); //$NON-NLS-1$
67
		notifier.subTask(Util.bind("build.analyzingDeltas")); //$NON-NLS-1$
68
		IResourceDelta sourceDelta = (IResourceDelta) deltas.get(javaBuilder.currentProject);
68
		IResourceDelta sourceDelta = (IResourceDelta) deltas.get(javaBuilder.currentProject);
69
		if (sourceDelta != null)
69
		if (sourceDelta != null)
70
			if (!findSourceFiles(sourceDelta)) return false;
70
			if (!findSourceFiles(sourceDelta)) return false;
71
		notifier.updateProgressDelta(0.10f);
71
		notifier.updateProgressDelta(0.10f);
72
72
73
		Object[] keyTable = deltas.keyTable;
73
		Object[] keyTable = deltas.keyTable;
74
		Object[] valueTable = deltas.valueTable;
74
		Object[] valueTable = deltas.valueTable;
75
		for (int i = 0, l = keyTable.length; i < l; i++) {
75
		for (int i = 0, l = keyTable.length; i < l; i++) {
76
			IResourceDelta delta = (IResourceDelta) valueTable[i];
76
			IResourceDelta delta = (IResourceDelta) valueTable[i];
77
			if (delta != null) {
77
			if (delta != null) {
78
				IResource[] binaryResources = (IResource[]) javaBuilder.binaryResources.get(keyTable[i]);
78
				IResource[] binaryResources = (IResource[]) javaBuilder.binaryResources.get(keyTable[i]);
79
				if (binaryResources != null)
79
				if (binaryResources != null)
80
					if (!findAffectedSourceFiles(delta, binaryResources)) return false;
80
					if (!findAffectedSourceFiles(delta, binaryResources)) return false;
81
			}
81
			}
82
		}
82
		}
83
		notifier.updateProgressDelta(0.10f);
83
		notifier.updateProgressDelta(0.10f);
84
84
85
		notifier.subTask(Util.bind("build.analyzingSources")); //$NON-NLS-1$
85
		notifier.subTask(Util.bind("build.analyzingSources")); //$NON-NLS-1$
86
		addAffectedSourceFiles();
86
		addAffectedSourceFiles();
87
		notifier.updateProgressDelta(0.05f);
87
		notifier.updateProgressDelta(0.05f);
88
88
89
		int compileLoop = 0;
89
		int compileLoop = 0;
90
		float increment = 0.40f;
90
		float increment = 0.40f;
91
		while (locations.size() > 0) { // added to in acceptResult
91
		while (locations.size() > 0) { // added to in acceptResult
92
			if (++compileLoop > MaxCompileLoop) {
92
			if (++compileLoop > MaxCompileLoop) {
93
				if (JavaBuilder.DEBUG)
93
				if (JavaBuilder.DEBUG)
94
					System.out.println("ABORTING incremental build... exceeded loop count"); //$NON-NLS-1$
94
					System.out.println("ABORTING incremental build... exceeded loop count"); //$NON-NLS-1$
95
				return false;
95
				return false;
96
			}
96
			}
97
			notifier.checkCancel();
97
			notifier.checkCancel();
98
98
99
			String[] allSourceFiles = new String[locations.size()];
99
			String[] allSourceFiles = new String[locations.size()];
100
			locations.toArray(allSourceFiles);
100
			locations.toArray(allSourceFiles);
101
			String[] initialTypeStrings = new String[typeNames.size()];
101
			String[] initialTypeStrings = new String[typeNames.size()];
102
			typeNames.toArray(initialTypeStrings);
102
			typeNames.toArray(initialTypeStrings);
103
			resetCollections();
103
			resetCollections();
104
104
105
			workQueue.addAll(allSourceFiles);
105
			workQueue.addAll(allSourceFiles);
106
			notifier.setProgressPerCompilationUnit(increment / allSourceFiles.length);
106
			notifier.setProgressPerCompilationUnit(increment / allSourceFiles.length);
107
			increment = increment / 2;
107
			increment = increment / 2;
108
			compile(allSourceFiles, initialTypeStrings);
108
			compile(allSourceFiles, initialTypeStrings);
109
			removeSecondaryTypes();
109
			removeSecondaryTypes();
110
			addAffectedSourceFiles();
110
			addAffectedSourceFiles();
111
		}
111
		}
112
	} catch (AbortIncrementalBuildException e) {
112
	} catch (AbortIncrementalBuildException e) {
113
		// abort the incremental build and let the batch builder handle the problem
113
		// abort the incremental build and let the batch builder handle the problem
114
		if (JavaBuilder.DEBUG)
114
		if (JavaBuilder.DEBUG)
115
			System.out.println("ABORTING incremental build... cannot find " + e.qualifiedTypeName + //$NON-NLS-1$
115
			System.out.println("ABORTING incremental build... cannot find " + e.qualifiedTypeName + //$NON-NLS-1$
116
				". Could have been renamed inside its existing source file."); //$NON-NLS-1$
116
				". Could have been renamed inside its existing source file."); //$NON-NLS-1$
117
		return false;
117
		return false;
118
	} catch (CoreException e) {
118
	} catch (CoreException e) {
119
		throw internalException(e);
119
		throw internalException(e);
120
	} finally {
120
	} finally {
121
		cleanUp();
121
		cleanUp();
122
	}
122
	}
123
	return true;
123
	return true;
124
}
124
}
125
125
126
protected void addAffectedSourceFiles() {
126
protected void addAffectedSourceFiles() {
127
	if (qualifiedStrings.isEmpty() && simpleStrings.isEmpty()) return;
127
	if (qualifiedStrings.isEmpty() && simpleStrings.isEmpty()) return;
128
128
129
	// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
129
	// the qualifiedStrings are of the form 'p1/p2' & the simpleStrings are just 'X'
130
	char[][][] qualifiedNames = ReferenceCollection.internQualifiedNames(qualifiedStrings);
130
	char[][][] qualifiedNames = ReferenceCollection.internQualifiedNames(qualifiedStrings);
131
	// if a well known qualified name was found then we can skip over these
131
	// if a well known qualified name was found then we can skip over these
132
	if (qualifiedNames.length < qualifiedStrings.size())
132
	if (qualifiedNames.length < qualifiedStrings.size())
133
		qualifiedNames = null;
133
		qualifiedNames = null;
134
	char[][] simpleNames = ReferenceCollection.internSimpleNames(simpleStrings);
134
	char[][] simpleNames = ReferenceCollection.internSimpleNames(simpleStrings);
135
	// if a well known name was found then we can skip over these
135
	// if a well known name was found then we can skip over these
136
	if (simpleNames.length < simpleStrings.size())
136
	if (simpleNames.length < simpleStrings.size())
137
		simpleNames = null;
137
		simpleNames = null;
138
138
139
	Object[] keyTable = newState.references.keyTable;
139
	Object[] keyTable = newState.references.keyTable;
140
	Object[] valueTable = newState.references.valueTable;
140
	Object[] valueTable = newState.references.valueTable;
141
	next : for (int i = 0, l = keyTable.length; i < l; i++) {
141
	next : for (int i = 0, l = keyTable.length; i < l; i++) {
142
		String sourceLocation = (String) keyTable[i];
142
		String sourceLocation = (String) keyTable[i];
143
		if (sourceLocation != null && !locations.contains(sourceLocation)) {
143
		if (sourceLocation != null && !locations.contains(sourceLocation)) {
144
			if (compiledAllAtOnce && previousLocations != null && previousLocations.contains(sourceLocation))
144
			if (compiledAllAtOnce && previousLocations != null && previousLocations.contains(sourceLocation))
145
				continue next; // can skip previously compiled locations since already saw hierarchy related problems
145
				continue next; // can skip previously compiled locations since already saw hierarchy related problems
146
146
147
			ReferenceCollection refs = (ReferenceCollection) valueTable[i];
147
			ReferenceCollection refs = (ReferenceCollection) valueTable[i];
148
			if (refs.includes(qualifiedNames, simpleNames)) {
148
			if (refs.includes(qualifiedNames, simpleNames)) {
149
				// check that the file still exists... the file or its package may have been deleted
149
				// check that the file still exists... the file or its package may have been deleted
150
				IResource affectedFile = resourceForLocation(sourceLocation);
150
				IResource affectedFile = resourceForLocation(sourceLocation);
151
				if (affectedFile != null && affectedFile.exists()) {
151
				if (affectedFile != null && affectedFile.exists()) {
152
					if (JavaBuilder.DEBUG)
152
					if (JavaBuilder.DEBUG)
153
						System.out.println("  adding affected source file " + sourceLocation); //$NON-NLS-1$
153
						System.out.println("  adding affected source file " + sourceLocation); //$NON-NLS-1$
154
					locations.add(sourceLocation);
154
					locations.add(sourceLocation);
155
					typeNames.add(extractTypeNameFrom(sourceLocation));
155
					typeNames.add(extractTypeNameFrom(sourceLocation));
156
				}
156
				}
157
			}
157
			}
158
		}
158
		}
159
	}
159
	}
160
}
160
}
161
161
162
protected void addDependentsOf(IPath path, boolean hasStructuralChanges) {
162
protected void addDependentsOf(IPath path, boolean hasStructuralChanges) {
163
	if (hasStructuralChanges)
163
	if (hasStructuralChanges)
164
		newState.tagAsStructurallyChanged();
164
		newState.tagAsStructurallyChanged();
165
	// the qualifiedStrings are of the form 'p1/p1' & the simpleStrings are just 'X'
165
	// the qualifiedStrings are of the form 'p1/p1' & the simpleStrings are just 'X'
166
	path = path.setDevice(null);
166
	path = path.setDevice(null);
167
	String packageName = path.uptoSegment(path.segmentCount() - 1).toString();
167
	String packageName = path.uptoSegment(path.segmentCount() - 1).toString();
168
	if (!qualifiedStrings.contains(packageName))
168
	if (!qualifiedStrings.contains(packageName))
169
		qualifiedStrings.add(packageName);
169
		qualifiedStrings.add(packageName);
170
	String typeName = path.lastSegment();
170
	String typeName = path.lastSegment();
171
	int memberIndex = typeName.indexOf('$');
171
	int memberIndex = typeName.indexOf('$');
172
	if (memberIndex > 0)
172
	if (memberIndex > 0)
173
		typeName = typeName.substring(0, memberIndex);
173
		typeName = typeName.substring(0, memberIndex);
174
	if (!simpleStrings.contains(typeName)) {
174
	if (!simpleStrings.contains(typeName)) {
175
		if (JavaBuilder.DEBUG)
175
		if (JavaBuilder.DEBUG)
176
			System.out.println("  adding dependents of " //$NON-NLS-1$
176
			System.out.println("  adding dependents of " //$NON-NLS-1$
177
				+ typeName + " in " + packageName); //$NON-NLS-1$
177
				+ typeName + " in " + packageName); //$NON-NLS-1$
178
		simpleStrings.add(typeName);
178
		simpleStrings.add(typeName);
179
	}
179
	}
180
}
180
}
181
181
182
protected void cleanUp() {
182
protected void cleanUp() {
183
	super.cleanUp();
183
	super.cleanUp();
184
184
185
	this.locations = null;
185
	this.locations = null;
186
	this.previousLocations = null;
186
	this.previousLocations = null;
187
	this.typeNames = null;
187
	this.typeNames = null;
188
	this.qualifiedStrings = null;
188
	this.qualifiedStrings = null;
189
	this.simpleStrings = null;
189
	this.simpleStrings = null;
190
}
190
}
191
191
192
protected boolean findAffectedSourceFiles(IResourceDelta delta, IResource[] binaryResources) {
192
protected boolean findAffectedSourceFiles(IResourceDelta delta, IResource[] binaryResources) {
193
	for (int j = 0, k = binaryResources.length; j < k; j++) {
193
	for (int j = 0, k = binaryResources.length; j < k; j++) {
194
		IResource binaryResource = binaryResources[j];
194
		IResource binaryResource = binaryResources[j];
195
		// either a .class file folder or a zip/jar file
195
		// either a .class file folder or a zip/jar file
196
		if (binaryResource != null) { // skip unchanged output folder
196
		if (binaryResource != null) { // skip unchanged output folder
197
			IResourceDelta binaryDelta = delta.findMember(binaryResource.getProjectRelativePath());
197
			IResourceDelta binaryDelta = delta.findMember(binaryResource.getProjectRelativePath());
198
			if (binaryDelta != null) {
198
			if (binaryDelta != null) {
199
				if (binaryResource instanceof IFile) {
199
				if (binaryResource instanceof IFile) {
200
					if (JavaBuilder.DEBUG)
200
					if (JavaBuilder.DEBUG)
201
						System.out.println("ABORTING incremental build... found delta to jar/zip file"); //$NON-NLS-1$
201
						System.out.println("ABORTING incremental build... found delta to jar/zip file"); //$NON-NLS-1$
202
					return false; // do full build since jar file was added/removed/changed
202
					return false; // do full build since jar file was added/removed/changed
203
				}
203
				}
204
				if (binaryDelta.getKind() == IResourceDelta.ADDED || binaryDelta.getKind() == IResourceDelta.REMOVED) {
204
				if (binaryDelta.getKind() == IResourceDelta.ADDED || binaryDelta.getKind() == IResourceDelta.REMOVED) {
205
					if (JavaBuilder.DEBUG)
205
					if (JavaBuilder.DEBUG)
206
						System.out.println("ABORTING incremental build... found added/removed binary folder"); //$NON-NLS-1$
206
						System.out.println("ABORTING incremental build... found added/removed binary folder"); //$NON-NLS-1$
207
					return false; // added/removed binary folder should not make it here, but handle anyways
207
					return false; // added/removed binary folder should not make it here, but handle anyways
208
				}
208
				}
209
				int segmentCount = binaryResource.getLocation().segmentCount();
209
				int segmentCount = binaryResource.getLocation().segmentCount();
210
				IResourceDelta[] children = binaryDelta.getAffectedChildren(); // .class files from class folder
210
				IResourceDelta[] children = binaryDelta.getAffectedChildren(); // .class files from class folder
211
				for (int i = 0, length = children.length; i < length; ++i)
211
				for (int i = 0, length = children.length; i < length; ++i)
212
					findAffectedSourceFiles(children[i], segmentCount);
212
					findAffectedSourceFiles(children[i], segmentCount);
213
				notifier.checkCancel();
213
				notifier.checkCancel();
214
			}
214
			}
215
		}
215
		}
216
	}
216
	}
217
	return true;
217
	return true;
218
}
218
}
219
219
220
protected void findAffectedSourceFiles(IResourceDelta binaryDelta, int segmentCount) {
220
protected void findAffectedSourceFiles(IResourceDelta binaryDelta, int segmentCount) {
221
	// When a package becomes a type or vice versa, expect 2 deltas,
221
	// When a package becomes a type or vice versa, expect 2 deltas,
222
	// one on the folder & one on the class file
222
	// one on the folder & one on the class file
223
	IResource resource = binaryDelta.getResource();
223
	IResource resource = binaryDelta.getResource();
224
	IPath location = resource.getLocation();
224
	IPath location = resource.getLocation();
225
	switch(resource.getType()) {
225
	switch(resource.getType()) {
226
		case IResource.PROJECT :
226
		case IResource.PROJECT :
227
		case IResource.FOLDER :
227
		case IResource.FOLDER :
228
			switch (binaryDelta.getKind()) {
228
			switch (binaryDelta.getKind()) {
229
				case IResourceDelta.ADDED :
229
				case IResourceDelta.ADDED :
230
				case IResourceDelta.REMOVED :
230
				case IResourceDelta.REMOVED :
231
					IPath packagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null);
231
					IPath packagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null);
232
					String packageName = packagePath.toString();
232
					String packageName = packagePath.toString();
233
					if (binaryDelta.getKind() == IResourceDelta.ADDED) {
233
					if (binaryDelta.getKind() == IResourceDelta.ADDED) {
234
						// see if any known source file is from the same package... classpath already includes new package
234
						// see if any known source file is from the same package... classpath already includes new package
235
						if (!newState.isKnownPackage(packageName)) {
235
						if (!newState.isKnownPackage(packageName)) {
236
							if (JavaBuilder.DEBUG)
236
							if (JavaBuilder.DEBUG)
237
								System.out.println("Add dependents of added package " + packageName); //$NON-NLS-1$
237
								System.out.println("Add dependents of added package " + packageName); //$NON-NLS-1$
238
							addDependentsOf(packagePath, false);
238
							addDependentsOf(packagePath, false);
239
							return;
239
							return;
240
						}
240
						}
241
						if (JavaBuilder.DEBUG)
241
						if (JavaBuilder.DEBUG)
242
							System.out.println("Skipped dependents of added package " + packageName); //$NON-NLS-1$
242
							System.out.println("Skipped dependents of added package " + packageName); //$NON-NLS-1$
243
					} else {
243
					} else {
244
						// see if the package still exists on the classpath
244
						// see if the package still exists on the classpath
245
						if (!nameEnvironment.isPackage(packageName)) {
245
						if (!nameEnvironment.isPackage(packageName)) {
246
							if (JavaBuilder.DEBUG)
246
							if (JavaBuilder.DEBUG)
247
								System.out.println("Add dependents of removed package " + packageName); //$NON-NLS-1$
247
								System.out.println("Add dependents of removed package " + packageName); //$NON-NLS-1$
248
							addDependentsOf(packagePath, false);
248
							addDependentsOf(packagePath, false);
249
							return;
249
							return;
250
						}
250
						}
251
						if (JavaBuilder.DEBUG)
251
						if (JavaBuilder.DEBUG)
252
							System.out.println("Skipped dependents of removed package " + packageName); //$NON-NLS-1$
252
							System.out.println("Skipped dependents of removed package " + packageName); //$NON-NLS-1$
253
					}
253
					}
254
					// fall thru & traverse the sub-packages and .class files
254
					// fall thru & traverse the sub-packages and .class files
255
				case IResourceDelta.CHANGED :
255
				case IResourceDelta.CHANGED :
256
					IResourceDelta[] children = binaryDelta.getAffectedChildren();
256
					IResourceDelta[] children = binaryDelta.getAffectedChildren();
257
					for (int i = 0, length = children.length; i < length; i++)
257
					for (int i = 0, length = children.length; i < length; i++)
258
						findAffectedSourceFiles(children[i], segmentCount);
258
						findAffectedSourceFiles(children[i], segmentCount);
259
			}
259
			}
260
			return;
260
			return;
261
		case IResource.FILE :
261
		case IResource.FILE :
262
			if (JavaBuilder.CLASS_EXTENSION.equalsIgnoreCase(location.getFileExtension())) {
262
			if (JavaBuilder.CLASS_EXTENSION.equalsIgnoreCase(location.getFileExtension())) {
263
				IPath typePath = location.removeFirstSegments(segmentCount).removeFileExtension().makeRelative().setDevice(null);
263
				IPath typePath = location.removeFirstSegments(segmentCount).removeFileExtension().makeRelative().setDevice(null);
264
				switch (binaryDelta.getKind()) {
264
				switch (binaryDelta.getKind()) {
265
					case IResourceDelta.ADDED :
265
					case IResourceDelta.ADDED :
266
					case IResourceDelta.REMOVED :
266
					case IResourceDelta.REMOVED :
267
						if (JavaBuilder.DEBUG)
267
						if (JavaBuilder.DEBUG)
268
							System.out.println("Add dependents of added/removed class file " + typePath); //$NON-NLS-1$
268
							System.out.println("Add dependents of added/removed class file " + typePath); //$NON-NLS-1$
269
						addDependentsOf(typePath, false);
269
						addDependentsOf(typePath, false);
270
						return;
270
						return;
271
					case IResourceDelta.CHANGED :
271
					case IResourceDelta.CHANGED :
272
						if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0)
272
						if ((binaryDelta.getFlags() & IResourceDelta.CONTENT) == 0)
273
							return; // skip it since it really isn't changed
273
							return; // skip it since it really isn't changed
274
						if (JavaBuilder.DEBUG)
274
						if (JavaBuilder.DEBUG)
275
							System.out.println("Add dependents of changed class file " + typePath); //$NON-NLS-1$
275
							System.out.println("Add dependents of changed class file " + typePath); //$NON-NLS-1$
276
						addDependentsOf(typePath, false);
276
						addDependentsOf(typePath, false);
277
				}
277
				}
278
				return;
278
				return;
279
			}
279
			}
280
	}
280
	}
281
}
281
}
282
282
283
protected boolean findSourceFiles(IResourceDelta delta) throws CoreException {
283
protected boolean findSourceFiles(IResourceDelta delta) throws CoreException {
284
	for (int i = 0, length = sourceFolders.length; i < length; i++) {
284
	for (int i = 0, length = sourceFolders.length; i < length; i++) {
285
		IResourceDelta sourceDelta = delta.findMember(sourceFolders[i].getProjectRelativePath());
285
		IResourceDelta sourceDelta = delta.findMember(sourceFolders[i].getProjectRelativePath());
286
		if (sourceDelta != null) {
286
		if (sourceDelta != null) {
287
			if (sourceDelta.getKind() == IResourceDelta.REMOVED) {
287
			if (sourceDelta.getKind() == IResourceDelta.REMOVED) {
288
				if (JavaBuilder.DEBUG)
288
				if (JavaBuilder.DEBUG)
289
					System.out.println("ABORTING incremental build... found removed source folder"); //$NON-NLS-1$
289
					System.out.println("ABORTING incremental build... found removed source folder"); //$NON-NLS-1$
290
				return false; // removed source folder should not make it here, but handle anyways (ADDED is supported)
290
				return false; // removed source folder should not make it here, but handle anyways (ADDED is supported)
291
			}
291
			}
292
			int segmentCount = sourceFolders[i].getLocation().segmentCount();
292
			int segmentCount = sourceFolders[i].getLocation().segmentCount();
293
			IResourceDelta[] children = sourceDelta.getAffectedChildren();
293
			IResourceDelta[] children = sourceDelta.getAffectedChildren();
294
			for (int c = 0, clength = children.length; c < clength; c++)
294
			for (int c = 0, clength = children.length; c < clength; c++)
295
				findSourceFiles(children[c], segmentCount);
295
				findSourceFiles(children[c], segmentCount);
296
			notifier.checkCancel();
296
			notifier.checkCancel();
297
		}
297
		}
298
	}
298
	}
299
	return true;
299
	return true;
300
}
300
}
301
301
302
protected void findSourceFiles(IResourceDelta sourceDelta, int segmentCount) throws CoreException {
302
protected void findSourceFiles(IResourceDelta sourceDelta, int segmentCount) throws CoreException {
303
	// When a package becomes a type or vice versa, expect 2 deltas,
303
	// When a package becomes a type or vice versa, expect 2 deltas,
304
	// one on the folder & one on the source file
304
	// one on the folder & one on the source file
305
	IResource resource = sourceDelta.getResource();
305
	IResource resource = sourceDelta.getResource();
306
	IPath location = resource.getLocation();
306
	IPath location = resource.getLocation();
307
	switch(resource.getType()) {
307
	switch(resource.getType()) {
308
		case IResource.PROJECT :
308
		case IResource.PROJECT :
309
		case IResource.FOLDER :
309
		case IResource.FOLDER :
310
			switch (sourceDelta.getKind()) {
310
			switch (sourceDelta.getKind()) {
311
				case IResourceDelta.ADDED :
311
				case IResourceDelta.ADDED :
312
					IPath addedPackagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null);
312
					IPath addedPackagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null);
313
					getOutputFolder(addedPackagePath); // ensure package exists in the output folder
313
					getOutputFolder(addedPackagePath); // ensure package exists in the output folder
314
					// add dependents even when the package thinks it exists to be on the safe side
314
					// add dependents even when the package thinks it exists to be on the safe side
315
					if (JavaBuilder.DEBUG)
315
					if (JavaBuilder.DEBUG)
316
						System.out.println("Add dependents of added package " + addedPackagePath); //$NON-NLS-1$
316
						System.out.println("Add dependents of added package " + addedPackagePath); //$NON-NLS-1$
317
					addDependentsOf(addedPackagePath, true);
317
					addDependentsOf(addedPackagePath, true);
318
					// fall thru & collect all the source files
318
					// fall thru & collect all the source files
319
				case IResourceDelta.CHANGED :
319
				case IResourceDelta.CHANGED :
320
					IResourceDelta[] children = sourceDelta.getAffectedChildren();
320
					IResourceDelta[] children = sourceDelta.getAffectedChildren();
321
					for (int i = 0, length = children.length; i < length; i++)
321
					for (int i = 0, length = children.length; i < length; i++)
322
						findSourceFiles(children[i], segmentCount);
322
						findSourceFiles(children[i], segmentCount);
323
					return;
323
					return;
324
				case IResourceDelta.REMOVED :
324
				case IResourceDelta.REMOVED :
325
					IPath removedPackagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null);
325
					IPath removedPackagePath = location.removeFirstSegments(segmentCount).makeRelative().setDevice(null);
326
					for (int i = 0, length = sourceFolders.length; i < length; i++) {
326
					for (int i = 0, length = sourceFolders.length; i < length; i++) {
327
						if (sourceFolders[i].findMember(removedPackagePath) != null) {
327
						if (sourceFolders[i].findMember(removedPackagePath) != null) {
328
							// only a package fragment was removed, same as removing multiple source files
328
							// only a package fragment was removed, same as removing multiple source files
329
							getOutputFolder(removedPackagePath); // ensure package exists in the output folder
329
							getOutputFolder(removedPackagePath); // ensure package exists in the output folder
330
							IResourceDelta[] removedChildren = sourceDelta.getAffectedChildren();
330
							IResourceDelta[] removedChildren = sourceDelta.getAffectedChildren();
331
							for (int j = 0, rlength = removedChildren.length; j < rlength; j++)
331
							for (int j = 0, rlength = removedChildren.length; j < rlength; j++)
332
								findSourceFiles(removedChildren[j], segmentCount);
332
								findSourceFiles(removedChildren[j], segmentCount);
333
							return;
333
							return;
334
						}
334
						}
335
					}
335
					}
336
					IFolder removedPackageFolder = outputFolder.getFolder(removedPackagePath);
336
					IFolder removedPackageFolder = outputFolder.getFolder(removedPackagePath);
337
					if (removedPackageFolder.exists())
337
					if (removedPackageFolder.exists())
338
						removedPackageFolder.delete(IResource.FORCE, null);
338
						removedPackageFolder.delete(IResource.FORCE, null);
339
					// add dependents even when the package thinks it does not exist to be on the safe side
339
					// add dependents even when the package thinks it does not exist to be on the safe side
340
					if (JavaBuilder.DEBUG)
340
					if (JavaBuilder.DEBUG)
341
						System.out.println("Add dependents of removed package " + removedPackagePath); //$NON-NLS-1$
341
						System.out.println("Add dependents of removed package " + removedPackagePath); //$NON-NLS-1$
342
					addDependentsOf(removedPackagePath, true);
342
					addDependentsOf(removedPackagePath, true);
343
					newState.removePackage(sourceDelta);
343
					newState.removePackage(sourceDelta);
344
			}
344
			}
345
			return;
345
			return;
346
		case IResource.FILE :
346
		case IResource.FILE :
347
			String extension = location.getFileExtension();
347
			String extension = location.getFileExtension();
348
			if (JavaBuilder.JAVA_EXTENSION.equalsIgnoreCase(extension)) {
348
			if (JavaBuilder.JAVA_EXTENSION.equalsIgnoreCase(extension)) {
349
				IPath typePath = location.removeFirstSegments(segmentCount).removeFileExtension().makeRelative().setDevice(null);
349
				IPath typePath = location.removeFirstSegments(segmentCount).removeFileExtension().makeRelative().setDevice(null);
350
				String sourceLocation = location.toString();
350
				String sourceLocation = location.toString();
351
				switch (sourceDelta.getKind()) {
351
				switch (sourceDelta.getKind()) {
352
					case IResourceDelta.ADDED :
352
					case IResourceDelta.ADDED :
353
						if (JavaBuilder.DEBUG)
353
						if (JavaBuilder.DEBUG)
354
							System.out.println("Compile this added source file " + sourceLocation); //$NON-NLS-1$
354
							System.out.println("Compile this added source file " + sourceLocation); //$NON-NLS-1$
355
						locations.add(sourceLocation);
355
						locations.add(sourceLocation);
356
						String typeName = typePath.toString();
356
						String typeName = typePath.toString();
357
						typeNames.add(typeName);
357
						typeNames.add(typeName);
358
						if (!newState.isDuplicateLocation(typeName, sourceLocation)) { // adding dependents results in 2 duplicate errors
358
						if (!newState.isDuplicateLocation(typeName, sourceLocation)) { // adding dependents results in 2 duplicate errors
359
							if (JavaBuilder.DEBUG)
359
							if (JavaBuilder.DEBUG)
360
								System.out.println("Add dependents of added source file " + typeName); //$NON-NLS-1$
360
								System.out.println("Add dependents of added source file " + typeName); //$NON-NLS-1$
361
							addDependentsOf(typePath, true);
361
							addDependentsOf(typePath, true);
362
						}
362
						}
363
						return;
363
						return;
364
					case IResourceDelta.REMOVED :
364
					case IResourceDelta.REMOVED :
365
						char[][] definedTypeNames = newState.getDefinedTypeNamesFor(sourceLocation);
365
						char[][] definedTypeNames = newState.getDefinedTypeNamesFor(sourceLocation);
366
						if (definedTypeNames == null) { // defined a single type matching typePath
366
						if (definedTypeNames == null) { // defined a single type matching typePath
367
							removeClassFile(typePath);
367
							removeClassFile(typePath);
368
						} else {
368
						} else {
369
							if (JavaBuilder.DEBUG)
369
							if (JavaBuilder.DEBUG)
370
								System.out.println("Add dependents of removed source file " + typePath.toString()); //$NON-NLS-1$
370
								System.out.println("Add dependents of removed source file " + typePath.toString()); //$NON-NLS-1$
371
							addDependentsOf(typePath, true); // add dependents of the source file since it may be involved in a name collision
371
							addDependentsOf(typePath, true); // add dependents of the source file since it may be involved in a name collision
372
							if (definedTypeNames.length > 0) { // skip it if it failed to successfully define a type
372
							if (definedTypeNames.length > 0) { // skip it if it failed to successfully define a type
373
								IPath packagePath = typePath.removeLastSegments(1);
373
								IPath packagePath = typePath.removeLastSegments(1);
374
								for (int i = 0, length = definedTypeNames.length; i < length; i++)
374
								for (int i = 0, length = definedTypeNames.length; i < length; i++)
375
									removeClassFile(packagePath.append(new String(definedTypeNames[i])));
375
									removeClassFile(packagePath.append(new String(definedTypeNames[i])));
376
							}
376
							}
377
						}
377
						}
378
						newState.remove(sourceLocation);
378
						newState.remove(sourceLocation);
379
						return;
379
						return;
380
					case IResourceDelta.CHANGED :
380
					case IResourceDelta.CHANGED :
381
						if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0)
381
						if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0)
382
							return; // skip it since it really isn't changed
382
							return; // skip it since it really isn't changed
383
						if (JavaBuilder.DEBUG)
383
						if (JavaBuilder.DEBUG)
384
							System.out.println("Compile this changed source file " + sourceLocation); //$NON-NLS-1$
384
							System.out.println("Compile this changed source file " + sourceLocation); //$NON-NLS-1$
385
						locations.add(sourceLocation);
385
						locations.add(sourceLocation);
386
						typeNames.add(typePath.toString());
386
						typeNames.add(typePath.toString());
387
				}
387
				}
388
				return;
388
				return;
389
			} else if (JavaBuilder.CLASS_EXTENSION.equalsIgnoreCase(extension)) {
389
			} else if (JavaBuilder.CLASS_EXTENSION.equalsIgnoreCase(extension)) {
390
				return; // skip class files
390
				return; // skip class files
391
			} else if (hasSeparateOutputFolder) {
391
			} else if (hasSeparateOutputFolder) {
392
				if (javaBuilder.filterResource(resource)) return;
392
				if (javaBuilder.filterResource(resource)) return;
393
393
394
				// copy all other resource deltas to the output folder
394
				// copy all other resource deltas to the output folder
395
				IPath resourcePath = location.removeFirstSegments(segmentCount).makeRelative();
395
				IPath resourcePath = location.removeFirstSegments(segmentCount).makeRelative();
396
				IResource outputFile = outputFolder.getFile(resourcePath);
396
				IResource outputFile = outputFolder.getFile(resourcePath);
397
				switch (sourceDelta.getKind()) {
397
				switch (sourceDelta.getKind()) {
398
					case IResourceDelta.ADDED :
398
					case IResourceDelta.ADDED :
399
						if (outputFile.exists()) {
399
						if (outputFile.exists()) {
400
							if (JavaBuilder.DEBUG)
400
							if (JavaBuilder.DEBUG)
401
								System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$
401
								System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$
402
							outputFile.delete(IResource.FORCE, null);
402
							outputFile.delete(IResource.FORCE, null);
403
						}
403
						}
404
						if (JavaBuilder.DEBUG)
404
						if (JavaBuilder.DEBUG)
405
							System.out.println("Copying added file " + resourcePath); //$NON-NLS-1$
405
							System.out.println("Copying added file " + resourcePath); //$NON-NLS-1$
406
						getOutputFolder(resourcePath.removeLastSegments(1)); // ensure package exists in the output folder
406
						getOutputFolder(resourcePath.removeLastSegments(1)); // ensure package exists in the output folder
407
						resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
407
						resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
408
						outputFile.setDerived(true);
408
						outputFile.setDerived(true);
409
						return;
409
						return;
410
					case IResourceDelta.REMOVED :
410
					case IResourceDelta.REMOVED :
411
						if (outputFile.exists()) {
411
						if (outputFile.exists()) {
412
							if (JavaBuilder.DEBUG)
412
							if (JavaBuilder.DEBUG)
413
								System.out.println("Deleting removed file " + resourcePath); //$NON-NLS-1$
413
								System.out.println("Deleting removed file " + resourcePath); //$NON-NLS-1$
414
							outputFile.delete(IResource.FORCE, null);
414
							outputFile.delete(IResource.FORCE, null);
415
						}
415
						}
416
						return;
416
						return;
417
					case IResourceDelta.CHANGED :
417
					case IResourceDelta.CHANGED :
418
						if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0)
418
						if ((sourceDelta.getFlags() & IResourceDelta.CONTENT) == 0)
419
							return; // skip it since it really isn't changed
419
							return; // skip it since it really isn't changed
420
						if (outputFile.exists()) {
420
						if (outputFile.exists()) {
421
							if (JavaBuilder.DEBUG)
421
							if (JavaBuilder.DEBUG)
422
								System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$
422
								System.out.println("Deleting existing file " + resourcePath); //$NON-NLS-1$
423
							outputFile.delete(IResource.FORCE, null);
423
							outputFile.delete(IResource.FORCE, null);
424
						}
424
						}
425
						if (JavaBuilder.DEBUG)
425
						if (JavaBuilder.DEBUG)
426
							System.out.println("Copying changed file " + resourcePath); //$NON-NLS-1$
426
							System.out.println("Copying changed file " + resourcePath); //$NON-NLS-1$
427
						getOutputFolder(resourcePath.removeLastSegments(1)); // ensure package exists in the output folder
427
						getOutputFolder(resourcePath.removeLastSegments(1)); // ensure package exists in the output folder
428
						resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
428
						resource.copy(outputFile.getFullPath(), IResource.FORCE, null);
429
						outputFile.setDerived(true);
429
						outputFile.setDerived(true);
430
				}
430
				}
431
				return;
431
				return;
432
			}
432
			}
433
	}
433
	}
434
}
434
}
435
435
436
protected void finishedWith(String sourceLocation, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) throws CoreException {
436
protected void finishedWith(String sourceLocation, CompilationResult result, char[] mainTypeName, ArrayList definedTypeNames, ArrayList duplicateTypeNames) throws CoreException {
437
	char[][] previousTypeNames = newState.getDefinedTypeNamesFor(sourceLocation);
437
	char[][] previousTypeNames = newState.getDefinedTypeNamesFor(sourceLocation);
438
	if (previousTypeNames == null)
438
	if (previousTypeNames == null)
439
		previousTypeNames = new char[][] {mainTypeName};
439
		previousTypeNames = new char[][] {mainTypeName};
440
	IPath packagePath = null;
440
	IPath packagePath = null;
441
	next : for (int i = 0, x = previousTypeNames.length; i < x; i++) {
441
	next : for (int i = 0, x = previousTypeNames.length; i < x; i++) {
442
		char[] previous = previousTypeNames[i];
442
		char[] previous = previousTypeNames[i];
443
		for (int j = 0, y = definedTypeNames.size(); j < y; j++)
443
		for (int j = 0, y = definedTypeNames.size(); j < y; j++)
444
			if (CharOperation.equals(previous, (char[]) definedTypeNames.get(j)))
444
			if (CharOperation.equals(previous, (char[]) definedTypeNames.get(j)))
445
				continue next;
445
				continue next;
446
446
447
		if (packagePath == null)
447
		if (packagePath == null)
448
			packagePath = new Path(extractTypeNameFrom(sourceLocation)).removeLastSegments(1);
448
			packagePath = new Path(extractTypeNameFrom(sourceLocation)).removeLastSegments(1);
449
		if (secondaryTypesToRemove == null)
449
		if (secondaryTypesToRemove == null)
450
			this.secondaryTypesToRemove = new ArrayList();
450
			this.secondaryTypesToRemove = new ArrayList();
451
		secondaryTypesToRemove.add(packagePath.append(new String(previous)));
451
		secondaryTypesToRemove.add(packagePath.append(new String(previous)));
452
	}
452
	}
453
	super.finishedWith(sourceLocation, result, mainTypeName, definedTypeNames, duplicateTypeNames);
453
	super.finishedWith(sourceLocation, result, mainTypeName, definedTypeNames, duplicateTypeNames);
454
}
454
}
455
455
456
protected void removeClassFile(IPath typePath) throws CoreException {
456
protected void removeClassFile(IPath typePath) throws CoreException {
457
	if (typePath.lastSegment().indexOf('$') == -1) { // is not a nested type
457
	if (typePath.lastSegment().indexOf('$') == -1) { // is not a nested type
458
		newState.removeTypeLocation(typePath.toString());
458
		newState.removeTypeLocation(typePath.toString());
459
		// add dependents even when the type thinks it does not exist to be on the safe side
459
		// add dependents even when the type thinks it does not exist to be on the safe side
460
		if (JavaBuilder.DEBUG)
460
		if (JavaBuilder.DEBUG)
461
			System.out.println("Add dependents of removed type " + typePath); //$NON-NLS-1$
461
			System.out.println("Add dependents of removed type " + typePath); //$NON-NLS-1$
462
		addDependentsOf(typePath, true); // when member types are removed, their enclosing type is structurally changed
462
		addDependentsOf(typePath, true); // when member types are removed, their enclosing type is structurally changed
463
	}
463
	}
464
	IFile classFile = outputFolder.getFile(typePath.addFileExtension(JavaBuilder.CLASS_EXTENSION));
464
	IFile classFile = outputFolder.getFile(typePath.addFileExtension(JavaBuilder.CLASS_EXTENSION));
465
	if (classFile.exists()) {
465
	if (classFile.exists()) {
466
		if (JavaBuilder.DEBUG)
466
		if (JavaBuilder.DEBUG)
467
			System.out.println("Deleting class file of removed type " + typePath); //$NON-NLS-1$
467
			System.out.println("Deleting class file of removed type " + typePath); //$NON-NLS-1$
468
		classFile.delete(IResource.FORCE, null);
468
		classFile.delete(IResource.FORCE, null);
469
	}
469
	}
470
}
470
}
471
471
472
protected void removeSecondaryTypes() throws CoreException {
472
protected void removeSecondaryTypes() throws CoreException {
473
	if (secondaryTypesToRemove != null) { // delayed deleting secondary types until the end of the compile loop
473
	if (secondaryTypesToRemove != null) { // delayed deleting secondary types until the end of the compile loop
474
		for (int i = 0, length = secondaryTypesToRemove.size(); i < length; i++)
474
		for (int i = 0, length = secondaryTypesToRemove.size(); i < length; i++)
475
			removeClassFile((IPath) secondaryTypesToRemove.get(i));
475
			removeClassFile((IPath) secondaryTypesToRemove.get(i));
476
		this.secondaryTypesToRemove = null;
476
		this.secondaryTypesToRemove = null;
477
		if (previousLocations != null && previousLocations.size() > 1)
477
		if (previousLocations != null && previousLocations.size() > 1)
478
			this.previousLocations = null; // cannot optimize recompile case when a secondary type is deleted
478
			this.previousLocations = null; // cannot optimize recompile case when a secondary type is deleted
479
	}
479
	}
480
}
480
}
481
481
482
protected void resetCollections() {
482
protected void resetCollections() {
483
	previousLocations = locations.isEmpty() ? null : (ArrayList) locations.clone();
483
	previousLocations = locations.isEmpty() ? null : (ArrayList) locations.clone();
484
484
485
	locations.clear();
485
	locations.clear();
486
	typeNames.clear();
486
	typeNames.clear();
487
	qualifiedStrings.clear();
487
	qualifiedStrings.clear();
488
	simpleStrings.clear();
488
	simpleStrings.clear();
489
	workQueue.clear();
489
	workQueue.clear();
490
}
490
}
491
491
492
protected void updateProblemsFor(String sourceLocation, CompilationResult result) throws CoreException {
492
protected void updateProblemsFor(String sourceLocation, CompilationResult result) throws CoreException {
493
	IResource resource = resourceForLocation(sourceLocation);
493
	IResource resource = resourceForLocation(sourceLocation);
494
	IMarker[] markers = JavaBuilder.getProblemsFor(resource);
494
	IMarker[] markers = JavaBuilder.getProblemsFor(resource);
495
	IProblem[] problems = result.getProblems();
495
	IProblem[] problems = result.getProblems();
496
	if (problems == null || problems.length == 0)
496
	if (problems == null || problems.length == 0)
497
		if (markers.length == 0) return;
497
		if (markers.length == 0) return;
498
498
499
	notifier.updateProblemCounts(markers, problems);
499
	notifier.updateProblemCounts(markers, problems);
500
	JavaBuilder.removeProblemsFor(resource);
500
	JavaBuilder.removeProblemsFor(resource);
501
	storeProblemsFor(resource, problems);
501
	storeProblemsFor(resource, problems);
502
}
502
}
503
503
504
protected boolean writeClassFileCheck(IFile file, String fileName, byte[] newBytes, boolean isSecondaryType) throws CoreException {
504
protected boolean writeClassFileCheck(IFile file, String fileName, byte[] newBytes, boolean isSecondaryType, boolean exists) throws CoreException {
505
	// Before writing out the class file, compare it to the previous file
505
	// Before writing out the class file, compare it to the previous file
506
	// If structural changes occured then add dependent source files
506
	// If structural changes occured then add dependent source files
507
	if (file.exists()) {
507
	if (exists) {
508
		try {
508
		try {
509
			byte[] oldBytes = Util.getResourceContentsAsByteArray(file);
509
			byte[] oldBytes = Util.getResourceContentsAsByteArray(file);
510
			notEqual : if (newBytes.length == oldBytes.length) {
510
			notEqual : if (newBytes.length == oldBytes.length) {
511
				for (int i = newBytes.length; --i >= 0;)
511
				for (int i = newBytes.length; --i >= 0;)
512
					if (newBytes[i] != oldBytes[i]) break notEqual;
512
					if (newBytes[i] != oldBytes[i]) break notEqual;
513
				return false; // bytes are identical so skip them
513
				return false; // bytes are identical so skip them
514
			}
514
			}
515
			ClassFileReader reader = new ClassFileReader(oldBytes, file.getLocation().toString().toCharArray());
515
			ClassFileReader reader = new ClassFileReader(oldBytes, file.getLocation().toString().toCharArray());
516
			// ignore local types since they're only visible inside a single method
516
			// ignore local types since they're only visible inside a single method
517
			if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) {
517
			if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) {
518
				if (JavaBuilder.DEBUG)
518
				if (JavaBuilder.DEBUG)
519
					System.out.println("Type has structural changes " + fileName); //$NON-NLS-1$
519
					System.out.println("Type has structural changes " + fileName); //$NON-NLS-1$
520
				addDependentsOf(new Path(fileName), true);
520
				addDependentsOf(new Path(fileName), true);
521
			}
521
			}
522
		} catch (ClassFormatException e) {
522
		} catch (ClassFormatException e) {
523
			addDependentsOf(new Path(fileName), true);
523
			addDependentsOf(new Path(fileName), true);
524
		}
524
		}
525
525
526
		file.delete(IResource.FORCE, null);
526
//		file.delete(IResource.FORCE, null);
527
	} else if (isSecondaryType) {
527
	} else if (isSecondaryType) {
528
		addDependentsOf(new Path(fileName), true); // new secondary type
528
		addDependentsOf(new Path(fileName), true); // new secondary type
529
	}
529
	}
530
	return true;
530
	return true;
531
}
531
}
532
532
533
public String toString() {
533
public String toString() {
534
	return "incremental image builder for:\n\tnew state: " + newState; //$NON-NLS-1$
534
	return "incremental image builder for:\n\tnew state: " + newState; //$NON-NLS-1$
535
}
535
}
536
536
537
537
538
/* Debug helper
538
/* Debug helper
539
539
540
static void dump(IResourceDelta delta) {
540
static void dump(IResourceDelta delta) {
541
	StringBuffer buffer = new StringBuffer();
541
	StringBuffer buffer = new StringBuffer();
542
	IPath path = delta.getFullPath();
542
	IPath path = delta.getFullPath();
543
	for (int i = path.segmentCount(); --i > 0;)
543
	for (int i = path.segmentCount(); --i > 0;)
544
		buffer.append("  ");
544
		buffer.append("  ");
545
	switch (delta.getKind()) {
545
	switch (delta.getKind()) {
546
		case IResourceDelta.ADDED:
546
		case IResourceDelta.ADDED:
547
			buffer.append('+');
547
			buffer.append('+');
548
			break;
548
			break;
549
		case IResourceDelta.REMOVED:
549
		case IResourceDelta.REMOVED:
550
			buffer.append('-');
550
			buffer.append('-');
551
			break;
551
			break;
552
		case IResourceDelta.CHANGED:
552
		case IResourceDelta.CHANGED:
553
			buffer.append('*');
553
			buffer.append('*');
554
			break;
554
			break;
555
		case IResourceDelta.NO_CHANGE:
555
		case IResourceDelta.NO_CHANGE:
556
			buffer.append('=');
556
			buffer.append('=');
557
			break;
557
			break;
558
		default:
558
		default:
559
			buffer.append('?');
559
			buffer.append('?');
560
			break;
560
			break;
561
	}
561
	}
562
	buffer.append(path);
562
	buffer.append(path);
563
	System.out.println(buffer.toString());
563
	System.out.println(buffer.toString());
564
	IResourceDelta[] children = delta.getAffectedChildren();
564
	IResourceDelta[] children = delta.getAffectedChildren();
565
	for (int i = 0, length = children.length; i < length; ++i)
565
	for (int i = 0, length = children.length; i < length; ++i)
566
		dump(children[i]);
566
		dump(children[i]);
567
}
567
}
568
*/
568
*/
569
}
569
}

Return to bug 21606