diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java index 0c638a1740a..d9809920daa 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/EmptyIndexFragment.java @@ -178,11 +178,22 @@ public class EmptyIndexFragment implements IIndexFragment { public IIndexFragmentFileSet createFileSet() { return null; } + @Override public IIndexFragmentFile[] getAllFiles() { return IIndexFragmentFile.EMPTY_ARRAY; } + @Override + public IIndexFragmentFile[] getDefectiveFiles() { + return IIndexFragmentFile.EMPTY_ARRAY; + } + + @Override + public IIndexFragmentFile[] getFilesWithUnresolvedIncludes() { + return IIndexFragmentFile.EMPTY_ARRAY; + } + @Override public Object getCachedResult(Object key) { return null; diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java index 86963579eaf..a0f00014261 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexBugsTests.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.util.HashSet; +import java.util.Properties; import java.util.Set; import java.util.regex.Pattern; @@ -62,6 +63,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFile; +import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.index.IIndexInclude; import org.eclipse.cdt.core.index.IIndexMacro; @@ -85,6 +87,7 @@ import org.eclipse.cdt.core.testplugin.util.BaseTestCase; import org.eclipse.cdt.core.testplugin.util.TestSourceReader; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.pdom.CModelListener; +import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; @@ -105,7 +108,7 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; public class IndexBugsTests extends BaseTestCase { - private static final int INDEX_WAIT_TIME = 8000; + private static final int INDEX_WAIT_TIME = 800000; //XXX private ICProject fCProject; protected IIndex fIndex; @@ -2470,4 +2473,58 @@ public class IndexBugsTests extends BaseTestCase { fIndex.releaseReadLock(); } } + + // // test.cpp + // #include "a.h" + // using ns::INT; + + // // a.h + // #include "b.h" + + // // b.h + // namespace ns { typedef int INT; } + public void testUpdateUnresolvedIncludes_378317() throws Exception { + // Turn off indexing of unused headers. + IndexerPreferences.set(fCProject.getProject(), IndexerPreferences.KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG, "false"); + // Turn off automatic index update. + IndexerPreferences.setUpdatePolicy(fCProject.getProject(), IndexerPreferences.UPDATE_POLICY_MANUAL); + + try { + String[] contents= getContentsForTest(3); + final IIndexManager indexManager = CCorePlugin.getIndexManager(); + TestSourceReader.createFile(fCProject.getProject(), "test.c", contents[0]); + IFile ah= TestSourceReader.createFile(fCProject.getProject(), "a.h", contents[1]); + // b.h is not created yet, so #include "b.h" in a.h is unresolved. + indexManager.reindex(fCProject); + waitForIndexer(); + fIndex.acquireReadLock(); + try { + IIndexFile[] files = fIndex.getFilesWithUnresolvedIncludes(); + assertEquals(1, files.length); + assertEquals(IndexLocationFactory.getWorkspaceIFL(ah), files[0].getLocation()); + } finally { + fIndex.releaseReadLock(); + } + + IFile bh= TestSourceReader.createFile(fCProject.getProject(), "b.h", contents[2]); + indexManager.update(new ICElement[] { fCProject }, IIndexManager.UPDATE_UNRESOLVED_INCLUDES); + waitForIndexer(); + fIndex.acquireReadLock(); + try { + IIndexFile[] files = fIndex.getFilesWithUnresolvedIncludes(); + assertEquals(0, files.length); + IIndexFileLocation location = IndexLocationFactory.getWorkspaceIFL(bh); + files = fIndex.getFiles(IndexLocationFactory.getWorkspaceIFL(bh)); + assertEquals(1, files.length); + } finally { + fIndex.releaseReadLock(); + } + } finally { + // Restore default indexer preferences. + Properties defaults = IndexerPreferences.getDefaultIndexerProperties(); + IndexerPreferences.set(fCProject.getProject(), IndexerPreferences.KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG, + defaults.getProperty(IndexerPreferences.KEY_INDEX_UNUSED_HEADERS_WITH_DEFAULT_LANG)); + IndexerPreferences.setUpdatePolicy(fCProject.getProject(), IndexerPreferences.getDefaultUpdatePolicy()); + } + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java index 01c773d3041..0f7ce9af3f1 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTPreprocessorIncludeStatement.java @@ -95,6 +95,13 @@ public interface IASTPreprocessorIncludeStatement extends IASTPreprocessorStatem */ public long getIncludedFileContentsHash(); + /** + * Returns time when the included file was read. Corresponds to the start of reading. + * @return time before reading started in milliseconds since epoch + * @since 5.4 + */ + public long getIncludedFileReadTime(); + /** * Returns true if I/O errors were encountered while reading the included file. * @since 5.4 @@ -113,5 +120,5 @@ public interface IASTPreprocessorIncludeStatement extends IASTPreprocessorStatem * if the include creates AST or is unresolved or skipped. * @since 5.4 */ - public IIndexFile getImportedIndexFile(); + public IIndexFile getImportedIndexFile(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java index 87a8b947dd6..173f410687b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndex.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2011 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2012 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 @@ -436,6 +436,20 @@ public interface IIndex { */ public IIndexFile[] getAllFiles() throws CoreException; + /** + * Returns an array of files that were indexed with I/O errors. + * @noreference This method is not intended to be referenced by clients. + * @since 5.4 + */ + public IIndexFile[] getDefectiveFiles() throws CoreException; + + /** + * Returns an array of files containg unresolved includes. + * @noreference This method is not intended to be referenced by clients. + * @since 5.4 + */ + public IIndexFile[] getFilesWithUnresolvedIncludes() throws CoreException; + /** * Returns the global inline c++ namespaces. * @throws CoreException diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFile.java index 257e1647451..eb63038b785 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexFile.java @@ -62,6 +62,14 @@ public interface IIndexFile extends IFileNomination { */ long getTimestamp() throws CoreException; + /** + * Time when the file was read during indexing. Corresponds to the start of reading. + * @return time of indexing in milliseconds since epoch + * @throws CoreException + * @since 5.4 + */ + long getSourceReadTime() throws CoreException; + /** * Hash of the file contents when the file was indexed. * @return 64-bit hash of the file content. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexManager.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexManager.java index 34b00db01de..20b8fc3536b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexManager.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexManager.java @@ -113,32 +113,31 @@ public interface IIndexManager extends IPDOMManager { public final static int ADD_EXTENSION_FRAGMENTS_SEARCH = 0x200; /** - * Constant for indicating there is no time out period for joining the indexer job. + * Constant for indicating that there is no time out period for joining the indexer job. * @see IIndexManager#joinIndexer(int, IProgressMonitor) */ public final static int FOREVER= -1; /** - * Constant for indicating to update all translation units. + * Constant for requesting an update of all translation units. */ public final static int UPDATE_ALL= 0x1; /** - * Constant for indicating to update translation units if their timestamp - * has changed. + * Constant for requesting an update of translation units if theit timestamps have changed. */ public final static int UPDATE_CHECK_TIMESTAMPS= 0x2; /** - * Constant for indicating to update translation units if their configuration - * has changed. The flag currently has no effect. + * Constant for requesting an update of translation units if their configurations + * have changed. The flag currently has no effect. */ public final static int UPDATE_CHECK_CONFIGURATION= 0x4; /** - * Constant for requesting to update the external files for a project, also. This flag works only - * if it is used to update one or more projects. It shall be used together with {@link #UPDATE_ALL} - * or {@link #UPDATE_CHECK_TIMESTAMPS}. + * Constant for requesting to update the external files for a project, also. This flag works + * only if it is used to update one or more projects. It shall be used together with + * {@link #UPDATE_ALL} or {@link #UPDATE_CHECK_TIMESTAMPS}. * @since 5.1 */ public final static int UPDATE_EXTERNAL_FILES_FOR_PROJECT= 0x8; @@ -168,6 +167,12 @@ public interface IIndexManager extends IPDOMManager { */ public final static int RESET_INDEX_INCLUSION= 0x40; + /** + * Constant for requesting an update of translation units that had unresolved includes. + * @since 5.4 + */ + public final static int UPDATE_UNRESOLVED_INCLUDES= 0x80; + /** * Returns the index for the given project. * @param project the project to get the index for diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/FileContent.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/FileContent.java index f9a93b043a8..fd7085fbd78 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/FileContent.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/FileContent.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2009, 2012 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 @@ -40,13 +40,20 @@ public abstract class FileContent { public abstract String getFileLocation(); /** - * Returns the modification time of the file containing the content or NULL_TIMESTAMP if + * Returns the modification time of the file containing the content, or NULL_TIMESTAMP if * the content does not originate from a file. A zero value may be returned if there was * an I/O error. * @since 5.4 */ public abstract long getTimestamp(); + /** + * Returns time when the file was read. Corresponds to the start of reading. + * @return time before reading started in milliseconds since epoch + * @since 5.4 + */ + public abstract long getReadTime(); + /** * Returns the size of the file, or NULL_FILE_SIZE if the content does not originate from * a file. A zero value may be returned if there was an I/O error. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java index 1fbc93e4b55..c3dde20b6f0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/CIndex.java @@ -758,6 +758,32 @@ public class CIndex implements IIndex { return result.values().toArray(new IIndexFile[result.size()]); } + @Override + public IIndexFile[] getDefectiveFiles() throws CoreException { + HashMap result= new HashMap(); + for (IIndexFragment fragment : fFragments) { + for (IIndexFragmentFile file : fragment.getDefectiveFiles()) { + if (file.hasContent()) { + result.put(file.getLocation(), file); + } + } + } + return result.values().toArray(new IIndexFile[result.size()]); + } + + @Override + public IIndexFile[] getFilesWithUnresolvedIncludes() throws CoreException { + HashMap result= new HashMap(); + for (IIndexFragment fragment : fFragments) { + for (IIndexFragmentFile file : fragment.getFilesWithUnresolvedIncludes()) { + if (file.hasContent()) { + result.put(file.getLocation(), file); + } + } + } + return result.values().toArray(new IIndexFile[result.size()]); + } + @Override public IIndexScope[] getInlineNamespaces() throws CoreException { if (SPECIALCASE_SINGLES && fFragments.length == 1) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java index 503ede13120..9168511d58d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/EmptyCIndex.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2011 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2012 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 @@ -189,6 +189,16 @@ final public class EmptyCIndex implements IIndex { return IIndexFile.EMPTY_FILE_ARRAY; } + @Override + public IIndexFile[] getDefectiveFiles() { + return IIndexFile.EMPTY_FILE_ARRAY; + } + + @Override + public IIndexFile[] getFilesWithUnresolvedIncludes() { + return IIndexFile.EMPTY_FILE_ARRAY; + } + @Override public IIndexBinding[] findBindings(char[] name, boolean fileScopeOnly, IndexFilter filter, IProgressMonitor monitor) { return IIndexBinding.EMPTY_INDEX_BINDING_ARRAY; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java index 2b2ac26362f..7a2bc0ccf72 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragment.java @@ -325,6 +325,16 @@ public interface IIndexFragment { */ IIndexFragmentFile[] getAllFiles() throws CoreException; + /** + * @return an array of files that were indexed with I/O errors. + */ + IIndexFragmentFile[] getDefectiveFiles() throws CoreException; + + /** + * @return an array of files containg unresolved includes. + */ + IIndexFragmentFile[] getFilesWithUnresolvedIncludes() throws CoreException; + /** * Caches an object with the key, the cache must be cleared at latest when the fragment no * longer holds a locks. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFile.java index f6ca6b05ca2..0577e408b1b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IIndexFragmentFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2011 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2012 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 @@ -24,10 +24,15 @@ public interface IIndexFragmentFile extends IIndexFile { IIndexFragment getIndexFragment(); /** - * Sets the timestamp of the file + * Sets the timestamp of the file. */ void setTimestamp(long timestamp) throws CoreException; + /** + * Sets the file read time. + */ + void setSourceReadTime(long time) throws CoreException; + /** * Sets the hash of the file content. */ @@ -57,6 +62,12 @@ public interface IIndexFragmentFile extends IIndexFile { */ boolean hasContent() throws CoreException; + /** + * Checks if the file contains at least one unresolved include. + * @return {@code true} if the file contains an unresolved include + */ + boolean hasUnresolvedInclude() throws CoreException; + /** * Returns the id of the linkage this file belongs to. */ @@ -74,4 +85,5 @@ public interface IIndexFragmentFile extends IIndexFile { * The file 'source' must belong to the same fragment as this file. */ void transferContext(IIndexFragmentFile source) throws CoreException; + } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/InternalParserUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/InternalParserUtil.java index 37ac0d0b27b..a9de019b08e 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/InternalParserUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/InternalParserUtil.java @@ -155,6 +155,7 @@ public class InternalParserUtil extends ParserFactory { InputStream input; try { + long fileReadTime = System.currentTimeMillis(); IFileStore store = EFS.getStore(file.getLocationURI()); IFileInfo fileInfo = store.fetchInfo(); input= file.getContents(true); @@ -173,7 +174,7 @@ public class InternalParserUtil extends ParserFactory { } try { return createFileContent(path, file.getCharset(), input, - fileInfo.getLastModified(), fileInfo.getLength()); + fileInfo.getLastModified(), fileInfo.getLength(), fileReadTime); } finally { try { input.close(); @@ -201,6 +202,7 @@ public class InternalParserUtil extends ParserFactory { * canonical path. */ public static InternalFileContent createExternalFileContent(String externalLocation, String encoding) { + long fileReadTime = System.currentTimeMillis(); File includeFile = null; String path = null; if (!UNCPathConverter.isUNC(externalLocation)) { @@ -228,7 +230,7 @@ public class InternalParserUtil extends ParserFactory { return null; } try { - return createFileContent(path, encoding, in, timestamp, fileSize); + return createFileContent(path, encoding, in, timestamp, fileSize, fileReadTime); } finally { try { in.close(); @@ -240,13 +242,13 @@ public class InternalParserUtil extends ParserFactory { } private static InternalFileContent createFileContent(String path, String charset, InputStream in, - long fileTimestamp, long fileSize) { + long fileTimestamp, long fileSize, long fileReadTime) { try { AbstractCharArray chars= FileCharArray.create(path, charset, in); if (chars == null) return null; - return new InternalFileContent(path, chars, fileTimestamp, fileSize); + return new InternalFileContent(path, chars, fileTimestamp, fileSize, fileReadTime); } catch (IOException e) { CCorePlugin.log(e); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java index 8cf8471286d..43bc89e7012 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ASTPreprocessorNode.java @@ -298,6 +298,7 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces private long fIncludedFileContentsHash; private long fIncludedFileTimestamp = -1; private long fIncludedFileSize; + private long fIncludedFileReadTime; private boolean fErrorInIncludedFile; public ASTInclusionStatement(IASTTranslationUnit parent, @@ -404,6 +405,19 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces fIncludedFileTimestamp= timestamp; } + @Override + public long getIncludedFileReadTime() { + if (fNominationDelegate != null) { + return 0; + } + return fIncludedFileReadTime; + } + + public void setIncludedFileReadTime(long time) { + assert fNominationDelegate == null; + fIncludedFileReadTime= time; + } + @Override public long getIncludedFileSize() { if (fNominationDelegate != null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java index 0829535d524..46da6f2a30b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/CPreprocessor.java @@ -302,7 +302,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { if (contextPath == null) { contextPath= fRootContent.getFileLocation(); } - configureIncludeSearchPath(new File(contextPath).getParentFile(), info); + fIncludeSearchPath = configureIncludeSearchPath(new File(contextPath).getParentFile(), info); setupMacroDictionary(configuration, info, language); ILocationCtx ctx= fLocationMap.pushTranslationUnit(fRootContent.getFileLocation(), fRootContent.getSource()); @@ -396,37 +396,39 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { return array == null ? CharArrayUtils.EMPTY_CHAR_ARRAY : array; } - private void configureIncludeSearchPath(File directory, IScannerInfo info) { + public static IncludeSearchPathElement[] configureIncludeSearchPath(File directory, IScannerInfo info) { + IncludeSearchPathElement[] includeSearchPath = null; String[] searchPath= info.getIncludePaths(); int idx= 0; if (info instanceof IExtendedScannerInfo) { final IExtendedScannerInfo einfo= (IExtendedScannerInfo) info; final String[] quoteIncludeSearchPath= einfo.getLocalIncludePath(); if (quoteIncludeSearchPath != null && quoteIncludeSearchPath.length > 0) { - fIncludeSearchPath= new IncludeSearchPathElement[quoteIncludeSearchPath.length + searchPath.length]; - for (String qip : quoteIncludeSearchPath) { - fIncludeSearchPath[idx++]= new IncludeSearchPathElement(makeAbsolute(directory, qip), true); + includeSearchPath= new IncludeSearchPathElement[quoteIncludeSearchPath.length + searchPath.length]; + for (String path : quoteIncludeSearchPath) { + includeSearchPath[idx++]= new IncludeSearchPathElement(makeAbsolute(directory, path), true); } } } - if (fIncludeSearchPath == null) { - fIncludeSearchPath= new IncludeSearchPathElement[searchPath.length]; + if (includeSearchPath == null) { + includeSearchPath= new IncludeSearchPathElement[searchPath.length]; } for (String path : searchPath) { - fIncludeSearchPath[idx++]= new IncludeSearchPathElement(makeAbsolute(directory, path), false); + includeSearchPath[idx++]= new IncludeSearchPathElement(makeAbsolute(directory, path), false); } + return includeSearchPath; } - private String makeAbsolute(File directory, String inlcudePath) { - if (directory == null || new File(inlcudePath).isAbsolute()) { - return inlcudePath; + private static String makeAbsolute(File directory, String includePath) { + if (directory == null || new File(includePath).isAbsolute()) { + return includePath; } - return ScannerUtility.createReconciledPath(directory.getAbsolutePath(), inlcudePath); + return ScannerUtility.createReconciledPath(directory.getAbsolutePath(), includePath); } private void setupMacroDictionary(IScannerExtensionConfiguration config, IScannerInfo info, ParserLanguage lang) { - // built in macros + // Built-in macros fMacroDictionary.put(__CDT_PARSER__.getNameCharArray(), __CDT_PARSER__); fMacroDictionary.put(__STDC__.getNameCharArray(), __STDC__); fMacroDictionary.put(__FILE__.getNameCharArray(), __FILE__); @@ -1066,20 +1068,10 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { private T findInclusion(final String includeDirective, final boolean quoteInclude, final boolean includeNext, final String currentFile, final IIncludeFileTester tester) { T reader = null; - // Filename is an absolute path - if (new File(includeDirective).isAbsolute()) { - return tester.checkFile(includeDirective, false, null); - } - // Filename is a Linux absolute path on a windows machine - if (File.separatorChar == '\\' && includeDirective.length() > 0) { - final char firstChar = includeDirective.charAt(0); - if (firstChar == '\\' || firstChar == '/') { - if (currentFile != null && currentFile.length() > 1 && currentFile.charAt(1) == ':') { - return tester.checkFile(currentFile.substring(0, 2) + includeDirective, false, null); - } - return tester.checkFile(includeDirective, false, null); - } - } + String absoluteInclusionPath = getAbsoluteInclusionPath(includeDirective, currentFile); + if (absoluteInclusionPath != null) { + return tester.checkFile(absoluteInclusionPath, false, null); + } if (currentFile != null && quoteInclude && !includeNext) { // Check to see if we find a match in the current directory @@ -1134,6 +1126,24 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { return null; } + public static String getAbsoluteInclusionPath(String includeDirective, String currentFile) { + // Filename is an absolute path + if (new File(includeDirective).isAbsolute()) { + return includeDirective; + } + // Filename is a Linux absolute path on a Windows machine + if (File.separatorChar == '\\' && includeDirective.length() > 0) { + final char firstChar = includeDirective.charAt(0); + if (firstChar == '\\' || firstChar == '/') { + if (currentFile != null && currentFile.length() > 1 && currentFile.charAt(1) == ':') { + return currentFile.substring(0, 2) + includeDirective; + } + return includeDirective; + } + } + return null; + } + private IncludeSearchPathElement findFileInIncludePath(String file, String includeDirective) { for (IncludeSearchPathElement path : fIncludeSearchPath) { String fileLocation = path.getLocation(includeDirective); @@ -1490,6 +1500,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { stmt.setIncludedFileTimestamp(fi.getTimestamp()); stmt.setIncludedFileSize(fi.getFileSize()); stmt.setIncludedFileContentsHash(source.getContentsHash()); + stmt.setIncludedFileReadTime(fi.getReadTime()); stmt.setErrorInIncludedFile(source.hasError()); if (!fCurrentContext.isPragmaOnce()) { // Track the loaded version count, even in a non-pragma-once context. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/FileCharArray.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/FileCharArray.java index 66708a23bb3..94c45ff9255 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/FileCharArray.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/FileCharArray.java @@ -186,6 +186,7 @@ public class FileCharArray extends LazyCharArray { decode(channel, chunk.fSourceOffset, chunk.fSourceEndOffset, CharBuffer.wrap(dest)); } catch (IOException e) { // File cannot be read + CCorePlugin.log(e); fHasError = true; } finally { try { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeSearchPathElement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeSearchPathElement.java index 7cd2ef5e4da..458dbc3f632 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeSearchPathElement.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/IncludeSearchPathElement.java @@ -15,7 +15,7 @@ import java.io.File; /** * Represents an entry of the include search path */ -final class IncludeSearchPathElement { +public final class IncludeSearchPathElement { private static final boolean NON_SLASH_SEPARATOR = File.separatorChar != '/'; public static final String FRAMEWORK_VAR = "__framework__"; //$NON-NLS-1$ public static final String FILE_VAR = "__header__"; //$NON-NLS-1$ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContent.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContent.java index d8daeb12efb..5ce1b706be9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContent.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContent.java @@ -60,6 +60,7 @@ public class InternalFileContent extends FileContent { private IncludeSearchPathElement fFoundOnPath; private final long fTimestamp; private final long fFileSize; + private final long fReadTime; /** * For skipping include files. @@ -79,7 +80,8 @@ public class InternalFileContent extends FileContent { fSource= null; fNonPragmaOnceFiles= null; fTimestamp= NULL_TIMESTAMP; - fFileSize = NULL_FILE_SIZE; + fFileSize= NULL_FILE_SIZE; + fReadTime= 0; } /** @@ -87,7 +89,7 @@ public class InternalFileContent extends FileContent { * @throws IllegalArgumentException in case the codeReader or its location is null. */ public InternalFileContent(String filePath, AbstractCharArray content, long timestamp, - long fileSize) throws IllegalArgumentException { + long fileSize, long fileReadTime) throws IllegalArgumentException { if (content == null) { throw new IllegalArgumentException(); } @@ -101,7 +103,8 @@ public class InternalFileContent extends FileContent { throw new IllegalArgumentException(); } fTimestamp= timestamp; - fFileSize = fileSize; + fFileSize= fileSize; + fReadTime= fileReadTime; } /** @@ -123,6 +126,7 @@ public class InternalFileContent extends FileContent { } fTimestamp= NULL_TIMESTAMP; fFileSize = NULL_FILE_SIZE; + fReadTime= 0; } /** @@ -144,6 +148,7 @@ public class InternalFileContent extends FileContent { fNonPragmaOnceFiles= nonPragmaOnceVersions; fTimestamp= NULL_TIMESTAMP; fFileSize = NULL_FILE_SIZE; + fReadTime= 0; } /** @@ -166,6 +171,11 @@ public class InternalFileContent extends FileContent { return fTimestamp; } + @Override + public long getReadTime() { + return fReadTime; + } + @Override public long getFileSize() { return fFileSize; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java index 8a15c8298a1..b86005f0d7a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/AbstractIndexerTask.java @@ -584,6 +584,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { final boolean forceAll= (fUpdateFlags & IIndexManager.UPDATE_ALL) != 0; final boolean checkTimestamps= (fUpdateFlags & IIndexManager.UPDATE_CHECK_TIMESTAMPS) != 0; final boolean checkFileContentsHash = (fUpdateFlags & IIndexManager.UPDATE_CHECK_CONTENTS_HASH) != 0; + final boolean forceUnresolvedIncludes = (fUpdateFlags & IIndexManager.UPDATE_UNRESOLVED_INCLUDES) != 0; final boolean both = fIndexHeadersWithoutContext == UnusedHeaderStrategy.useBoth; int count= 0; int forceFirst= fForceNumberFiles; @@ -616,7 +617,9 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (ifile != null && ifile.getLinkageID() == linkageID && ifile.hasContent()) { foundInLinkage = true; indexFiles[i]= null; // Take the file. - boolean update= force || isModified(checkTimestamps, checkFileContentsHash, ifl, tu, ifile); + boolean update= force || + (forceUnresolvedIncludes && ifile.hasUnresolvedInclude()) || + isModified(checkTimestamps, checkFileContentsHash, ifl, tu, ifile); if (update && requestUpdate(linkageID, ifl, ifile, tu, updateKind)) { count++; linkages.set(linkageID); @@ -639,7 +642,9 @@ public abstract class AbstractIndexerTask extends PDOMWriter { iFilesToRemove.add(ifile); count++; } else { - boolean update= force || isModified(checkTimestamps, checkFileContentsHash, ifl, tu, ifile); + boolean update= force || + (forceUnresolvedIncludes && ifile.hasUnresolvedInclude()) || + isModified(checkTimestamps, checkFileContentsHash, ifl, tu, ifile); final int linkageID = ifile.getLinkageID(); if (update && requestUpdate(linkageID, ifl, ifile, tu, UpdateKind.OTHER_HEADER)) { count++; @@ -648,7 +653,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } } - for (int lid = linkages.nextSetBit(0); lid >= 0; lid= linkages.nextSetBit(lid+1)) { + for (int lid = linkages.nextSetBit(0); lid >= 0; lid= linkages.nextSetBit(lid + 1)) { addPerLinkage(lid, ifl, files); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 3d027cb7c6b..b7f081a4cc9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -72,6 +72,7 @@ import org.eclipse.cdt.internal.core.pdom.db.BTree; import org.eclipse.cdt.internal.core.pdom.db.ChunkCache; import org.eclipse.cdt.internal.core.pdom.db.DBProperties; import org.eclipse.cdt.internal.core.pdom.db.Database; +import org.eclipse.cdt.internal.core.pdom.db.IBTreeComparator; import org.eclipse.cdt.internal.core.pdom.db.IBTreeVisitor; import org.eclipse.cdt.internal.core.pdom.dom.BindingCollector; import org.eclipse.cdt.internal.core.pdom.dom.FindBinding; @@ -215,10 +216,11 @@ public class PDOM extends PlatformObject implements IPDOM { * 122.0 - Compacting strings * 123.0 - Combined file size and encoding hash code. * 124.0 - GCC attributes and NO_RETURN flag for functions. + * 125.0 - Indexes for unresolved includes and files indexed with I/O errors. */ - private static final int MIN_SUPPORTED_VERSION= version(124, 0); - private static final int MAX_SUPPORTED_VERSION= version(124, Short.MAX_VALUE); - private static final int DEFAULT_VERSION = version(124, 0); + private static final int MIN_SUPPORTED_VERSION= version(125, 0); + private static final int MAX_SUPPORTED_VERSION= version(125, Short.MAX_VALUE); + private static final int DEFAULT_VERSION = version(125, 0); private static int version(int major, int minor) { return (major << 16) + minor; @@ -251,8 +253,10 @@ public class PDOM extends PlatformObject implements IPDOM { public static final int LINKAGES = Database.DATA_AREA; public static final int FILE_INDEX = Database.DATA_AREA + 4; - public static final int PROPERTIES = Database.DATA_AREA + 8; - public static final int END= Database.DATA_AREA + 12; + public static final int INDEX_OF_DEFECTIVE_FILES = Database.DATA_AREA + 8; + public static final int INDEX_OF_FILES_WITH_UNRESOLVED_INCLUDES = Database.DATA_AREA + 12; + public static final int PROPERTIES = Database.DATA_AREA + 16; + public static final int END= Database.DATA_AREA + 20; static { assert END <= Database.CHUNK_SIZE; } @@ -303,9 +307,19 @@ public class PDOM extends PlatformObject implements IPDOM { public void handleChange(PDOM pdom, ChangeEvent event); } + // Primitive comparator that compares database offsets of two records. + private static final IBTreeComparator offsetComparator = new IBTreeComparator() { + @Override + public int compare(long record1, long record2) throws CoreException { + return record1 < record2 ? -1 : record1 == record2 ? 0 : 1; + } + }; + // Local caches protected Database db; private BTree fileIndex; + private BTree indexOfDefectiveFiles; + private BTree indexOfFiledWithUnresolvedIncludes; private Map fLinkageIDCache = new HashMap(); private File fPath; private IIndexLocationConverter locationConverter; @@ -432,6 +446,26 @@ public class PDOM extends PlatformObject implements IPDOM { return fileIndex; } + /** + * Returns the index of files that were read with I/O errors. + */ + public BTree getIndexOfDefectiveFiles() throws CoreException { + if (indexOfDefectiveFiles == null) + indexOfDefectiveFiles = new BTree(getDB(), INDEX_OF_DEFECTIVE_FILES, offsetComparator); + return indexOfDefectiveFiles; + } + + /** + * Returns the index of files containg unresolved includes. + */ + public BTree getIndexOfFilesWithUnresolvedIncludes() throws CoreException { + if (indexOfFiledWithUnresolvedIncludes == null) { + indexOfFiledWithUnresolvedIncludes = + new BTree(getDB(), INDEX_OF_FILES_WITH_UNRESOLVED_INCLUDES, offsetComparator); + } + return indexOfFiledWithUnresolvedIncludes; + } + @Deprecated @Override public PDOMFile getFile(int linkageID, IIndexFileLocation location) throws CoreException { @@ -471,8 +505,22 @@ public class PDOM extends PlatformObject implements IPDOM { @Override public IIndexFragmentFile[] getAllFiles() throws CoreException { - final List locations = new ArrayList(); - getFileIndex().accept(new IBTreeVisitor() { + return getFiles(getFileIndex()); + } + + @Override + public IIndexFragmentFile[] getDefectiveFiles() throws CoreException { + return getFiles(getIndexOfDefectiveFiles()); + } + + @Override + public IIndexFragmentFile[] getFilesWithUnresolvedIncludes() throws CoreException { + return getFiles(getIndexOfFilesWithUnresolvedIncludes()); + } + + private IIndexFragmentFile[] getFiles(BTree index) throws CoreException { + final List files = new ArrayList(); + index.accept(new IBTreeVisitor() { @Override public int compare(long record) throws CoreException { return 0; @@ -481,13 +529,13 @@ public class PDOM extends PlatformObject implements IPDOM { @Override public boolean visit(long record) throws CoreException { PDOMFile file = PDOMFile.recreateFile(PDOM.this, record); - locations.add(file); + files.add(file); return true; } }); - return locations.toArray(new IIndexFragmentFile[locations.size()]); + return files.toArray(new IIndexFragmentFile[files.size()]); } - + protected IIndexFragmentFile addFile(int linkageID, IIndexFileLocation location, ISignificantMacros sigMacros) throws CoreException { PDOMLinkage linkage= createLinkage(linkageID); @@ -1296,6 +1344,8 @@ public class PDOM extends PlatformObject implements IPDOM { private void clearCaches() { fileIndex= null; + indexOfDefectiveFiles= null; + indexOfFiledWithUnresolvedIncludes= null; fLinkageIDCache.clear(); clearResultCache(); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java index 20f4d820d0a..99d43bc24d3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMProxy.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2012 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 @@ -41,7 +41,7 @@ import org.eclipse.core.runtime.IProgressMonitor; /** * The PDOMProxy is returned by the PDOMManager before the indexer kicks in. Also and more * importantly it is returned when the indexer has been shut down (clients may not be aware - * of this yet). Doing that prevents the creation of empty pdoms for deleted projects. + * of this yet). Doing that prevents the creation of empty PDOMs for deleted projects. */ public class PDOMProxy implements IPDOM { private PDOM fDelegate; @@ -318,6 +318,20 @@ public class PDOMProxy implements IPDOM { return IIndexFragmentFile.EMPTY_ARRAY; } + @Override + public synchronized IIndexFragmentFile[] getDefectiveFiles() throws CoreException { + if (fDelegate != null) + return fDelegate.getDefectiveFiles(); + return IIndexFragmentFile.EMPTY_ARRAY; + } + + @Override + public synchronized IIndexFragmentFile[] getFilesWithUnresolvedIncludes() throws CoreException { + if (fDelegate != null) + return fDelegate.getFilesWithUnresolvedIncludes(); + return IIndexFragmentFile.EMPTY_ARRAY; + } + @Override public synchronized IIndexFragmentBinding[] findMacroContainers(Pattern pattern, IndexFilter filter, IProgressMonitor monitor) throws CoreException { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java index c3b7c051b92..bcdc654fe9f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMWriter.java @@ -79,6 +79,7 @@ abstract public class PDOMWriter { final long timestamp; final long fileSize; final long contentsHash; + final long sourceReadTime; final boolean hasError; public FileInAST(IASTPreprocessorIncludeStatement includeStmt, FileContentKey key) { @@ -87,6 +88,7 @@ abstract public class PDOMWriter { timestamp= includeStmt.getIncludedFileTimestamp(); fileSize = includeStmt.getIncludedFileSize(); contentsHash= includeStmt.getIncludedFileContentsHash(); + sourceReadTime= includeStmt.getIncludedFileReadTime(); hasError= includeStmt.isErrorInIncludedFile(); } @@ -96,6 +98,7 @@ abstract public class PDOMWriter { timestamp= codeReader.getTimestamp(); fileSize= codeReader.getFileSize(); contentsHash= codeReader.getContentsHash(); + sourceReadTime= codeReader.getReadTime(); hasError= codeReader.hasError(); } @@ -577,6 +580,7 @@ abstract public class PDOMWriter { index.setFileContent(file, linkageID, includeInfoArray, macros, names, fResolver, lock); } file.setTimestamp(astFile.hasError ? 0 : astFile.timestamp); + file.setSourceReadTime(astFile.sourceReadTime); file.setSizeAndEncodingHashcode(computeFileSizeAndEncodingHashcode(astFile.fileSize, location)); file.setContentsHash(astFile.contentsHash); file = index.commitUncommittedFile(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/WritablePDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/WritablePDOM.java index aaeb280dfd8..89b1b26d487 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/WritablePDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/WritablePDOM.java @@ -87,17 +87,36 @@ public class WritablePDOM extends PDOM implements IWritableIndexFragment { public IIndexFragmentFile commitUncommittedFile() throws CoreException { if (uncommittedFile == null) return null; + + int defectiveStateChange = uncommittedFile.getTimestamp() == 0 ? 1 : 0; + int unresolvedIncludeStateChange = uncommittedFile.hasUnresolvedInclude() ? 1 : 0; + PDOMFile file; if (fileBeingUpdated == null) { // New file, insert it into the index. file = uncommittedFile; - getFileIndex().insert(file.getRecord()); + getFileIndex().insert(file.getRecord()); } else { // Existing file. + if (fileBeingUpdated.getTimestamp() == 0) + defectiveStateChange -= 1; + if (fileBeingUpdated.hasUnresolvedInclude()) + unresolvedIncludeStateChange -= 1; fileBeingUpdated.replaceContentsFrom(uncommittedFile); file = fileBeingUpdated; fileBeingUpdated = null; } + if (defectiveStateChange > 0) { + getIndexOfDefectiveFiles().insert(file.getRecord()); + } else if (defectiveStateChange < 0) { + getIndexOfDefectiveFiles().delete(file.getRecord()); + } + if (unresolvedIncludeStateChange > 0) { + getIndexOfFilesWithUnresolvedIncludes().insert(file.getRecord()); + } else if (unresolvedIncludeStateChange < 0) { + getIndexOfFilesWithUnresolvedIncludes().delete(file.getRecord()); + } + fEvent.fFilesWritten.add(uncommittedKey.getLocation()); uncommittedFile = null; uncommittedKey = null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java index 816e1dbcbb1..e44b2170e72 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMFile.java @@ -72,13 +72,14 @@ public class PDOMFile implements IIndexFragmentFile { private static final int LOCATION_REPRESENTATION = FIRST_MACRO + Database.PTR_SIZE; private static final int LINKAGE_ID= LOCATION_REPRESENTATION + Database.PTR_SIZE; // size 3 private static final int FLAGS= LINKAGE_ID + 3; // size 1 - private static final int TIME_STAMP = FLAGS + 1; // long - private static final int CONTENT_HASH= TIME_STAMP + 8; // long + private static final int TIME_STAMP= FLAGS + 1; // long + private static final int SOURCE_READ_TIME= TIME_STAMP + 8; // long + private static final int CONTENT_HASH= SOURCE_READ_TIME + 8; // long private static final int SIZE_AND_ENCODING_HASH= CONTENT_HASH + 8; private static final int LAST_USING_DIRECTIVE= SIZE_AND_ENCODING_HASH + 4; private static final int FIRST_MACRO_REFERENCE= LAST_USING_DIRECTIVE + Database.PTR_SIZE; private static final int SIGNIFICANT_MACROS= FIRST_MACRO_REFERENCE + Database.PTR_SIZE; - private static final int RECORD_SIZE= SIGNIFICANT_MACROS + Database.PTR_SIZE; // 8*PTR_SIZE + 3+1+8+8+4 = 56 + private static final int RECORD_SIZE= SIGNIFICANT_MACROS + Database.PTR_SIZE; // 8*PTR_SIZE + 3+1+8+8+8+4 = 64 private static final int FLAG_PRAGMA_ONCE_SEMANTICS = 0x01; @@ -205,6 +206,7 @@ public class PDOMFile implements IIndexFragmentFile { } setTimestamp(sourceFile.getTimestamp()); + setSourceReadTime(sourceFile.getSourceReadTime()); setSizeAndEncodingHashcode(sourceFile.getSizeAndEncodingHashcode()); setContentsHash(sourceFile.getContentsHash()); @@ -309,6 +311,18 @@ public class PDOMFile implements IIndexFragmentFile { db.putLong(record + TIME_STAMP, timestamp); } + @Override + public long getSourceReadTime() throws CoreException { + Database db = fLinkage.getDB(); + return db.getLong(record + SOURCE_READ_TIME); + } + + @Override + public void setSourceReadTime(long time) throws CoreException { + Database db= fLinkage.getDB(); + db.putLong(record + SOURCE_READ_TIME, time); + } + @Override public long getContentsHash() throws CoreException { Database db = fLinkage.getDB(); @@ -571,6 +585,7 @@ public class PDOMFile implements IIndexFragmentFile { m.delete(); } setFirstMacroReference(null); + setSourceReadTime(0); setTimestamp(-1); } @@ -644,6 +659,17 @@ public class PDOMFile implements IIndexFragmentFile { return result.toArray(new IIndexInclude[result.size()]); } + @Override + public boolean hasUnresolvedInclude() throws CoreException { + PDOMInclude include = getFirstInclude(); + while (include != null) { + if (!include.isResolved() && include.isActive()) + return true; + include = include.getNextInIncludes(); + } + return false; + } + @Override public IIndexMacro[] getMacros() throws CoreException { List result= new ArrayList(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMUpdateTask.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMUpdateTask.java index 349ea0fde3f..df8621199c4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMUpdateTask.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMUpdateTask.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2012 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 @@ -11,6 +11,7 @@ ******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.indexer; +import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -22,13 +23,18 @@ import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexFile; import org.eclipse.cdt.core.index.IIndexFileLocation; +import org.eclipse.cdt.core.index.IIndexInclude; import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.core.index.IndexLocationFactory; 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.core.parser.IScannerInfo; import org.eclipse.cdt.internal.core.model.ExternalTranslationUnit; +import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor; +import org.eclipse.cdt.internal.core.parser.scanner.IncludeSearchPathElement; +import org.eclipse.cdt.internal.core.parser.scanner.ScannerUtility; import org.eclipse.cdt.internal.core.pdom.IndexerProgress; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; @@ -42,19 +48,18 @@ import org.eclipse.osgi.util.NLS; * A task for updating an index, suitable for all indexers. */ public class PDOMUpdateTask implements IPDOMIndexerTask { - protected static final String TRUE= String.valueOf(true); - protected static final ITranslationUnit[] NO_TUS = {}; + private static final ITranslationUnit[] NO_TUS = {}; private final IPDOMIndexer fIndexer; - private final IndexerProgress fProgress; private final int fUpdateOptions; + private final IndexerProgress fProgress; private volatile IPDOMIndexerTask fDelegate; private ArrayList fFilesAndFolders; public PDOMUpdateTask(IPDOMIndexer indexer, int updateOptions) { fIndexer= indexer; - fProgress= createProgress(); fUpdateOptions= updateOptions; + fProgress= createProgress(); } private IndexerProgress createProgress() { @@ -92,40 +97,65 @@ public class PDOMUpdateTask implements IPDOMIndexerTask { private void createDelegate(ICProject project, IProgressMonitor monitor) throws CoreException, InterruptedException { HashSet set= new HashSet(); - TranslationUnitCollector collector= new TranslationUnitCollector(set, set, monitor); - boolean haveProject= false; - if (fFilesAndFolders == null) { - project.accept(collector); - } else { - for (ICElement elem : fFilesAndFolders) { - if (elem.getElementType() == ICElement.C_PROJECT) { - haveProject= true; + if ((fUpdateOptions & (IIndexManager.UPDATE_ALL | IIndexManager.UPDATE_CHECK_TIMESTAMPS)) != 0) { + TranslationUnitCollector collector= new TranslationUnitCollector(set, set, monitor); + boolean haveProject= false; + if (fFilesAndFolders == null) { + project.accept(collector); + } else { + for (ICElement elem : fFilesAndFolders) { + if (elem.getElementType() == ICElement.C_PROJECT) { + haveProject= true; + } + elem.accept(collector); + } + } + if (haveProject && (fUpdateOptions & IIndexManager.UPDATE_EXTERNAL_FILES_FOR_PROJECT) != 0) { + final String projectPrefix= project.getProject().getFullPath().toString() + IPath.SEPARATOR; + IIndex index= CCorePlugin.getIndexManager().getIndex(project); + index.acquireReadLock(); + try { + IIndexFile[] files= index.getAllFiles(); + for (IIndexFile indexFile : files) { + IIndexFileLocation floc= indexFile.getLocation(); + final String fullPath = floc.getFullPath(); + if (fullPath == null || !fullPath.startsWith(projectPrefix)) { + ITranslationUnit tu = getTranslationUnit(floc, project); + if (tu != null) { + set.add(tu); + } + } + } + } finally { + index.releaseReadLock(); } - elem.accept(collector); } } - if (haveProject && (fUpdateOptions & IIndexManager.UPDATE_EXTERNAL_FILES_FOR_PROJECT) != 0) { - final String projectPrefix= project.getProject().getFullPath().toString() + IPath.SEPARATOR; + + if ((fUpdateOptions & IIndexManager.UPDATE_UNRESOLVED_INCLUDES) != 0) { IIndex index= CCorePlugin.getIndexManager().getIndex(project); index.acquireReadLock(); try { - IIndexFile[] files= index.getAllFiles(); - for (IIndexFile indexFile : files) { - IIndexFileLocation floc= indexFile.getLocation(); - final String fullPath = floc.getFullPath(); - if (fullPath == null || !fullPath.startsWith(projectPrefix)) { - IPath path= IndexLocationFactory.getAbsolutePath(floc); - if (path != null) { - ITranslationUnit tu= CoreModel.getDefault().createTranslationUnitFrom(project, path); - if (tu != null) { - if (fullPath != null) { - if (tu instanceof ExternalTranslationUnit) { - IResource file= ResourcesPlugin.getWorkspace().getRoot().findMember(fullPath); - if (file instanceof IFile) { - ((ExternalTranslationUnit) tu).setResource((IFile) file); - } - } - } + // Files that were indexed with I/O errors. + IIndexFile[] files= index.getDefectiveFiles(); + for (IIndexFile file : files) { + ITranslationUnit tu = getTranslationUnit(file.getLocation(), project); + if (tu != null) { + set.add(tu); + } + } + + // Files with unresolved includes. + files= index.getFilesWithUnresolvedIncludes(); + if (files.length > 0) { + ProjectIndexerInputAdapter inputAdapter = new ProjectIndexerInputAdapter(project, true); + ProjectIndexerIncludeResolutionHeuristics includeResolutionHeuristics = + new ProjectIndexerIncludeResolutionHeuristics(project.getProject(), inputAdapter); + for (IIndexFile file : files) { + ITranslationUnit tu = getTranslationUnit(file.getLocation(), project); + if (tu != null) { + IScannerInfo scannerInfo = tu.getScannerInfo(true); + if (canResolveUnresolvedInclude(file, scannerInfo, includeResolutionHeuristics)) { set.add(tu); } } @@ -135,15 +165,108 @@ public class PDOMUpdateTask implements IPDOMIndexerTask { index.releaseReadLock(); } } + ITranslationUnit[] tus= set.toArray(new ITranslationUnit[set.size()]); IPDOMIndexerTask delegate= fIndexer.createTask(NO_TUS, tus, NO_TUS); if (delegate instanceof PDOMIndexerTask) { final PDOMIndexerTask task = (PDOMIndexerTask) delegate; task.setUpdateFlags(fUpdateOptions); } - synchronized (this) { - fDelegate= delegate; + setDelegate(delegate); + } + + private ITranslationUnit getTranslationUnit(IIndexFileLocation location, ICProject project) { + IPath path= IndexLocationFactory.getAbsolutePath(location); + if (path == null) + return null; + ITranslationUnit tu= CoreModel.getDefault().createTranslationUnitFrom(project, path); + if (tu != null) { + final String fullPath = location.getFullPath(); + if (fullPath != null) { + if (tu instanceof ExternalTranslationUnit) { + IResource file= ResourcesPlugin.getWorkspace().getRoot().findMember(fullPath); + if (file instanceof IFile) { + ((ExternalTranslationUnit) tu).setResource((IFile) file); + } + } + } } + return tu; + } + + private boolean canResolveUnresolvedInclude(IIndexFile file, IScannerInfo scannerInfo, + ProjectIndexerIncludeResolutionHeuristics includeResolutionHeuristics) { + try { + String filePath = IndexLocationFactory.getAbsolutePath(file.getLocation()).toOSString(); + long fileReadTime = file.getSourceReadTime(); + IncludeSearchPathElement[] includeSearchPath = + CPreprocessor.configureIncludeSearchPath(new File(filePath).getParentFile(), scannerInfo); + for (IIndexInclude include : file.getIncludes()) { + if (!include.isResolved() && include.isActive() && + canResolveInclude(include, filePath, fileReadTime, includeSearchPath, includeResolutionHeuristics)) { + return true; + } + } + } catch (CoreException e) { + CCorePlugin.log(e); + } + return false; + } + + private boolean canResolveInclude(IIndexInclude include, String currentFile, long timestamp, + IncludeSearchPathElement[] includeSearchPath, + ProjectIndexerIncludeResolutionHeuristics includeResolutionHeuristics) throws CoreException { + String includeName = include.getFullName(); + String filePath = CPreprocessor.getAbsoluteInclusionPath(includeName, currentFile); + if (filePath != null && fileIsNotOlderThanTimestamp(filePath, timestamp)) { + return true; + } + + if (currentFile != null && !include.isSystemInclude()) { + // Check to see if we find a match in the current directory + final File currentDir= new File(currentFile).getParentFile(); + if (currentDir != null) { + filePath = ScannerUtility.createReconciledPath(currentDir.getAbsolutePath(), includeName); + if (!filePath.equals(currentFile) && fileIsNotOlderThanTimestamp(filePath, timestamp)) { + return true; + } + } + } + + // Unlike CPreprocessor.findInclusion we are searching include path from the beginning. + // This simplification may produce false positives, but by checking file modification time + // we guarantee that any false positive won't be produced again when this task runs + // next time. + for (IncludeSearchPathElement path : includeSearchPath) { + if (!include.isSystemInclude() || !path.isForQuoteIncludesOnly()) { + filePath = path.getLocation(includeName); + if (filePath != null && fileIsNotOlderThanTimestamp(filePath, timestamp)) { + return true; + } + } + } + if (includeResolutionHeuristics != null) { + filePath= includeResolutionHeuristics.findInclusion(includeName, currentFile); + if (filePath != null && fileIsNotOlderThanTimestamp(filePath, timestamp)) { + return true; + } + } + + return false; + } + + /** + * Returns true if the file exists and is not older than the given timestamp. + */ + private boolean fileIsNotOlderThanTimestamp(String filename, long timestamp) { + // We are subtracting 1 second from the timestamp to account for limited precision + // of File.lastModified() method and possible asynchrony between clocks on multi-CPU + // systems. This may produce false positives, but they are pretty harmless. + return new File(filename).lastModified() >= timestamp - 1000; + } + + private synchronized void setDelegate(IPDOMIndexerTask delegate) { + fDelegate= delegate; } @Override diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties index 8551271a582..5de290067a3 100644 --- a/core/org.eclipse.cdt.ui/plugin.properties +++ b/core/org.eclipse.cdt.ui/plugin.properties @@ -460,8 +460,9 @@ CDTIndexer.fastindexer=C/C++ Indexer IndexView.name=C/C++ Index RebuildIndex.name=&Rebuild -SyncIndex.name=&Update with Modified Files FreshenIndex.name=&Freshen All Files +SyncIndex.name=&Update with Modified Files +UpdateUnresolvedIncludes.name=R&e-resolve Unresolved Includes SearchUnresolvedIncludes.name=Search for Unresolved &Includes CreateParserLog.name=Create Parser &Log File diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index f679daf1a8e..a51d26ebdca 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -1372,15 +1372,20 @@ + class="org.eclipse.cdt.internal.ui.actions.UpdateUnresolvedIncludesAction" + id="org.eclipse.cdt.ui.updateUnresolvedIncludesAction" + label="%UpdateUnresolvedIncludes.name" + menubarPath="org.eclipse.cdt.ui.indexmenu/update"/> + class="org.eclipse.cdt.internal.ui.actions.UpdateIndexWithModifiedFilesAction" + id="org.eclipse.cdt.ui.syncIndexWithDiskAction" + label="%SyncIndex.name" + menubarPath="org.eclipse.cdt.ui.indexmenu/update"/> + +