/******************************************************************************* * Copyright (c) 2013 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 *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom; import java.util.Arrays; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.index.IPDOMASTProcessor; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.core.expressions.EvaluationContext; import org.eclipse.core.expressions.EvaluationResult; import org.eclipse.core.expressions.Expression; import org.eclipse.core.expressions.ExpressionConverter; import org.eclipse.core.expressions.ExpressionTagNames; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; /** * Internal container for extensions of org.eclipse.cdt.core.PDOMASTProcessor. The implementation * of the processor is instantiated only after checking the enablement expression (if present) for * the given AST translation unit. This avoids activating the contributing plugin until it is * actually needed. */ public class PDOMASTProcessorDesc { private static final String Attr_Class = "class"; //$NON-NLS-1$ private final IConfigurationElement element; private final Expression enablementExpression; private Boolean fStatus = null; private String id; private IPDOMASTProcessor processor; private static final String VAR_PROJECTNATURES = "projectNatures"; //$NON-NLS-1$ private static final String VAR_LANGUAGEID = "languageId"; //$NON-NLS-1$ /** * An empty implementation of the processor used as a placeholder in descriptors that are unable * to load the contributed class. */ private static final IPDOMASTProcessor NULL_PROCESSOR = new IPDOMASTProcessor.Abstract() { }; public PDOMASTProcessorDesc(IConfigurationElement element) { this.element = element; Expression expr = null; IConfigurationElement[] children = element.getChildren(ExpressionTagNames.ENABLEMENT); switch (children.length) { case 0: fStatus = Boolean.TRUE; break; case 1: try { ExpressionConverter parser = ExpressionConverter.getDefault(); expr = parser.perform(children[0]); } catch (CoreException e) { CCorePlugin.log("Error in enablement expression of " + id, e); //$NON-NLS-1$ } break; default: CCorePlugin.log("Too many enablement expressions for " + id); //$NON-NLS-1$ fStatus = Boolean.FALSE; break; } enablementExpression = expr; } private boolean matches(ITranslationUnit tu) { // If the enablement expression is missing or structurally invalid, then return immediately if (fStatus != null) return fStatus.booleanValue(); // If there is no tu, then the enablement expression cannot be evaluated, assume that all // taggers are needed if (tu == null) return true; if (enablementExpression != null) try { IProject project = null; ICProject cProject = tu.getCProject(); if (cProject != null) project = cProject.getProject(); EvaluationContext evalContext = new EvaluationContext(null, project); // if the project is not accessible, then only taggers that don't care about it will // get a chance to run if (project != null) { String[] natures = project.getDescription().getNatureIds(); evalContext.addVariable(VAR_PROJECTNATURES, Arrays.asList(natures)); } ILanguage language = tu.getLanguage(); if (language != null) evalContext.addVariable(VAR_LANGUAGEID, language.getId()); return enablementExpression.evaluate(evalContext) == EvaluationResult.TRUE; } catch (CoreException e) { CCorePlugin.log("Error while evaluating enablement expression for " + id, e); //$NON-NLS-1$ } fStatus = Boolean.FALSE; return false; } private IPDOMASTProcessor getProcessor() { if (processor == null) synchronized (this) { if (processor == null) { try { processor = (IPDOMASTProcessor) element.createExecutableExtension(Attr_Class); } catch (CoreException e) { String id = element.getDeclaringExtension().getNamespaceIdentifier() + '.' + element.getDeclaringExtension().getSimpleIdentifier(); CCorePlugin.log("Error in class attribute of " + id, e); //$NON-NLS-1$ // mark the tagger with an empty implementation to prevent future load attempts processor = NULL_PROCESSOR; } } } return processor; } // Activates the plugin if needed. public IPDOMASTProcessor getProcessorFor(IASTTranslationUnit ast) { // If there isn't an ast with an AST-TU accessible, then there is no way to defer processing, // just return the processor and let it try to sort things out. E.g., this happens for built-in // things. if (ast == null) return getProcessor(); // Otherwise evaluate the enablement expression for this TU return matches(ast.getOriginatingTranslationUnit()) ? getProcessor() : null; } }