Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: b1df1c7ac125438d4f4acc74488757b85d4c0cd5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
/*******************************************************************************
 * Copyright (c) 2005, 2007 QNX Software Systems 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
 *
 * Contributors:
 *    QNX - Initial API and implementation
 *    Markus Schorn (Wind River Systems)
 *    Andrew Ferguson (Symbian)
 *******************************************************************************/
package org.eclipse.cdt.internal.core.pdom.dom;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IIndexInclude;
import org.eclipse.cdt.core.index.IIndexLocationConverter;
import org.eclipse.cdt.core.index.IIndexMacro;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IIndexFragmentFile;
import org.eclipse.cdt.internal.core.index.IWritableIndexFragment;
import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.WritablePDOM;
import org.eclipse.cdt.internal.core.pdom.db.BTree;
import org.eclipse.cdt.internal.core.pdom.db.Database;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
import org.eclipse.cdt.internal.core.pdom.db.IString;
import org.eclipse.core.runtime.CoreException;

/**
 * Represents a file containing names.
 * 
 * @author Doug Schaefer
 *
 */
public class PDOMFile implements IIndexFragmentFile {
	private final PDOM pdom;
	private final int record;

	private static final int FIRST_NAME = 0;
	private static final int FIRST_INCLUDE = 4;
	private static final int FIRST_INCLUDED_BY = 8;
	private static final int FIRST_MACRO = 12;
	private static final int LOCATION_REPRESENTATION = 16;
	private static final int TIME_STAMP = 20;
	private static final int SCANNER_CONFIG_HASH= 28;

	private static final int RECORD_SIZE = 32;

	public static class Comparator implements IBTreeComparator {
		private Database db;

		public Comparator(Database db) {
			this.db = db;
		}

		public int compare(int record1, int record2) throws CoreException {
			IString name1 = db.getString(db.getInt(record1 + LOCATION_REPRESENTATION));
			IString name2 = db.getString(db.getInt(record2 + LOCATION_REPRESENTATION));
			return name1.compare(name2, true);
		}
	}

	public PDOMFile(PDOM pdom, int record) {
		this.pdom = pdom;
		this.record = record;
	}

	public PDOMFile(PDOM pdom, IIndexFileLocation location) throws CoreException {
		this.pdom = pdom;
		Database db = pdom.getDB();
		record = db.malloc(RECORD_SIZE);
		String locationString = pdom.getLocationConverter().toInternalFormat(location);
		if(locationString==null)
			throw new CoreException(CCorePlugin.createStatus(Messages.getString("PDOMFile.toInternalProblem")+location.getURI())); //$NON-NLS-1$
		IString locationDBString = db.newString(locationString);
		db.putInt(record + LOCATION_REPRESENTATION, locationDBString.getRecord());
		db.putLong(record + TIME_STAMP, 0);
		setFirstName(null);
		setFirstInclude(null);
		setFirstIncludedBy(null);
	}

	public int getRecord() {
		return record;
	}

	public boolean equals(Object obj) {
		if (obj == this)
			return true;
		if (obj instanceof PDOMFile) {
			PDOMFile other = (PDOMFile)obj;
			return pdom.equals(other.pdom) && record == other.record;
		}
		return false;
	}

	public final int hashCode() {
		return System.identityHashCode(pdom) + 41*record;
	}
	
	/**
	 * Directly changes this record's internal location string. The format
	 * of this string is unspecified in general and is determined by the 
	 * associated IIndexLocationConverter
	 * @param newName
	 * @throws CoreException
	 */
	public void setInternalLocation(String internalLocation) throws CoreException {
		Database db = pdom.getDB();
		int oldRecord = db.getInt(record + LOCATION_REPRESENTATION);
		db.free(oldRecord);
		db.putInt(record + LOCATION_REPRESENTATION, db.newString(internalLocation).getRecord());
	}

	public long getTimestamp() throws CoreException {
		Database db = pdom.getDB();
		return db.getLong(record + TIME_STAMP);
	}

	public void setTimestamp(long timestamp) throws CoreException {
		Database db= pdom.getDB();
		db.putLong(record + TIME_STAMP, timestamp);
	}

	public int getScannerConfigurationHashcode() throws CoreException {
		Database db = pdom.getDB();
		return db.getInt(record + SCANNER_CONFIG_HASH);
	}

	public void setScannerConfigurationHashcode(int hashcode) throws CoreException {
		Database db= pdom.getDB();
		db.putInt(record + SCANNER_CONFIG_HASH, hashcode);
	}

	public PDOMName getFirstName() throws CoreException {
		int namerec = pdom.getDB().getInt(record + FIRST_NAME);
		return namerec != 0 ? new PDOMName(pdom, namerec) : null;
	}

	public void setFirstName(PDOMName firstName) throws CoreException {
		int namerec = firstName != null ? firstName.getRecord() : 0;
		pdom.getDB().putInt(record + FIRST_NAME, namerec);
	}

