/******************************************************************************* * Copyright (c) 2009, 2011 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 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; import org.eclipse.cdt.codan.core.model.IRunnableInEditorChecker; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTImageLocation; 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.IASTNodeLocation; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; 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.OperationCanceledException; /** * 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 CxxModelsCache modelCache; @Override public synchronized boolean processResource(IResource resource) throws OperationCanceledException { if (!shouldProduceProblems(resource)) return false; 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 { processAst(ast); } finally { modelCache = null; setContext(null); } } } @Override public boolean runInEditor() { 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); } 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 (enclosedInMacroExpansion(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); } protected static boolean enclosedInMacroExpansion(IASTNode node) { IASTNodeLocation[] nodeLocations = node.getNodeLocations(); return nodeLocations.length == 1 && nodeLocations[0] instanceof IASTMacroExpansionLocation; } protected static boolean includesMacroExpansion(IASTNode node) { for (IASTNodeLocation nodeLocation : node.getNodeLocations()) { if (nodeLocation instanceof IASTMacroExpansionLocation) return true; } return false; } 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() { return modelCache.getCommentedNodeMap(); } }