/*******************************************************************************
* Copyright (c) 2009, 2010 Alena Laskavaia
* 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:
* Alena Laskavaia - initial API and implementation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.codan.core.cxx.model;
import java.util.WeakHashMap;
import org.eclipse.cdt.codan.core.cxx.Activator;
import org.eclipse.cdt.codan.core.cxx.internal.model.CodanCommentMap;
import org.eclipse.cdt.codan.core.cxx.internal.model.cfg.CxxControlFlowGraph;
import org.eclipse.cdt.codan.core.model.ICodanDisposable;
import org.eclipse.cdt.codan.core.model.cfg.IControlFlowGraph;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.ASTCommenter;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.OperationCanceledException;
/**
* Cache data models for resource so checkers can share it
*/
public class CxxModelsCache implements ICodanDisposable {
private static final int PARSE_MODE = ITranslationUnit.AST_SKIP_ALL_HEADERS
| ITranslationUnit.AST_CONFIGURE_USING_SOURCE_CONTEXT
| ITranslationUnit.AST_SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS
| ITranslationUnit.AST_PARSE_INACTIVE_CODE;
private final IFile file;
private final ITranslationUnit tu;
private IASTTranslationUnit ast;
private IIndex index;
private final WeakHashMap<IASTFunctionDefinition, IControlFlowGraph> cfgmap;
private ICodanCommentMap commentMap;
private boolean disposed;
CxxModelsCache(ITranslationUnit tu) {
this.tu = tu;
this.file = tu != null ? (IFile) tu.getResource() : null;
cfgmap = new WeakHashMap<IASTFunctionDefinition, IControlFlowGraph>(0);
}
CxxModelsCache(IASTTranslationUnit ast) {
this(ast.getOriginatingTranslationUnit());
this.ast = ast;
}
public IASTTranslationUnit getAST() throws OperationCanceledException, CoreException {
return getAST(tu);
}
public IASTTranslationUnit getAST(ITranslationUnit tu)
throws OperationCanceledException, CoreException {
if (!this.tu.equals(tu)) {
throw new IllegalArgumentException();
}
if (ast == null) {
getIndex();
ast= tu.getAST(index, PARSE_MODE);
}
return ast;
}
public ITranslationUnit getTranslationUnit() {
return tu;
}
public IFile getFile() {
return file;
}
public synchronized IControlFlowGraph getControlFlowGraph(IASTFunctionDefinition func) {
IControlFlowGraph cfg = cfgmap.get(func);
if (cfg != null)
return cfg;
cfg = CxxControlFlowGraph.build(func);
// TODO(Alena Laskavaia): Change to LRU.
if (cfgmap.size() > 20) { // if too many function better drop the cash
cfgmap.clear();
}
cfgmap.put(func, cfg);
return cfg;
}
public synchronized ICodanCommentMap getCommentedNodeMap() {
return getCommentedNodeMap(tu);
}
public synchronized ICodanCommentMap getCommentedNodeMap(ITranslationUnit tu) {
if (!this.tu.equals(tu)) {
throw new IllegalArgumentException();
}
if (commentMap == null) {
if (ast == null) {
throw new IllegalStateException("getCommentedNodeMap called before getAST"); //$NON-NLS-1$
}
commentMap = new CodanCommentMap(ASTCommenter.getCommentedNodeMap(ast));
}
return commentMap;
}
/**
* Returns the index that can be safely used for reading until the cache is disposed.
*
* @return The index.
*/
public synchronized IIndex getIndex() throws CoreException, OperationCanceledException {
Assert.isTrue(!disposed, "CxxASTCache is already disposed."); //$NON-NLS-1$
if (this.index == null) {
ICProject[] projects = CoreModel.getDefault().getCModel().getCProjects();
IIndex index = CCorePlugin.getIndexManager().getIndex(projects);
try {
index.acquireReadLock();
} catch (InterruptedException e) {
throw new OperationCanceledException();
}
this.index = index;
}
return this.index;
}
/**
* @see IDisposable#dispose()
* This method should not be called concurrently with any other method.
*/
public void dispose() {
Assert.isTrue(!disposed, "CxxASTCache.dispose() called more than once."); //$NON-NLS-1$
disposed = true;
if (index != null) {
index.releaseReadLock();
}
}
@Override
protected void finalize() throws Throwable {
if (!disposed)
Activator.log("CxxASTCache was not disposed."); //$NON-NLS-1$
super.finalize();
}
}