/*******************************************************************************
* Copyright (c) 2006, 2011 Wind River Systems, Inc. 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:
* Markus Schorn - initial API and implementation
* Andrew Ferguson (Symbian)
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IIndexLocationConverter;
import org.eclipse.cdt.core.parser.ISignificantMacros;
import org.eclipse.cdt.internal.core.index.FileContentKey;
import org.eclipse.cdt.internal.core.index.IIndexFragment;
import org.eclipse.cdt.internal.core.index.IIndexFragmentFile;
import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation;
import org.eclipse.cdt.internal.core.index.IWritableIndexFragment;
import org.eclipse.cdt.internal.core.pdom.db.ChunkCache;
import org.eclipse.cdt.internal.core.pdom.db.DBProperties;
import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor;
import org.eclipse.cdt.internal.core.pdom.dom.IPDOMLinkageFactory;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMBinding;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMFile;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMLinkage;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMMacro;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMMacroReferenceName;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
import org.eclipse.core.runtime.CoreException;
public class WritablePDOM extends PDOM implements IWritableIndexFragment {
private boolean fClearedBecauseOfVersionMismatch= false;
private boolean fCreatedFromScratch= false;
private ASTFilePathResolver fPathResolver;
private PDOMFile fileBeingUpdated;
private PDOMFile uncommittedFile;
private FileContentKey uncommittedKey;
public WritablePDOM(File dbPath, IIndexLocationConverter locationConverter,
Map<String, IPDOMLinkageFactory> linkageFactoryMappings) throws CoreException {
this(dbPath, locationConverter, ChunkCache.getSharedInstance(), linkageFactoryMappings);
}
public WritablePDOM(File dbPath, IIndexLocationConverter locationConverter, ChunkCache cache,
Map<String, IPDOMLinkageFactory> linkageFactoryMappings) throws CoreException {
super(dbPath, locationConverter, cache, linkageFactoryMappings);
}
public void setASTFilePathResolver(ASTFilePathResolver resolver) {
fPathResolver= resolver;
}
@Override
public IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location, ISignificantMacros sigMacros) throws CoreException {
if (uncommittedKey != null && uncommittedKey.equals(new FileContentKey(linkageID, location, sigMacros)))
return uncommittedFile;
return super.addFile(linkageID, location, sigMacros);
}
@Override
public IIndexFragmentFile addUncommittedFile(int linkageID, IIndexFileLocation location,
ISignificantMacros significantMacros) throws CoreException {
uncommittedKey = new FileContentKey(linkageID, location, significantMacros);
fileBeingUpdated = getFile(linkageID, location, significantMacros);
PDOMLinkage linkage= createLinkage(linkageID);
uncommittedFile = new PDOMFile(linkage, location, linkageID, significantMacros);
return uncommittedFile;
}
@Override
public IIndexFragmentFile commitUncommittedFile() throws CoreException {
if (uncommittedFile == null)
return null;
PDOMFile file;
if (fileBeingUpdated == null) {
// New file, insert it into the index.
file = uncommittedFile;
getFileIndex().insert(file.getRecord());
} else {
// Existing file.
fileBeingUpdated.replaceContentsFrom(uncommittedFile);
file = fileBeingUpdated;
fileBeingUpdated = null;
}
fEvent.fFilesWritten.add(uncommittedKey.getLocation());
uncommittedFile = null;
uncommittedKey = null;
return file;
}
@Override
public void clearUncommittedFile() throws CoreException {
if (uncommittedFile != null) {
try {
uncommittedFile.clear();
uncommittedFile.delete();
} finally {
uncommittedFile = null;
uncommittedKey = null;
fileBeingUpdated = null;
}
}
}
@Override
public void addFileContent(IIndexFragmentFile sourceFile, IncludeInformation[] includes,
IASTPreprocessorStatement[] macros, IASTName[][] names, ASTFilePathResolver pathResolver,
YieldableIndexLock lock) throws CoreException, InterruptedException {
assert sourceFile.getIndexFragment() == this;
PDOMFile pdomFile = (PDOMFile) sourceFile;
pdomFile.addMacros(macros);
final ASTFilePathResolver origResolver= fPathResolver;
fPathResolver= pathResolver;
try {
pdomFile.addNames(names, lock);
} finally {
fPathResolver= origResolver;
}
// Includes expose the temporary file in the index, we must not yield the lock beyond this point.
pdomFile.addIncludesTo(includes);
final IIndexFileLocation location = pdomFile.getLocation();
if (location != null) {
fEvent.fClearedFiles.remove(location);
fEvent.fFilesWritten.add(location);
}
}
@Override
public void clearFile(IIndexFragmentFile file) throws CoreException {
assert file.getIndexFragment() == this;
IIndexFileLocation location = file.getLocation();
PDOMFile pdomFile = (PDOMFile) file;
pdomFile.clear();
fEvent.fClearedFiles.add(location);
}
@Override
public void clear() throws CoreException {
super.clear();
}
@Override
public void flush() throws CoreException {
super.flush();
}
@Override
public void setProperty(String propertyName, String value) throws CoreException {
if (IIndexFragment.PROPERTY_FRAGMENT_FORMAT_ID.equals(propertyName)
|| IIndexFragment.PROPERTY_FRAGMENT_FORMAT_VERSION.equals(propertyName)) {
throw new IllegalArgumentException("Property " + value + " may not be written to"); //$NON-NLS-1$ //$NON-NLS-2$
}
new DBProperties(db, PROPERTIES).setProperty(propertyName, value);
}
/**
* Uses the specified location converter to update each internal representation of a file
* location. The file index is rebuilt with the new representations. Individual PDOMFile records
* are unmoved so as to maintain referential integrity with other PDOM records.
*
* <b>A write-lock must be obtained before calling this method</b>
*
* @param newConverter the converter to use to update internal file representations
* @throws CoreException
*/
public void rewriteLocations(final IIndexLocationConverter newConverter) throws CoreException {
final List<PDOMFile> pdomfiles = new ArrayList<PDOMFile>();
getFileIndex().accept(new IBTreeVisitor() {
@Override
public int compare(long record) throws CoreException {
return 0;
}
@Override
public boolean visit(long record) throws CoreException {
PDOMFile file = PDOMFile.recreateFile(WritablePDOM.this, record);
pdomfiles.add(file);
return true;
}
});
clearFileIndex();
final List<PDOMFile> notConverted = new ArrayList<PDOMFile>();
for (PDOMFile file : pdomfiles) {
String internalFormat = newConverter.toInternalFormat(file.getLocation());
if (internalFormat != null) {
file.setInternalLocation(internalFormat);
getFileIndex().insert(file.getRecord());
} else {
notConverted.add(file);
}
}
// remove content where converter returns null
for (PDOMFile file : notConverted) {
file.convertIncludersToUnresolved();
file.clear();
}
}
boolean isClearedBecauseOfVersionMismatch() {
return fClearedBecauseOfVersionMismatch;
}
void setClearedBecauseOfVersionMismatch(boolean clearedBecauseOfVersionMismatch) {
fClearedBecauseOfVersionMismatch = clearedBecauseOfVersionMismatch;
}
boolean isCreatedFromScratch() {
return fCreatedFromScratch;
}
void setCreatedFromScratch(boolean createdFromScratch) {
fCreatedFromScratch = createdFromScratch;
}
@Override
protected final boolean isPermanentlyReadOnly() {
return false;
}
public PDOMFile getFileForASTNode(int linkageID, IASTNode node) throws CoreException {
if (fPathResolver != null && node != null) {
IASTFileLocation loc= node.getFileLocation();
if (loc != null) {
ISignificantMacros sigMacros= getSignificantMacros(node, loc);
if (sigMacros != null) {
IIndexFileLocation location = fPathResolver.resolveASTPath(loc.getFileName());
if (uncommittedKey != null && uncommittedKey.equals(new FileContentKey(linkageID, location, sigMacros)))
return fileBeingUpdated != null ? fileBeingUpdated : uncommittedFile;
return getFile(linkageID, location, sigMacros);
}
}
}
return null;
}
private ISignificantMacros getSignificantMacros(IASTNode node, IASTFileLocation loc) throws CoreException {
IASTPreprocessorIncludeStatement owner= loc.getContextInclusionStatement();
if (owner != null)
return owner.getSignificantMacros();
IASTTranslationUnit tu = node.getTranslationUnit();
if (tu != null)
return tu.getSignificantMacros();
return null;
}
@Override
public boolean hasLastingDefinition(PDOMBinding binding) throws CoreException {
if (fileBeingUpdated == null) {
return binding.hasDefinition();
}
// Definitions in fileBeingUpdated will soon go away, so look for a definition elsewhere.
for (PDOMName name = binding.getFirstDefinition(); name != null; name = name.getNextInBinding()) {
if (!fileBeingUpdated.getPDOM().equals(name.getPDOM()) ||
fileBeingUpdated.getRecord() != name.getFileRecord()) {
return true;
}
}
return false;
}
@Override
protected boolean isCommitted(PDOMName name) throws CoreException {
return uncommittedFile == null || !uncommittedFile.getPDOM().equals(name.getPDOM()) ||
uncommittedFile.getRecord() != name.getFileRecord();
}
@Override
protected boolean isCommitted(PDOMMacro name) throws CoreException {
return uncommittedFile == null || !uncommittedFile.getPDOM().equals(name.getPDOM()) ||
uncommittedFile.getRecord() != name.getFileRecord();
}
@Override
protected boolean isCommitted(PDOMMacroReferenceName name) throws CoreException {
return uncommittedFile == null || !uncommittedFile.getPDOM().equals(name.getPDOM()) ||
uncommittedFile.getRecord() != name.getFileRecord();
}
/* (non-Javadoc)
* @see org.eclipse.cdt.internal.core.index.IWritableIndexFragment#getDatabaseSizeBytes()
*/
public long getDatabaseSizeBytes() {
return getDB().getSizeBytes();
}
}