blob: 04790878a4a7e9b1cee38a25ac98a5a59594205b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
* Markus Schorn (Wind River Systems)
* Mike Kucera (IBM)
* Sergey Prigogin (Google)
* Thomas Corbat (IFS)
*******************************************************************************/
package org.eclipse.cdt.core.dom.parser;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTCompletionNode;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.index.IIndex;
import org.eclipse.cdt.core.model.AbstractLanguage;
import org.eclipse.cdt.core.model.ICLanguageKeywords;
import org.eclipse.cdt.core.model.IContributedModelBuilder;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
import org.eclipse.cdt.core.parser.FileContent;
import org.eclipse.cdt.core.parser.IParserLogService;
import org.eclipse.cdt.core.parser.IParserSettings;
import org.eclipse.cdt.core.parser.IScanner;
import org.eclipse.cdt.core.parser.IScannerInfo;
import org.eclipse.cdt.core.parser.IncludeFileContentProvider;
import org.eclipse.cdt.core.parser.ParseError;
import org.eclipse.cdt.core.parser.ParseError.ParseErrorKind;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.ParserMode;
import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
import org.eclipse.cdt.internal.core.util.ICancelable;
import org.eclipse.cdt.internal.core.util.ICanceler;
import org.eclipse.core.runtime.CoreException;
/**
* This class provides a skeletal implementation of the ILanguage interface
* for the DOM parser framework.
*
* This class uses the template method pattern, derived classes need only implement
* {@link AbstractCLikeLanguage#getScannerExtensionConfiguration(IScannerInfo info)},
* {@link AbstractCLikeLanguage#getParserLanguage()} and
* {@link AbstractCLikeLanguage#createParser(IScanner scanner, ParserMode parserMode,
* IParserLogService logService, IIndex index)}.
*
* @see AbstractScannerExtensionConfiguration
*
* @since 5.0
*/
public abstract class AbstractCLikeLanguage extends AbstractLanguage implements ICLanguageKeywords {
private static final AbstractScannerExtensionConfiguration DUMMY_SCANNER_EXTENSION_CONFIGURATION = new AbstractScannerExtensionConfiguration() {
};
static class NameCollector extends ASTVisitor {
{
shouldVisitNames = true;
}
private List<IASTName> nameList = new ArrayList<>();
@Override
public int visit(IASTName name) {
nameList.add(name);
return PROCESS_CONTINUE;
}
public IASTName[] getNames() {
return nameList.toArray(new IASTName[nameList.size()]);
}
}
/**
* @nooverride This method is not intended to be re-implemented or extended by clients.
* @deprecated Do not override this method.
* Override {@link #getScannerExtensionConfiguration(IScannerInfo)} instead.
*/
@Deprecated
protected IScannerExtensionConfiguration getScannerExtensionConfiguration() {
return DUMMY_SCANNER_EXTENSION_CONFIGURATION;
}
/**
* @return the scanner extension configuration for this language. May not return {@code null}.
* @since 5.4
*/
protected IScannerExtensionConfiguration getScannerExtensionConfiguration(IScannerInfo info) {
return getScannerExtensionConfiguration();
}
/**
* @return the actual parser object.
*/
protected abstract ISourceCodeParser createParser(IScanner scanner, ParserMode parserMode,
IParserLogService logService, IIndex index);
/**
* @return the actual parser object, configured with additional settings.
* @since 5.6
*/
protected ISourceCodeParser createParser(IScanner scanner, ParserMode parserMode, IParserLogService logService,
IIndex index, int options, IParserSettings settings) {
return createParser(scanner, parserMode, logService, index);
}
/**
* @return The ParserLanguage value corresponding to the language supported.
*/
protected abstract ParserLanguage getParserLanguage();
@Deprecated
@Override
public IASTTranslationUnit getASTTranslationUnit(org.eclipse.cdt.core.parser.CodeReader reader,
IScannerInfo scanInfo, org.eclipse.cdt.core.dom.ICodeReaderFactory fileCreator, IIndex index,
IParserLogService log) throws CoreException {
return getASTTranslationUnit(reader, scanInfo, fileCreator, index, 0, log);
}
@Deprecated
@Override
public IASTTranslationUnit getASTTranslationUnit(org.eclipse.cdt.core.parser.CodeReader reader,
IScannerInfo scanInfo, org.eclipse.cdt.core.dom.ICodeReaderFactory codeReaderFactory, IIndex index,
int options, IParserLogService log) throws CoreException {
return getASTTranslationUnit(FileContent.adapt(reader), scanInfo,
IncludeFileContentProvider.adapt(codeReaderFactory), index, options, log);
}
@Override
public IASTTranslationUnit getASTTranslationUnit(FileContent reader, IScannerInfo scanInfo,
IncludeFileContentProvider fileCreator, IIndex index, int options, IParserLogService log)
throws CoreException {
final IScanner scanner = createScanner(reader, scanInfo, fileCreator, log);
scanner.setComputeImageLocations((options & OPTION_NO_IMAGE_LOCATIONS) == 0);
scanner.setProcessInactiveCode((options & OPTION_PARSE_INACTIVE_CODE) != 0);
IParserSettings parserSettings = null;
if (scanInfo instanceof ExtendedScannerInfo) {
ExtendedScannerInfo extendedScannerInfo = (ExtendedScannerInfo) scanInfo;
parserSettings = extendedScannerInfo.getParserSettings();
}
final ISourceCodeParser parser = createParser(scanner, log, index, false, options, parserSettings);
// Make it possible to cancel parser by reconciler - http://bugs.eclipse.org/226682
ICanceler canceler = null;
if (log instanceof ICanceler) {
canceler = (ICanceler) log;
canceler.setCancelable(new ICancelable() {
@Override
public void cancel() {
scanner.cancel();
parser.cancel();
}
});
}
try {
// Parse
return parser.parse();
} catch (ParseError e) {
// Only the TOO_MANY_TOKENS error can be handled here.
if (e.getErrorKind() != ParseErrorKind.TOO_MANY_TOKENS)
throw e;
// Otherwise generate a log because parsing was stopped because of a user preference.
if (log != null) {
String tuName = null;
if (scanner.getLocationResolver() != null)
tuName = scanner.getLocationResolver().getTranslationUnitPath();
log.traceLog(e.getMessage() + (tuName == null ? "" : (" while parsing " + tuName))); //$NON-NLS-1$ //$NON-NLS-2$
}
return null;
} finally {
if (canceler != null) {
canceler.setCancelable(null);
}
}
}
@Deprecated
@Override
public IASTCompletionNode getCompletionNode(org.eclipse.cdt.core.parser.CodeReader reader, IScannerInfo scanInfo,
org.eclipse.cdt.core.dom.ICodeReaderFactory fileCreator, IIndex index, IParserLogService log, int offset)
throws CoreException {
return getCompletionNode(FileContent.adapt(reader), scanInfo, IncludeFileContentProvider.adapt(fileCreator),
index, log, offset);
}
@Override
public IASTCompletionNode getCompletionNode(FileContent reader, IScannerInfo scanInfo,
IncludeFileContentProvider fileCreator, IIndex index, IParserLogService log, int offset)
throws CoreException {
IScanner scanner = createScanner(reader, scanInfo, fileCreator, log);
scanner.setContentAssistMode(offset);
ISourceCodeParser parser = createParser(scanner, log, index, true, 0);
// Run the parse and return the completion node
parser.parse();
IASTCompletionNode node = parser.getCompletionNode();
return node;
}
/**
* Creates the parser.
*
* @param scanner the IScanner to get tokens from
* @param log the parser log service
* @param index the index to help resolve bindings
* @param forCompletion whether the parser is used for code completion
* @param options for valid options see
* {@link AbstractLanguage#getASTTranslationUnit(FileContent, IScannerInfo, IncludeFileContentProvider, IIndex, int, IParserLogService)}
* @return an instance of ISourceCodeParser
*/
protected ISourceCodeParser createParser(IScanner scanner, IParserLogService log, IIndex index,
boolean forCompletion, int options) {
ParserMode mode = createParserMode(forCompletion, options);
return createParser(scanner, mode, log, index);
}
/**
* Create the parser with additional settings.
*
* @param scanner the IScanner to get tokens from
* @param log the parser log service
* @param index the index to help resolve bindings
* @param forCompletion whether the parser is used for code completion
* @param options for valid options see
* {@link AbstractLanguage#getASTTranslationUnit(FileContent, IScannerInfo, IncludeFileContentProvider, IIndex, int, IParserLogService)}
* @param settings for the parser
* @return an instance of ISourceCodeParser
* @since 5.6
*/
protected ISourceCodeParser createParser(IScanner scanner, IParserLogService log, IIndex index,
boolean forCompletion, int options, IParserSettings settings) {
ParserMode mode = createParserMode(forCompletion, options);
return createParser(scanner, mode, log, index, options, settings);
}
private ParserMode createParserMode(boolean forCompletion, int options) {
if (forCompletion) {
return ParserMode.COMPLETION_PARSE;
} else if ((options & OPTION_SKIP_FUNCTION_BODIES) != 0) {
return ParserMode.STRUCTURAL_PARSE;
} else {
return ParserMode.COMPLETE_PARSE;
}
}
/**
* @deprecated Replaced by
* {@link #createScanner(FileContent, IScannerInfo, IncludeFileContentProvider, IParserLogService)}
*/
@Deprecated
protected IScanner createScanner(org.eclipse.cdt.core.parser.CodeReader reader, IScannerInfo scanInfo,
org.eclipse.cdt.core.dom.ICodeReaderFactory fileCreator, IParserLogService log) {
return createScanner(FileContent.adapt(reader), scanInfo, IncludeFileContentProvider.adapt(fileCreator), log);
}
/**
* Create the scanner to be used with the parser.
* @since 5.2
*/
protected IScanner createScanner(FileContent content, IScannerInfo scanInfo, IncludeFileContentProvider fcp,
IParserLogService log) {
return new CPreprocessor(content, scanInfo, getParserLanguage(), log,
getScannerExtensionConfiguration(scanInfo), fcp);
}
@Override
@Deprecated
public IASTName[] getSelectedNames(IASTTranslationUnit ast, int start, int length) {
IASTNode selectedNode = ast.getNodeSelector(null).findNode(start, length);
if (selectedNode == null)
return new IASTName[0];
if (selectedNode instanceof IASTName)
return new IASTName[] { (IASTName) selectedNode };
if (selectedNode instanceof IASTPreprocessorMacroExpansion) {
return new IASTName[] { ((IASTPreprocessorMacroExpansion) selectedNode).getMacroReference() };
}
NameCollector collector = new NameCollector();
selectedNode.accept(collector);
return collector.getNames();
}
@Override
public IContributedModelBuilder createModelBuilder(ITranslationUnit tu) {
// Use default model builder.
return null;
}
private ICLanguageKeywords cLanguageKeywords;
private synchronized ICLanguageKeywords getCLanguageKeywords() {
if (cLanguageKeywords == null) {
cLanguageKeywords = new CLanguageKeywords(getParserLanguage(),
getScannerExtensionConfiguration(new ExtendedScannerInfo()));
}
return cLanguageKeywords;
}
@Override
@SuppressWarnings("unchecked")
public <T> T getAdapter(Class<T> adapter) {
if (adapter.isAssignableFrom(ICLanguageKeywords.class))
return (T) getCLanguageKeywords();
return super.getAdapter(adapter);
}
// For backwards compatibility
@Override
public String[] getBuiltinTypes() {
return getCLanguageKeywords().getBuiltinTypes();
}
@Override
public String[] getKeywords() {
return getCLanguageKeywords().getKeywords();
}
@Override
public String[] getPreprocessorKeywords() {
return getCLanguageKeywords().getPreprocessorKeywords();
}
}