mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Bug 337486 - AbstractIndexAstChecker allows AST to outlive index read lock.
This commit is contained in:
parent
c24ce74075
commit
87ae09ee72
11 changed files with 477 additions and 327 deletions
|
@ -6,7 +6,7 @@
|
|||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.internal.checkers;
|
||||
|
||||
|
@ -14,7 +14,6 @@ import java.util.Iterator;
|
|||
|
||||
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
|
||||
import org.eclipse.cdt.codan.core.cxx.model.AbstractAstFunctionChecker;
|
||||
import org.eclipse.cdt.codan.core.cxx.model.CxxModelsCache;
|
||||
import org.eclipse.cdt.codan.core.model.IProblem;
|
||||
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
|
||||
import org.eclipse.cdt.codan.core.model.cfg.ICfgData;
|
||||
|
@ -156,7 +155,7 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
|
|||
* @return
|
||||
*/
|
||||
protected boolean endsWithNoExitNode(IASTFunctionDefinition func) {
|
||||
IControlFlowGraph graph = CxxModelsCache.getInstance().getControlFlowGraph(func);
|
||||
IControlFlowGraph graph = getModelCache().getControlFlowGraph(func);
|
||||
Iterator<IExitNode> exitNodeIterator = graph.getExitNodeIterator();
|
||||
boolean noexitop = false;
|
||||
for (; exitNodeIterator.hasNext();) {
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.model;
|
||||
|
||||
import org.eclipse.cdt.codan.core.CodanCorePlugin;
|
||||
import org.eclipse.cdt.codan.core.cxx.Activator;
|
||||
import org.eclipse.cdt.codan.core.model.AbstractCheckerWithProblemPreferences;
|
||||
import org.eclipse.cdt.codan.core.model.ICheckerInvocationContext;
|
||||
import org.eclipse.cdt.codan.core.model.IProblem;
|
||||
import org.eclipse.cdt.codan.core.model.IProblemLocation;
|
||||
import org.eclipse.cdt.codan.core.model.IProblemLocationFactory;
|
||||
|
@ -23,114 +24,87 @@ import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.index.IIndex;
|
||||
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
|
||||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
|
||||
/**
|
||||
* Convenience implementation of checker that work on index based ast of a c/c++
|
||||
* Convenience implementation of checker that works on index-based AST of a C/C++
|
||||
* program.
|
||||
*
|
||||
* Clients may extend this class.
|
||||
*/
|
||||
public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblemPreferences implements ICAstChecker,
|
||||
IRunnableInEditorChecker {
|
||||
private IFile file;
|
||||
private ICodanCommentMap commentmap;
|
||||
public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblemPreferences
|
||||
implements ICAstChecker, IRunnableInEditorChecker {
|
||||
private CxxModelsCache modelCache;
|
||||
|
||||
protected IFile getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
protected IProject getProject() {
|
||||
return file == null ? null : file.getProject();
|
||||
}
|
||||
|
||||
void processFile(IFile file) throws CoreException, InterruptedException {
|
||||
commentmap = null;
|
||||
IASTTranslationUnit ast = CxxModelsCache.getInstance().getAst(file);
|
||||
if (ast == null)
|
||||
return;
|
||||
// lock the index for read access
|
||||
IIndex index = CxxModelsCache.getInstance().getIndex(file);
|
||||
index.acquireReadLock();
|
||||
try {
|
||||
// traverse the ast using the visitor pattern.
|
||||
this.file = file;
|
||||
processAst(ast);
|
||||
} finally {
|
||||
this.file = null;
|
||||
index.releaseReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean processResource(IResource resource) {
|
||||
@Override
|
||||
public synchronized boolean processResource(IResource resource) throws OperationCanceledException {
|
||||
if (!shouldProduceProblems(resource))
|
||||
return false;
|
||||
if (resource instanceof IFile) {
|
||||
IFile file = (IFile) resource;
|
||||
if (!(resource instanceof IFile))
|
||||
return true;
|
||||
|
||||
processFile((IFile) resource);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processFile(IFile file) throws OperationCanceledException {
|
||||
ICheckerInvocationContext context = getContext();
|
||||
synchronized (context) {
|
||||
modelCache = context.get(CxxModelsCache.class);
|
||||
if (modelCache == null) {
|
||||
ICElement celement = CoreModel.getDefault().create(file);
|
||||
if (!(celement instanceof ITranslationUnit)) {
|
||||
return;
|
||||
}
|
||||
modelCache = new CxxModelsCache((ITranslationUnit) celement);
|
||||
context.add(modelCache);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
IASTTranslationUnit ast = modelCache.getAST();
|
||||
if (ast != null) {
|
||||
synchronized (ast) {
|
||||
processAst(ast);
|
||||
}
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
Activator.log(e);
|
||||
} finally {
|
||||
modelCache = null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see IRunnableInEditorChecker#processModel(Object, ICheckerInvocationContext)
|
||||
*/
|
||||
public synchronized void processModel(Object model, ICheckerInvocationContext context) {
|
||||
if (model instanceof IASTTranslationUnit) {
|
||||
setContext(context);
|
||||
IASTTranslationUnit ast = (IASTTranslationUnit) model;
|
||||
synchronized (context) {
|
||||
modelCache = context.get(CxxModelsCache.class);
|
||||
if (modelCache == null) {
|
||||
modelCache = new CxxModelsCache(ast);
|
||||
context.add(modelCache);
|
||||
}
|
||||
}
|
||||
try {
|
||||
processFile(file);
|
||||
} catch (CoreException e) {
|
||||
CodanCorePlugin.log(e);
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void reportProblem(String id, IASTNode astNode, Object... args) {
|
||||
IProblemLocation loc = getProblemLocation(astNode);
|
||||
if (loc!=null) reportProblem(id, loc, args);
|
||||
}
|
||||
public void reportProblem(IProblem problem, IASTNode astNode, Object... args) {
|
||||
IProblemLocation loc = getProblemLocation(astNode);
|
||||
if (loc!=null) reportProblem(problem, loc, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
protected IProblemLocation getProblemLocation(IASTNode astNode) {
|
||||
IASTFileLocation astLocation = astNode.getFileLocation();
|
||||
IPath location = new Path(astLocation.getFileName());
|
||||
IFile astFile = ResourceLookup.selectFileForLocation(location, getProject());
|
||||
if (astFile == null) {
|
||||
astFile = file;
|
||||
}
|
||||
if (astFile == null) {
|
||||
Activator.log("Cannot resolve location: " + location); //$NON-NLS-1$
|
||||
return null;
|
||||
}
|
||||
return getProblemLocation(astNode, astLocation, astFile);
|
||||
}
|
||||
|
||||
private IProblemLocation getProblemLocation(IASTNode astNode, IASTFileLocation astLocation, IFile astFile) {
|
||||
int line = astLocation.getStartingLineNumber();
|
||||
IProblemLocationFactory locFactory = getRuntime().getProblemLocationFactory();
|
||||
if (hasMacroLocation(astNode) && astNode instanceof IASTName) {
|
||||
IASTImageLocation imageLocation = ((IASTName) astNode).getImageLocation();
|
||||
if (imageLocation != null) {
|
||||
int start = imageLocation.getNodeOffset();
|
||||
int end = start + imageLocation.getNodeLength();
|
||||
return locFactory.createProblemLocation(astFile, start, end, line);
|
||||
processAst(ast);
|
||||
} finally {
|
||||
modelCache = null;
|
||||
setContext(null);
|
||||
}
|
||||
}
|
||||
if (line == astLocation.getEndingLineNumber()) {
|
||||
return locFactory.createProblemLocation(astFile, astLocation.getNodeOffset(),
|
||||
astLocation.getNodeOffset() + astLocation.getNodeLength(), line);
|
||||
}
|
||||
return locFactory.createProblemLocation(astFile, line);
|
||||
}
|
||||
|
||||
private boolean hasMacroLocation(IASTNode astNode) {
|
||||
return astNode.getNodeLocations().length == 1 && astNode.getNodeLocations()[0] instanceof IASTMacroExpansionLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -138,40 +112,60 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker#processModel
|
||||
* (java.lang.Object)
|
||||
*/
|
||||
@SuppressWarnings("restriction")
|
||||
public synchronized void processModel(Object model) {
|
||||
if (model instanceof IASTTranslationUnit) {
|
||||
CxxModelsCache.getInstance().clearCash();
|
||||
IASTTranslationUnit ast = (IASTTranslationUnit) model;
|
||||
IPath location = new Path(ast.getFilePath());
|
||||
IFile astFile = ResourceLookup.selectFileForLocation(location, getProject());
|
||||
file = astFile;
|
||||
commentmap = null;
|
||||
processAst(ast);
|
||||
public void reportProblem(String id, IASTNode astNode, Object... args) {
|
||||
IProblemLocation loc = getProblemLocation(astNode);
|
||||
if (loc != null)
|
||||
reportProblem(id, loc, args);
|
||||
}
|
||||
|
||||
public void reportProblem(IProblem problem, IASTNode astNode, Object... args) {
|
||||
IProblemLocation loc = getProblemLocation(astNode);
|
||||
if (loc != null)
|
||||
reportProblem(problem, loc, args);
|
||||
}
|
||||
|
||||
protected IProblemLocation getProblemLocation(IASTNode astNode) {
|
||||
IASTFileLocation astLocation = astNode.getFileLocation();
|
||||
return getProblemLocation(astNode, astLocation);
|
||||
}
|
||||
|
||||
private IProblemLocation getProblemLocation(IASTNode astNode, IASTFileLocation astLocation) {
|
||||
int line = astLocation.getStartingLineNumber();
|
||||
IProblemLocationFactory locFactory = getRuntime().getProblemLocationFactory();
|
||||
if (hasMacroLocation(astNode) && astNode instanceof IASTName) {
|
||||
IASTImageLocation imageLocation = ((IASTName) astNode).getImageLocation();
|
||||
if (imageLocation != null) {
|
||||
int start = imageLocation.getNodeOffset();
|
||||
int end = start + imageLocation.getNodeLength();
|
||||
return locFactory.createProblemLocation(getFile(), start, end, line);
|
||||
}
|
||||
}
|
||||
if (line == astLocation.getEndingLineNumber()) {
|
||||
return locFactory.createProblemLocation(getFile(), astLocation.getNodeOffset(),
|
||||
astLocation.getNodeOffset() + astLocation.getNodeLength(), line);
|
||||
}
|
||||
return locFactory.createProblemLocation(getFile(), line);
|
||||
}
|
||||
|
||||
private boolean hasMacroLocation(IASTNode astNode) {
|
||||
return astNode.getNodeLocations().length == 1 &&
|
||||
astNode.getNodeLocations()[0] instanceof IASTMacroExpansionLocation;
|
||||
}
|
||||
|
||||
protected IFile getFile() {
|
||||
return modelCache.getFile();
|
||||
}
|
||||
|
||||
protected IProject getProject() {
|
||||
IFile file = getFile();
|
||||
return file == null ? null : file.getProject();
|
||||
}
|
||||
|
||||
protected CxxModelsCache getModelCache() {
|
||||
return modelCache;
|
||||
}
|
||||
|
||||
protected ICodanCommentMap getCommentMap() {
|
||||
if (commentmap == null) {
|
||||
try {
|
||||
CxxModelsCache cxxcache = CxxModelsCache.getInstance();
|
||||
synchronized (cxxcache) {
|
||||
IASTTranslationUnit ast = cxxcache.getAst(getFile());
|
||||
commentmap = cxxcache.getCommentedNodeMap(ast);
|
||||
return commentmap;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Activator.log(e);
|
||||
}
|
||||
}
|
||||
return commentmap;
|
||||
return modelCache.getCommentedNodeMap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.cxx.model;
|
||||
|
||||
|
@ -15,32 +16,71 @@ 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.ICElement;
|
||||
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 {
|
||||
private IFile file;
|
||||
private IASTTranslationUnit ast;
|
||||
private ITranslationUnit tu;
|
||||
private IIndex index;
|
||||
private WeakHashMap<IASTFunctionDefinition, IControlFlowGraph> cfgmap = new WeakHashMap<IASTFunctionDefinition, IControlFlowGraph>(0);
|
||||
private ICodanCommentMap commentMap;
|
||||
private static CxxModelsCache instance = new CxxModelsCache();
|
||||
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;
|
||||
|
||||
public static CxxModelsCache getInstance() {
|
||||
return instance;
|
||||
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) {
|
||||
|
@ -48,85 +88,67 @@ public class CxxModelsCache {
|
|||
if (cfg != null)
|
||||
return cfg;
|
||||
cfg = CxxControlFlowGraph.build(func);
|
||||
if (cfgmap.size() > 20) { // if too many function better drop the cash XXX should be LRU
|
||||
// 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 IASTTranslationUnit getAst(IFile file) throws CoreException, InterruptedException {
|
||||
if (file.equals(this.file)) {
|
||||
return ast;
|
||||
public synchronized ICodanCommentMap getCommentedNodeMap() {
|
||||
return getCommentedNodeMap(tu);
|
||||
}
|
||||
|
||||
public synchronized ICodanCommentMap getCommentedNodeMap(ITranslationUnit tu) {
|
||||
if (!this.tu.equals(tu)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// create translation unit and access index
|
||||
ICElement celement = CoreModel.getDefault().create(file);
|
||||
if (!(celement instanceof ITranslationUnit))
|
||||
return null; // not a C/C++ file
|
||||
clearCash();
|
||||
this.file = file;
|
||||
//System.err.println("Making ast for "+file);
|
||||
tu = (ITranslationUnit) celement;
|
||||
index = CCorePlugin.getIndexManager().getIndex(tu.getCProject());
|
||||
// lock the index for read access
|
||||
index.acquireReadLock();
|
||||
try {
|
||||
// create index based ast
|
||||
ast = tu.getAST(index, ITranslationUnit.AST_SKIP_INDEXED_HEADERS);
|
||||
if (ast == null)
|
||||
return null;//
|
||||
return ast;
|
||||
} finally {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized ICodanCommentMap getCommentedNodeMap(IASTTranslationUnit ast) {
|
||||
if (this.ast == ast) {
|
||||
try {
|
||||
index.acquireReadLock();
|
||||
try {
|
||||
commentMap = new CodanCommentMap(ASTCommenter.getCommentedNodeMap(ast));
|
||||
} finally {
|
||||
index.releaseReadLock();
|
||||
}
|
||||
return commentMap;
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Not cached");
|
||||
}
|
||||
|
||||
public ICodanCommentMap getCommentedNodeMap(IFile file) {
|
||||
try {
|
||||
IASTTranslationUnit ast = getAst(file);
|
||||
return getCommentedNodeMap(ast);
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
} catch (CoreException e) {
|
||||
Activator.log(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cash for current file
|
||||
*/
|
||||
public void clearCash() {
|
||||
cfgmap.clear();
|
||||
ast = null;
|
||||
tu = null;
|
||||
index = null;
|
||||
commentMap = null;
|
||||
}
|
||||
|
||||
public synchronized IIndex getIndex(IFile file) throws CoreException, InterruptedException {
|
||||
if (file.equals(this.file)) {
|
||||
return index;
|
||||
}
|
||||
getAst(file); // to init variables
|
||||
return index;
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
if (!disposed)
|
||||
Activator.log("CxxASTCache was not disposed."); //$NON-NLS-1$
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,11 @@ import junit.framework.TestCase;
|
|||
|
||||
import org.eclipse.cdt.codan.core.CodanRuntime;
|
||||
import org.eclipse.cdt.codan.core.model.IChecker;
|
||||
import org.eclipse.cdt.codan.core.model.ICheckerInvocationContext;
|
||||
import org.eclipse.cdt.codan.core.model.IProblemLocation;
|
||||
import org.eclipse.cdt.codan.core.model.IProblemReporter;
|
||||
import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker;
|
||||
import org.eclipse.cdt.codan.internal.core.CheckerInvocationContext;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTProblem;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.parser.ISourceCodeParser;
|
||||
|
@ -71,7 +73,7 @@ public abstract class CodanFastCxxAstTestCase extends TestCase {
|
|||
|
||||
/**
|
||||
* @return
|
||||
*
|
||||
*
|
||||
*/
|
||||
public IASTTranslationUnit parse(String code) {
|
||||
return parse(code, isCpp() ? ParserLanguage.CPP : ParserLanguage.C, true);
|
||||
|
@ -116,7 +118,7 @@ public abstract class CodanFastCxxAstTestCase extends TestCase {
|
|||
/**
|
||||
* Override if any of code that test tried to parse has errors, otherwise
|
||||
* parse method would assert
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected boolean hasCodeErrors() {
|
||||
|
@ -153,11 +155,13 @@ public abstract class CodanFastCxxAstTestCase extends TestCase {
|
|||
codanproblems.add(new ProblemInstance(problemId, loc, args));
|
||||
}
|
||||
});
|
||||
ICheckerInvocationContext context = new CheckerInvocationContext(null);
|
||||
try {
|
||||
IChecker checker = getChecker();
|
||||
((IRunnableInEditorChecker) checker).processModel(tu);
|
||||
((IRunnableInEditorChecker) checker).processModel(tu, context);
|
||||
} finally {
|
||||
CodanRuntime.getInstance().setProblemReporter(problemReporter);
|
||||
context.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2010 Alena Laskavaia
|
||||
* 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
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.model;
|
||||
|
||||
|
@ -14,22 +15,21 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.codan.core.CodanRuntime;
|
||||
import org.eclipse.cdt.codan.internal.core.CheckerInvocationContext;
|
||||
import org.eclipse.cdt.codan.internal.core.CheckersRegistry;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
|
||||
/**
|
||||
* Convenience implementation of IChecker interface. Has a default
|
||||
* implementation for common methods.
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractChecker implements IChecker {
|
||||
protected String name;
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
protected ICheckerInvocationContext context;
|
||||
private ICheckerInvocationContext context;
|
||||
private IProblemReporter problemReporter;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
|
@ -47,7 +47,7 @@ public abstract class AbstractChecker implements IChecker {
|
|||
|
||||
/**
|
||||
* Reports a simple problem for given file and line
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* - problem id
|
||||
* @param file
|
||||
|
@ -66,7 +66,7 @@ public abstract class AbstractChecker implements IChecker {
|
|||
/**
|
||||
* Finds an instance of problem by given id, in user profile registered for
|
||||
* specific file
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* - problem id
|
||||
* @param file
|
||||
|
@ -104,7 +104,7 @@ public abstract class AbstractChecker implements IChecker {
|
|||
/**
|
||||
* Reports a simple problem for given file and line, error message comes
|
||||
* from problem definition
|
||||
*
|
||||
*
|
||||
* @param id
|
||||
* - problem id
|
||||
* @param file
|
||||
|
@ -121,16 +121,12 @@ public abstract class AbstractChecker implements IChecker {
|
|||
* @since 2.0
|
||||
*/
|
||||
public IProblemReporter getProblemReporter() {
|
||||
try {
|
||||
return getContext().getProblemReporter();
|
||||
} catch (Exception e) {
|
||||
return CodanRuntime.getInstance().getProblemReporter();
|
||||
}
|
||||
return problemReporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to return codan runtime
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected CodanRuntime getRuntime() {
|
||||
|
@ -139,7 +135,7 @@ public abstract class AbstractChecker implements IChecker {
|
|||
|
||||
/**
|
||||
* Convenience method to create and return instance of IProblemLocation
|
||||
*
|
||||
*
|
||||
* @param file
|
||||
* - file where problem is found
|
||||
* @param line
|
||||
|
@ -152,7 +148,7 @@ public abstract class AbstractChecker implements IChecker {
|
|||
|
||||
/**
|
||||
* Convenience method to create and return instance of IProblemLocation
|
||||
*
|
||||
*
|
||||
* @param file
|
||||
* - file where problem is found
|
||||
* @param startChar
|
||||
|
@ -176,7 +172,7 @@ public abstract class AbstractChecker implements IChecker {
|
|||
|
||||
/**
|
||||
* report a problem
|
||||
*
|
||||
*
|
||||
* @param problemId - id of a problem
|
||||
* @param loc - problem location
|
||||
* @param args - extra problem arguments
|
||||
|
@ -186,56 +182,72 @@ public abstract class AbstractChecker implements IChecker {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get invocation context.
|
||||
*
|
||||
* Returns the invocation context.
|
||||
*
|
||||
* @return checker invocation context
|
||||
*
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public ICheckerInvocationContext getContext() {
|
||||
protected ICheckerInvocationContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the invocation context. Usually called by codan builder.
|
||||
* Object that calls this should also synchronize of checker object
|
||||
* to prevent multi-thread access to a running context
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public void setContext(ICheckerInvocationContext context) {
|
||||
protected void setContext(ICheckerInvocationContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
public boolean before(IResource resource) {
|
||||
IChecker checker = this;
|
||||
public void before(IResource resource) {
|
||||
IProblemReporter problemReporter = CodanRuntime.getInstance().getProblemReporter();
|
||||
IProblemReporter sessionReporter = problemReporter;
|
||||
this.problemReporter = problemReporter;
|
||||
if (problemReporter instanceof IProblemReporterSessionPersistent) {
|
||||
// create session problem reporter
|
||||
sessionReporter = ((IProblemReporterSessionPersistent) problemReporter).createReporter(resource, checker);
|
||||
((IProblemReporterSessionPersistent) sessionReporter).start();
|
||||
this.problemReporter = ((IProblemReporterSessionPersistent) problemReporter).createReporter(resource, this);
|
||||
((IProblemReporterSessionPersistent) this.problemReporter).start();
|
||||
} else if (problemReporter instanceof IProblemReporterPersistent) {
|
||||
// delete markers if checker can possibly run on this
|
||||
// resource this way if checker is not enabled markers would be
|
||||
// deleted too
|
||||
((IProblemReporterPersistent) problemReporter).deleteProblems(resource, checker);
|
||||
((IProblemReporterPersistent) problemReporter).deleteProblems(resource, this);
|
||||
}
|
||||
((AbstractChecker) checker).setContext(new CheckerInvocationContext(resource, sessionReporter));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
*/
|
||||
public boolean after(IResource resource) {
|
||||
if (getContext().getProblemReporter() instanceof IProblemReporterSessionPersistent) {
|
||||
// delete general markers
|
||||
((IProblemReporterSessionPersistent) getContext().getProblemReporter()).done();
|
||||
public void after(IResource resource) {
|
||||
if (problemReporter instanceof IProblemReporterSessionPersistent) {
|
||||
// Delete general markers
|
||||
((IProblemReporterSessionPersistent) problemReporter).done();
|
||||
}
|
||||
problemReporter = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource the resource to process.
|
||||
* @return true if framework should traverse children of the resource and
|
||||
* run this checkers on them again.
|
||||
* @throws OperationCanceledException if the checker was interrupted.
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract boolean processResource(IResource resource) throws OperationCanceledException;
|
||||
|
||||
/**
|
||||
* @see IChecker#processResource(IResource, ICheckerInvocationContext)
|
||||
* @since 2.0
|
||||
*/
|
||||
public synchronized boolean processResource(IResource resource, ICheckerInvocationContext context)
|
||||
throws OperationCanceledException {
|
||||
this.setContext(context);
|
||||
try {
|
||||
return processResource(resource);
|
||||
} finally {
|
||||
this.setContext(null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2010 Alena Laskavaia
|
||||
* 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
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.model;
|
||||
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
|
||||
/**
|
||||
* Interface that checker must implement (through extending directly or
|
||||
* indirectly {@link AbstractChecker}.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as part
|
||||
* of a work in progress. There is no guarantee that this API will work or that
|
||||
* it will remain the same.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @noextend This interface is not intended to be extended by clients.
|
||||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
* Extend {@link AbstractChecker} class instead.
|
||||
|
@ -29,25 +31,36 @@ import org.eclipse.core.resources.IResource;
|
|||
public interface IChecker {
|
||||
/**
|
||||
* Main method that checker should implement that actually detects errors
|
||||
*
|
||||
* @param resource
|
||||
* - resource to run on
|
||||
*
|
||||
* @param resource the resource to run on.
|
||||
* @param context container object for sharing data between different checkers
|
||||
* operating on the resource.
|
||||
* @return true if framework should traverse children of the resource and
|
||||
* run this checkers on them again
|
||||
*/
|
||||
boolean processResource(IResource resource);
|
||||
|
||||
/**
|
||||
* run this checkers on them again.
|
||||
* @throws OperationCanceledException if the checker was interrupted.
|
||||
* @since 2.0
|
||||
*/
|
||||
boolean before(IResource resource);
|
||||
boolean processResource(IResource resource, ICheckerInvocationContext context)
|
||||
throws OperationCanceledException;
|
||||
|
||||
/**
|
||||
* Called before processing a resource.
|
||||
*
|
||||
* @param resource the resource that is about to be processed.
|
||||
* @since 2.0
|
||||
*/
|
||||
boolean after(IResource resource);
|
||||
void before(IResource resource);
|
||||
|
||||
/**
|
||||
* Called before processing a resource.
|
||||
*
|
||||
* @param resource the resource that has been processed.
|
||||
* @since 2.0
|
||||
*/
|
||||
void after(IResource resource);
|
||||
|
||||
/**
|
||||
* @return the problem reporter.
|
||||
* @since 2.0
|
||||
*/
|
||||
IProblemReporter getProblemReporter();
|
||||
|
@ -56,10 +69,9 @@ public interface IChecker {
|
|||
* Implement this method to trim down type of resource you are interested
|
||||
* in, usually it will be c/c++ files only. This method should be
|
||||
* independent from current user preferences.
|
||||
*
|
||||
* @param resource
|
||||
* - resource to run on
|
||||
* @return - true if checker should be run on this resource
|
||||
*
|
||||
* @param resource the resource to run on.
|
||||
* @return true if checker should be run on this resource.
|
||||
*/
|
||||
boolean enabledInContext(IResource resource);
|
||||
|
||||
|
@ -70,7 +82,7 @@ public interface IChecker {
|
|||
* {@link IRunnableInEditorChecker}.
|
||||
* Checker should return false if check is non-trivial and takes a long
|
||||
* time.
|
||||
*
|
||||
*
|
||||
* @return true if need to be run in editor as user types, and false
|
||||
* otherwise
|
||||
*/
|
||||
|
|
|
@ -1,34 +1,60 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009,2010 QNX Software Systems
|
||||
* Copyright (c) 2009, 2011 QNX Software Systems
|
||||
* 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 Software Systems (Alena Laskavaia) - initial API and implementation
|
||||
* QNX Software Systems (Alena Laskavaia) - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.model;
|
||||
|
||||
import org.eclipse.core.resources.IResource;
|
||||
|
||||
/**
|
||||
* Since there is only one instance of checker available this object keeps
|
||||
* track of invocation context - which would usually contain resource and some
|
||||
* other object that checker require
|
||||
* Context object that can be used to store data shared between different
|
||||
* checkers operating on the same resource. The context and all objects stored
|
||||
* in it are disposed of at the end of processing of a resource. May store
|
||||
* objects of arbitrary types but only a single instance per type.
|
||||
* <p>
|
||||
* Implementations of this interface are guaranteed to be thread-safe.
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as part
|
||||
* of a work in progress. There is no guarantee that this API will work or that
|
||||
* it will remain the same.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @noextend This interface is not intended to be extended by clients.
|
||||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
*
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ICheckerInvocationContext {
|
||||
public interface ICheckerInvocationContext extends ICodanDisposable {
|
||||
/**
|
||||
* @return the resource this context is associated with.
|
||||
*/
|
||||
IResource getResource();
|
||||
|
||||
IProblemReporter getProblemReporter();
|
||||
/**
|
||||
* Returns the object of the given type. Lookup by an interface or a superclass
|
||||
* is also possible, but in case when there are multiple objects implementing
|
||||
* the interface, an arbitrary one will be returned.
|
||||
*
|
||||
* @param <T> the type of the object.
|
||||
* @param objectClass the class of the object to retrieve.
|
||||
* @return the object of the given type, or <code>null</code> if not present in the context.
|
||||
*/
|
||||
public <T> T get(Class<T> objectClass);
|
||||
|
||||
/**
|
||||
* Adds an object to the context. The context accepts only a single
|
||||
* instance of each class.
|
||||
*
|
||||
* @param <T> the type of the object.
|
||||
* @param object the object to add to the context.
|
||||
* @throws IllegalArgumentException if an attempt is made to add second instance
|
||||
* of the same class.
|
||||
*/
|
||||
public <T extends ICodanDisposable> void add(T object);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011 Google, 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:
|
||||
* Sergey Prigogin (Google) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.model;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An interface for objects that own resources that have to be explicitly
|
||||
* released. A disposable object is guaranteed to receive a {@link #dispose()} call
|
||||
* when it is not longer needed. At this point, the object must release all resources
|
||||
* and detach all listeners. A disposable object can only be disposed once; it cannot
|
||||
* be reused.
|
||||
* </p>
|
||||
* <p>
|
||||
* This interface can be extended or implemented by clients.
|
||||
* </p>
|
||||
* @since 2.0
|
||||
*/
|
||||
public interface ICodanDisposable {
|
||||
/**
|
||||
* Disposes of the cache. This method has to be called exactly once during
|
||||
* the life cycle of the cache.
|
||||
*/
|
||||
public void dispose();
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009, 2010 Alena Laskavaia
|
||||
* 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
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.core.model;
|
||||
|
||||
|
@ -18,12 +19,15 @@ package org.eclipse.cdt.codan.core.model;
|
|||
* of a work in progress. There is no guarantee that this API will work or that
|
||||
* it will remain the same.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @noextend This interface is not intended to be extended by clients.
|
||||
*/
|
||||
public interface IRunnableInEditorChecker {
|
||||
/**
|
||||
* @param model
|
||||
* @param model the model to check.
|
||||
* @param context container object for sharing data between different checkers
|
||||
* operating on the model.
|
||||
* @since 2.0
|
||||
*/
|
||||
void processModel(Object model);
|
||||
void processModel(Object model, ICheckerInvocationContext context);
|
||||
}
|
||||
|
|
|
@ -1,40 +1,78 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009,2010 QNX Software Systems
|
||||
* Copyright (c) 2009, 2011 QNX Software Systems
|
||||
* 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 Software Systems (Alena Laskavaia) - initial API and implementation
|
||||
* QNX Software Systems (Alena Laskavaia) - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.internal.core;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.codan.core.model.ICheckerInvocationContext;
|
||||
import org.eclipse.cdt.codan.core.model.IProblemReporter;
|
||||
import org.eclipse.cdt.codan.core.model.ICodanDisposable;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
|
||||
/**
|
||||
* Implementation of ICheckerInvocationContext
|
||||
* Implementation of ICheckerInvocationContext.
|
||||
* This class is thread-safe.
|
||||
*/
|
||||
public class CheckerInvocationContext implements ICheckerInvocationContext {
|
||||
private IResource resource;
|
||||
private IProblemReporter sessionReporter;
|
||||
private final IResource resource;
|
||||
private final Map<Class<?>, Object> objectStorage;
|
||||
|
||||
/**
|
||||
* @param resource
|
||||
* @param sessionReporter
|
||||
* @param resource the resource this context is associated with.
|
||||
*/
|
||||
public CheckerInvocationContext(IResource resource, IProblemReporter sessionReporter) {
|
||||
public CheckerInvocationContext(IResource resource) {
|
||||
this.resource = resource;
|
||||
this.sessionReporter = sessionReporter;
|
||||
objectStorage = new HashMap<Class<?>, Object>();
|
||||
}
|
||||
|
||||
public IResource getResource() {
|
||||
return resource;
|
||||
}
|
||||
|
||||
public IProblemReporter getProblemReporter() {
|
||||
return sessionReporter;
|
||||
@SuppressWarnings("unchecked")
|
||||
public synchronized <T> T get(Class<T> objectClass) {
|
||||
T object = (T) objectStorage.get(objectClass);
|
||||
if (object != null)
|
||||
return object;
|
||||
for (Map.Entry<Class<?>, Object> entry : objectStorage.entrySet()) {
|
||||
if (objectClass.isAssignableFrom(entry.getKey()))
|
||||
return (T) entry.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see ICheckerInvocationContext#add(Object)
|
||||
*/
|
||||
public synchronized <T extends ICodanDisposable> void add(T object) {
|
||||
Object old = objectStorage.put(object.getClass(), object);
|
||||
if (old != null && object != old) {
|
||||
objectStorage.put(old.getClass(), old); // Restore old value.
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see IDisposableCache#dispose()
|
||||
*/
|
||||
public void dispose() {
|
||||
for (Map.Entry<Class<?>, Object> entry : objectStorage.entrySet()) {
|
||||
Object obj = entry.getValue();
|
||||
if (obj instanceof ICodanDisposable) {
|
||||
((ICodanDisposable) obj).dispose();
|
||||
}
|
||||
}
|
||||
objectStorage.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Alena Laskavaia - initial API and implementation
|
||||
* Sergey Prigogin (Google)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.codan.internal.core;
|
||||
|
||||
|
@ -17,6 +18,7 @@ import org.eclipse.cdt.codan.core.Messages;
|
|||
import org.eclipse.cdt.codan.core.model.CheckerLaunchMode;
|
||||
import org.eclipse.cdt.codan.core.model.Checkers;
|
||||
import org.eclipse.cdt.codan.core.model.IChecker;
|
||||
import org.eclipse.cdt.codan.core.model.ICheckerInvocationContext;
|
||||
import org.eclipse.cdt.codan.core.model.ICodanBuilder;
|
||||
import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker;
|
||||
import org.eclipse.core.resources.IContainer;
|
||||
|
@ -27,6 +29,7 @@ import org.eclipse.core.resources.IResourceDeltaVisitor;
|
|||
import org.eclipse.core.resources.IncrementalProjectBuilder;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.core.runtime.SubProgressMonitor;
|
||||
|
||||
/**
|
||||
|
@ -34,7 +37,7 @@ import org.eclipse.core.runtime.SubProgressMonitor;
|
|||
*/
|
||||
public class CodanBuilder extends IncrementalProjectBuilder implements ICodanBuilder {
|
||||
/**
|
||||
* codan builder id
|
||||
* Codan builder id
|
||||
*/
|
||||
public static final String BUILDER_ID = "org.eclipse.cdt.codan.core.codanBuilder"; //$NON-NLS-1$
|
||||
|
||||
|
@ -126,39 +129,43 @@ public class CodanBuilder extends IncrementalProjectBuilder implements ICodanBui
|
|||
// System.err.println("processing " + resource);
|
||||
monitor.beginTask(Messages.CodanBuilder_Code_Analysis_On + resource, checkers + memsize * tick);
|
||||
try {
|
||||
for (IChecker checker : chegistry) {
|
||||
try {
|
||||
if (monitor.isCanceled())
|
||||
return;
|
||||
if (doesCheckerSupportLaunchMode(checker, checkerLaunchMode)
|
||||
&& checker.enabledInContext(resource)
|
||||
&& chegistry.isCheckerEnabledForLaunchMode(checker, resource, checkerLaunchMode)) {
|
||||
synchronized (checker) {
|
||||
try {
|
||||
checker.before(resource);
|
||||
if (chegistry.isCheckerEnabled(checker, resource)) {
|
||||
//long time = System.currentTimeMillis();
|
||||
if (checkerLaunchMode == CheckerLaunchMode.RUN_AS_YOU_TYPE) {
|
||||
((IRunnableInEditorChecker) checker).processModel(model);
|
||||
} else {
|
||||
checker.processResource(resource);
|
||||
ICheckerInvocationContext context = new CheckerInvocationContext(resource);
|
||||
try {
|
||||
for (IChecker checker : chegistry) {
|
||||
try {
|
||||
if (monitor.isCanceled())
|
||||
return;
|
||||
if (doesCheckerSupportLaunchMode(checker, checkerLaunchMode)
|
||||
&& checker.enabledInContext(resource)
|
||||
&& chegistry.isCheckerEnabledForLaunchMode(checker, resource, checkerLaunchMode)) {
|
||||
synchronized (checker) {
|
||||
try {
|
||||
checker.before(resource);
|
||||
if (chegistry.isCheckerEnabled(checker, resource)) {
|
||||
//long time = System.currentTimeMillis();
|
||||
if (checkerLaunchMode == CheckerLaunchMode.RUN_AS_YOU_TYPE) {
|
||||
((IRunnableInEditorChecker) checker).processModel(model, context);
|
||||
} else {
|
||||
checker.processResource(resource, context);
|
||||
}
|
||||
// System.err.println("Checker "
|
||||
// + checker.getClass() + " worked "
|
||||
// + (System.currentTimeMillis() - time));
|
||||
}
|
||||
// System.err
|
||||
// .println("Checker "
|
||||
// + checker.getClass()
|
||||
// + " worked "
|
||||
// + (System
|
||||
// .currentTimeMillis() - time));
|
||||
} finally {
|
||||
checker.after(resource);
|
||||
}
|
||||
} finally {
|
||||
checker.after(resource);
|
||||
}
|
||||
}
|
||||
monitor.worked(1);
|
||||
} catch (OperationCanceledException e) {
|
||||
return;
|
||||
} catch (Throwable e) {
|
||||
CodanCorePlugin.log(e);
|
||||
}
|
||||
monitor.worked(1);
|
||||
} catch (Throwable e) {
|
||||
CodanCorePlugin.log(e);
|
||||
}
|
||||
} finally {
|
||||
context.dispose();
|
||||
}
|
||||
if (resource instanceof IContainer
|
||||
&& (checkerLaunchMode == CheckerLaunchMode.RUN_ON_FULL_BUILD || checkerLaunchMode == CheckerLaunchMode.RUN_ON_DEMAND)) {
|
||||
|
|
Loading…
Add table
Reference in a new issue