	public PDOMInclude getFirstInclude() throws CoreException {
		int increc = pdom.getDB().getInt(record + FIRST_INCLUDE);
		return increc != 0 ? new PDOMInclude(pdom, increc) : null;
	}

	public void setFirstInclude(PDOMInclude include) throws CoreException {
		int rec = include != null ? include.getRecord() : 0;
		pdom.getDB().putInt(record + FIRST_INCLUDE, rec);
	}

	public PDOMInclude getFirstIncludedBy() throws CoreException {
		int rec = pdom.getDB().getInt(record + FIRST_INCLUDED_BY);
		return rec != 0 ? new PDOMInclude(pdom, rec) : null;
	}
	
	public IIndexInclude getParsedInContext() throws CoreException {
		return getFirstIncludedBy();
	}

	public void setFirstIncludedBy(PDOMInclude includedBy) throws CoreException {
		int rec = includedBy != null ? includedBy.getRecord() : 0;
		pdom.getDB().putInt(record + FIRST_INCLUDED_BY, rec);
	}

	public PDOMMacro getFirstMacro() throws CoreException {
		int rec = pdom.getDB().getInt(record + FIRST_MACRO);
		return rec != 0 ? new PDOMMacro(pdom, rec) : null;
	}

	public void setFirstMacro(PDOMMacro macro) throws CoreException {
		int rec = macro != null ? macro.getRecord() : 0;
		pdom.getDB().putInt(record + FIRST_MACRO, rec);
	}

	public void addMacros(IASTPreprocessorMacroDefinition[] macros) throws CoreException {
		assert getFirstMacro() == null;

		PDOMMacro lastMacro= null;
		for (int i = 0; i < macros.length; i++) {
			IASTPreprocessorMacroDefinition macro = macros[i];
			PDOMMacro pdomMacro = new PDOMMacro(pdom, macro, this);
			if (lastMacro == null) {
				setFirstMacro(pdomMacro);
			}
			else {
				lastMacro.setNextMacro(pdomMacro);
			}
			lastMacro= pdomMacro;
			pdom.afterAddMacro(pdomMacro);
		}
	}

	public void addNames(IASTName[][] names) throws CoreException {
		assert getFirstName() == null;
		HashMap nameCache= new HashMap();
		PDOMName lastName= null;
		for (int i = 0; i < names.length; i++) {
			IASTName[] name = names[i];
			if (name[0] != null) {
				PDOMName caller= (PDOMName) nameCache.get(name[1]);
				PDOMName pdomName = createPDOMName(name[0], caller);
				if (pdomName != null) {
					nameCache.put(name[0], pdomName);
					if (lastName == null) {
						setFirstName(pdomName);
					}
					else {
						lastName.setNextInFile(pdomName);
					}
					lastName= pdomName;
				}
			}
		}
	}

