/******************************************************************************* * Copyright (c) 2008, 2011 Wind River Systems, 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: * Markus Schorn - initial API and implementation * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser; import java.util.List; import java.util.concurrent.Semaphore; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IName; import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTComment; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; 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.IASTNodeSelector; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.core.dom.ast.INodeFactory; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.index.IndexBasedFileContentProvider; import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver; import org.eclipse.cdt.internal.core.parser.scanner.ISkippedIndexedFilesListener; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContentProvider; import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions; import org.eclipse.core.runtime.CoreException; /** * Abstract base class for all translation units. * * This class and other ASTNode subclasses are not thread safe. * Even 'get' methods may cause changes to the underlying object. */ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslationUnit, ISkippedIndexedFilesListener { private static final IASTPreprocessorStatement[] EMPTY_PREPROCESSOR_STATEMENT_ARRAY = new IASTPreprocessorStatement[0]; private static final IASTPreprocessorMacroDefinition[] EMPTY_PREPROCESSOR_MACRODEF_ARRAY = new IASTPreprocessorMacroDefinition[0]; private static final IASTPreprocessorIncludeStatement[] EMPTY_PREPROCESSOR_INCLUSION_ARRAY = new IASTPreprocessorIncludeStatement[0]; private static final IASTProblem[] EMPTY_PROBLEM_ARRAY = new IASTProblem[0]; private static final String EMPTY_STRING = ""; //$NON-NLS-1$ private IASTDeclaration[] fAllDeclarations = null; private IASTDeclaration[] fActiveDeclarations= null; private int fLastDeclaration= -1; protected ILocationResolver fLocationResolver; private IIndex fIndex; private boolean fIsHeader= true; private IIndexFileSet fIndexFileSet; private IIndexFileSet fASTFileSet; private INodeFactory fNodeFactory; private boolean fForContentAssist; private ITranslationUnit fOriginatingTranslationUnit; private ISignificantMacros fSignificantMacros= ISignificantMacros.NONE; private boolean fPragmaOnceSemantics; private SizeofCalculator fSizeofCalculator; /** The semaphore controlling exclusive access to the AST. */ private final Semaphore fSemaphore= new Semaphore(1); @Override public final IASTTranslationUnit getTranslationUnit() { return this; } public final void addDeclaration(IASTDeclaration d) { if (d != null) { d.setParent(this); d.setPropertyInParent(OWNED_DECLARATION); fAllDeclarations = (IASTDeclaration[]) ArrayUtil.append(IASTDeclaration.class, fAllDeclarations, ++fLastDeclaration, d); fActiveDeclarations= null; } } public final IASTDeclaration[] getDeclarations() { IASTDeclaration[] active= fActiveDeclarations; if (active == null) { active = ASTQueries.extractActiveDeclarations(fAllDeclarations, fLastDeclaration+1); fActiveDeclarations= active; } return active; } public final IASTDeclaration[] getDeclarations(boolean includeInactive) { if (includeInactive) { fAllDeclarations= (IASTDeclaration[]) ArrayUtil.removeNullsAfter(IASTDeclaration.class, fAllDeclarations, fLastDeclaration); return fAllDeclarations; } return getDeclarations(); } public final void replace(IASTNode child, IASTNode other) { assert child.isActive() == other.isActive(); for (int i = 0; i <= fLastDeclaration; ++i) { if (fAllDeclarations[i] == child) { other.setParent(child.getParent()); other.setPropertyInParent(child.getPropertyInParent()); fAllDeclarations[i] = (IASTDeclaration) other; fActiveDeclarations= null; return; } } } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getDeclarations(org.eclipse.cdt.core.dom.ast.IBinding) */ public final IName[] getDeclarations(IBinding binding) { IName[] names= getDeclarationsInAST(binding); if (names.length == 0 && fIndex != null) { try { names = fIndex.findDeclarations(binding); } catch (CoreException e) { CCorePlugin.log(e); return names; } } return names; } protected final IASTName[] getMacroDefinitionsInAST(IMacroBinding binding) { if (fLocationResolver == null) return IASTName.EMPTY_NAME_ARRAY; return fLocationResolver.getDeclarations(binding); } protected final IASTName[] getMacroReferencesInAST(IMacroBinding binding) { if (fLocationResolver == null) return IASTName.EMPTY_NAME_ARRAY; return fLocationResolver.getReferences(binding); } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getDefinitions(org.eclipse.cdt.core.dom.ast.IBinding) */ public final IName[] getDefinitions(IBinding binding) { IName[] names= getDefinitionsInAST(binding); if (names.length == 0 && fIndex != null) { try { names= fIndex.findDefinitions(binding); } catch (CoreException e) { CCorePlugin.log(e); return names; } } return names; } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getMacroDefinitions() */ public final IASTPreprocessorMacroDefinition[] getMacroDefinitions() { if (fLocationResolver == null) return EMPTY_PREPROCESSOR_MACRODEF_ARRAY; return fLocationResolver.getMacroDefinitions(); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getMacroExpansions() */ public IASTPreprocessorMacroExpansion[] getMacroExpansions() { if (fLocationResolver == null) return IASTPreprocessorMacroExpansion.EMPTY_ARRAY; return fLocationResolver.getMacroExpansions(getFileLocation()); } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getBuiltinMacroDefinitions() */ public final IASTPreprocessorMacroDefinition[] getBuiltinMacroDefinitions() { if (fLocationResolver == null) return EMPTY_PREPROCESSOR_MACRODEF_ARRAY; return fLocationResolver.getBuiltinMacroDefinitions(); } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getIncludeDirectives() */ public final IASTPreprocessorIncludeStatement[] getIncludeDirectives() { if (fLocationResolver == null) return EMPTY_PREPROCESSOR_INCLUSION_ARRAY; return fLocationResolver.getIncludeDirectives(); } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getAllPreprocessorStatements() */ public final IASTPreprocessorStatement[] getAllPreprocessorStatements() { if (fLocationResolver == null) return EMPTY_PREPROCESSOR_STATEMENT_ARRAY; return fLocationResolver.getAllPreprocessorStatements(); } /* * (non-Javadoc) * * @see org.eclipse.cdt.internal.core.parser2.IRequiresLocationInformation#setLocationResolver(org.eclipse.cdt.internal.core.parser.scanner2.ILocationResolver) */ public final void setLocationResolver(ILocationResolver resolver) { fLocationResolver= resolver; resolver.setRootNode(this); } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getPreprocesorProblems() */ public final IASTProblem[] getPreprocessorProblems() { if (fLocationResolver == null) return EMPTY_PROBLEM_ARRAY; IASTProblem[] result = fLocationResolver.getScannerProblems(); for (int i = 0; i < result.length; ++i) { IASTProblem p = result[i]; p.setParent(this); p.setPropertyInParent(IASTTranslationUnit.SCANNER_PROBLEM); } return result; } public final int getPreprocessorProblemsCount() { return fLocationResolver == null ? 0 : fLocationResolver.getScannerProblemsCount(); } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getFilePath() */ public final String getFilePath() { if (fLocationResolver == null) return EMPTY_STRING; return new String(fLocationResolver.getTranslationUnitPath()); } @Override public final boolean accept(ASTVisitor action) { if (action.shouldVisitTranslationUnit) { switch (action.visit(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; default: break; } } IASTDeclaration[] decls = getDeclarations(action.includeInactiveNodes); for (IASTDeclaration decl : decls) { if (!decl.accept(action)) return false; } if (action.shouldVisitTranslationUnit && action.leave(this) == ASTVisitor.PROCESS_ABORT) return false; return true; } public final IASTFileLocation flattenLocationsToFile(IASTNodeLocation[] nodeLocations) { if (fLocationResolver == null) return null; return fLocationResolver.flattenLocations(nodeLocations); } public final IDependencyTree getDependencyTree() { if (fLocationResolver == null) return null; return fLocationResolver.getDependencyTree(); } public final String getContainingFilename(int offset) { if (fLocationResolver == null) return EMPTY_STRING; return fLocationResolver.getContainingFilePath(offset); } public final IIndex getIndex() { return fIndex; } public final void setIndex(IIndex index) { this.fIndex = index; if (index != null) { fIndexFileSet= index.createFileSet(); fASTFileSet= index.createFileSet(); } } public final INodeFactory getASTNodeFactory() { return fNodeFactory; } public final void setASTNodeFactory(INodeFactory nodeFactory) { this.fNodeFactory = nodeFactory; } public final IASTComment[] getComments() { if (fLocationResolver != null) { return fLocationResolver.getComments(); } return new IASTComment[0]; } @SuppressWarnings({ "unchecked", "rawtypes" }) public final Object getAdapter(Class adapter) { if (adapter.isAssignableFrom(fLocationResolver.getClass())) { return fLocationResolver; } if (adapter.isAssignableFrom(IIndexFileSet.class)) { return fIndexFileSet; } if (adapter.isAssignableFrom(LexerOptions.class)) { return fLocationResolver.getLexerOptions(); } return null; } public final boolean isHeaderUnit() { return fIsHeader; } public final void setIsHeaderUnit(boolean headerUnit) { fIsHeader= headerUnit; } public boolean isForContentAssist() { return fForContentAssist; } public final void setIsForContentAssist(boolean forContentAssist) { fForContentAssist= forContentAssist; } /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.parser.scanner.ISkippedIndexedFilesListener#skippedFile(org.eclipse.cdt.internal.core.parser.scanner.IncludeFileContent) */ public void skippedFile(int offset, InternalFileContent fileContent) { if (fIndexFileSet != null) { List<IIndexFile> files= fileContent.getFilesIncluded(); for (IIndexFile indexFile : files) { fASTFileSet.remove(indexFile); fIndexFileSet.add(indexFile); } } } public final IIndexFileSet getIndexFileSet() { return fIndexFileSet; } public void parsingFile(InternalFileContentProvider provider, InternalFileContent fc) { if (fASTFileSet != null) { if (provider instanceof IndexBasedFileContentProvider) { try { for (IIndexFile file : ((IndexBasedFileContentProvider) provider).findIndexFiles(fc)) { if (!fIndexFileSet.contains(file)) { fASTFileSet.add(file); } } } catch (CoreException e) { // Ignore, tracking of replaced files fails. } } } } public final IIndexFileSet getASTFileSet() { return fASTFileSet; } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getNodeForLocation(org.eclipse.cdt.core.dom.ast.IASTNodeLocation) */ public final IASTNode selectNodeForLocation(String path, int realOffset, int realLength) { return getNodeSelector(path).findNode(realOffset, realLength); } public final IASTNodeSelector getNodeSelector(String filePath) { return new ASTNodeSelector(this, fLocationResolver, filePath); } /** * Must be called by the parser, before the ast is passed to the clients. */ public abstract void resolveAmbiguities(); protected void copyAbstractTU(ASTTranslationUnit copy, CopyStyle style) { copy.setIndex(fIndex); copy.fIsHeader = fIsHeader; copy.fNodeFactory = fNodeFactory; copy.setLocationResolver(fLocationResolver); copy.fForContentAssist = fForContentAssist; copy.fOriginatingTranslationUnit = fOriginatingTranslationUnit; for (IASTDeclaration declaration : getDeclarations()) copy.addDeclaration(declaration == null ? null : declaration.copy(style)); copy.setOffsetAndLength(this); } public final void freeze() { accept(new ASTGenericVisitor(true) { @Override protected int genericVisit(IASTNode node) { ((ASTNode) node).setIsFrozen(); return PROCESS_CONTINUE; } }); } /* * (non-Javadoc) * * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getOriginatingTranslationUnit() */ public ITranslationUnit getOriginatingTranslationUnit() { return fOriginatingTranslationUnit; } public void setOriginatingTranslationUnit(ITranslationUnit tu) { this.fOriginatingTranslationUnit = tu; } public ISignificantMacros getSignificantMacros() { return fSignificantMacros; } public void setSignificantMacros(ISignificantMacros sigMacros) { assertNotFrozen(); if (sigMacros != null) fSignificantMacros= sigMacros; } public boolean hasPragmaOnceSemantics() { return fPragmaOnceSemantics; } public void setPragmaOnceSemantics(boolean value) { assertNotFrozen(); fPragmaOnceSemantics= value; } /** * Starts exclusive access * @throws InterruptedException */ public void beginExclusiveAccess() throws InterruptedException { fSemaphore.acquire(); } public void endExclusiveAccess() { fSemaphore.release(); } public SizeofCalculator getSizeofCalculator() { if (fSizeofCalculator == null) { fSizeofCalculator = new SizeofCalculator(this); } return fSizeofCalculator; } }