	private PDOMName createPDOMName(IASTName name, PDOMName caller) {
		PDOMName result= null;
		try {
			PDOMBinding binding = ((WritablePDOM) pdom).addBinding(name);
			if (binding != null) {
				result= new PDOMName(pdom, name, this, binding, caller);
				binding.getLinkageImpl().onCreateName(result, name);
			}
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
		return result;
	}

	public void clear(Collection contextsRemoved) throws CoreException {
		// Remove the includes
		PDOMInclude include = getFirstInclude();
		while (include != null) {
			PDOMInclude nextInclude = include.getNextInIncludes();
			if (contextsRemoved != null && include.getPrevInIncludedByRecord() == 0) {
				contextsRemoved.add(include.getIncludesLocation());
			}
			include.delete();
			include = nextInclude;
		}
		setFirstInclude(include);

		// Delete all the macros in this file
		PDOMMacro macro = getFirstMacro();
		while (macro != null) {
			pdom.beforeRemoveMacro(macro);
			PDOMMacro nextMacro = macro.getNextMacro();
			macro.delete();
			macro = nextMacro;
		}
		setFirstMacro(null);

		// Delete all the names in this file
		ArrayList names= new ArrayList();
		PDOMName name = getFirstName();
		while (name != null) {
			names.add(name);
			name.getPDOMBinding().getLinkageImpl().onDeleteName(name);
			name= name.getNextInFile();
		}
		
		for (Iterator iterator = names.iterator(); iterator.hasNext();) {
			name = (PDOMName) iterator.next();
			name.delete();
		}
		setFirstName(null);
	}

	public void addIncludesTo(IncludeInformation[] includeInfos) throws CoreException {
		assert getFirstInclude() == null;

		PDOMInclude lastInclude= null;
		for (int i = 0; i < includeInfos.length; i++) {
			final IncludeInformation info= includeInfos[i];
			final PDOMFile targetFile= (PDOMFile) info.fTargetFile;
			
			PDOMInclude pdomInclude = new PDOMInclude(pdom, info.fStatement, this, targetFile);
			if (targetFile != null) {
				assert targetFile.getIndexFragment() instanceof IWritableIndexFragment;
				targetFile.addIncludedBy(pdomInclude, info.fIsContext);
			}
			if (lastInclude == null) {
				setFirstInclude(pdomInclude);
			}
			else {
				lastInclude.setNextInIncludes(pdomInclude);
			}
			lastInclude= pdomInclude;
		}
	}

	public void addIncludedBy(PDOMInclude include, boolean isContext) throws CoreException {
		PDOMInclude firstIncludedBy = getFirstIncludedBy();
		if (firstIncludedBy != null) {
			if (isContext) {
				setFirstIncludedBy(include);
				include.setNextInIncludedBy(firstIncludedBy);
				firstIncludedBy.setPrevInIncludedBy(include);				
			}
			else {
				PDOMInclude secondIncludedBy= firstIncludedBy.getNextInIncludedBy();
				if (secondIncludedBy != null) {
					include.setNextInIncludedBy(secondIncludedBy);
					secondIncludedBy.setPrevInIncludedBy(include);
				}
				include.setPrevInIncludedBy(firstIncludedBy);
				firstIncludedBy.setNextInIncludedBy(include);
			}
		}
		else {
			setFirstIncludedBy(include);
		}
	}

	public IIndexInclude[] getIncludes() throws CoreException {
		List result= new ArrayList();
		PDOMInclude include = getFirstInclude();
		while (include != null) {
			result.add(include);
			include = include.getNextInIncludes();
		}
		return (IIndexInclude[]) result.toArray(new IIndexInclude[result.size()]);
	}

	public IIndexMacro[] getMacros() throws CoreException {
		List result= new ArrayList();
		PDOMMacro macro = getFirstMacro();
		while (macro != null) {
			result.add(macro);
			macro = macro.getNextMacro();
		}
		return (IIndexMacro[]) result.toArray(new IIndexMacro[result.size()]);
	}

	public IIndexFragment getIndexFragment() {
		return pdom;
	}

	public IIndexName[] findNames(int offset, int length) throws CoreException {
		ArrayList result= new ArrayList();
		for (PDOMName name= getFirstName(); name != null; name= name.getNextInFile()) {
			int nameOffset=  name.getNodeOffset();
			if (nameOffset >= offset) {
				if (nameOffset == offset) {
					if (name.getNodeLength() == length) {
						result.add(name);
					}
				}
				else if (name.isReference()) { 
					// names are ordered, but callers are inserted before
					// their references
					break;
				}
			}

		}
		return (IIndexName[]) result.toArray(new IIndexName[result.size()]);
	}

	public static IIndexFragmentFile findFile(PDOM pdom, BTree btree, IIndexFileLocation location, IIndexLocationConverter strategy)
			throws CoreException {
		String internalRepresentation= strategy.toInternalFormat(location);
		int record= 0;
		if(internalRepresentation!=null) {
			Finder finder = new Finder(pdom.getDB(), internalRepresentation);
			btree.accept(finder);
			record= finder.getRecord();
		}
		return record != 0 ? new PDOMFile(pdom, record) : null;
	}
	
	private static class Finder implements IBTreeVisitor {
		private final Database db;
		private final String rawKey;
		private int record;

		public Finder(Database db, String internalRepresentation)
			throws CoreException
		{
			this.db = db;
			this.rawKey = internalRepresentation;
		}

		public int compare(int record) throws CoreException {
			IString name = db.getString(db.getInt(record + PDOMFile.LOCATION_REPRESENTATION));
			return name.compare(rawKey, true);
		}

		public boolean visit(int record) throws CoreException {
			this.record = record;
			return false;
		}

		public int getRecord() {
			return record;
		}
	}

	public IIndexFileLocation getLocation() throws CoreException {
		Database db = pdom.getDB();
		String raw = db.getString(db.getInt(record + LOCATION_REPRESENTATION)).getString();
		IIndexFileLocation result = pdom.getLocationConverter().fromInternalFormat(raw);
		if(result==null)
			throw new CoreException(CCorePlugin.createStatus(Messages.getString("PDOMFile.toExternalProblem")+raw)); //$NON-NLS-1$
		return result;
	}
	
	public boolean hasNames() throws CoreException {
		return getFirstName()!=null || getFirstMacro() != null || getFirstInclude() != null;
	}

	public void convertIncludersToUnresolved() throws CoreException {
		// Remove the includes
		PDOMInclude include = getFirstIncludedBy();
		while (include != null) {
			PDOMInclude nextInclude = include.getNextInIncludedBy();
			include.convertToUnresolved();
			include.setNextInIncludedBy(null);
			include.setPrevInIncludedBy(null);
			include = nextInclude;
		}
		setFirstIncludedBy(null);
	}
}

Back to the top