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 293cbc8ae73..86963579eaf 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 @@ -2394,7 +2394,8 @@ public class IndexBugsTests extends BaseTestCase { final Set folders = new HashSet(); folders.add(root); root.accept(new IResourceVisitor() { - public boolean visit(final IResource resource) throws CoreException { + @Override + public boolean visit(final IResource resource) throws CoreException { if (resource instanceof IFile) { files.add((IFile) resource); } else if (resource instanceof IFolder) { @@ -2431,4 +2432,42 @@ public class IndexBugsTests extends BaseTestCase { index.releaseReadLock(); } } + + // // context.c + // #define A B + // #include "b.h" // file name is important to reproduce the issue + // #include "a.h" // file name is important to reproduce the issue + + // // a.h and b.h + // int A; + public void testUpdatingHeaderInContext_367315() throws Exception { + String[] contents= getContentsForTest(2); + final IIndexManager indexManager = CCorePlugin.getIndexManager(); + TestSourceReader.createFile(fCProject.getProject(), "context.c", contents[0]); + IFile ah= TestSourceReader.createFile(fCProject.getProject(), "a.h", contents[1]); + IFile bh= TestSourceReader.createFile(fCProject.getProject(), "b.h", contents[1]); + indexManager.reindex(fCProject); + waitForIndexer(); + fIndex.acquireReadLock(); + try { + IIndexBinding[] vars = fIndex.findBindings("B".toCharArray(), IndexFilter.ALL_DECLARED, new NullProgressMonitor()); + assertEquals(1, vars.length); + assertEquals(2, fIndex.findDefinitions(vars[0]).length); + } finally { + fIndex.releaseReadLock(); + } + + final CoreModel coreModel = CCorePlugin.getDefault().getCoreModel(); + ICElement[] selection = new ICElement[] {coreModel.create(ah), coreModel.create(bh)}; + indexManager.update(selection, IIndexManager.UPDATE_ALL); + waitForIndexer(); + fIndex.acquireReadLock(); + try { + IIndexBinding[] vars = fIndex.findBindings("B".toCharArray(), IndexFilter.ALL_DECLARED, new NullProgressMonitor()); + assertEquals(1, vars.length); + assertEquals(2, fIndex.findDefinitions(vars[0]).length); + } finally { + fIndex.releaseReadLock(); + } + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexBasedFileContentProvider.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexBasedFileContentProvider.java index ccfc664eed6..944e6cc9817 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexBasedFileContentProvider.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/IndexBasedFileContentProvider.java @@ -47,7 +47,6 @@ import org.eclipse.core.runtime.CoreException; * Code reader factory, that fakes code readers for header files already stored in the index. */ public final class IndexBasedFileContentProvider extends InternalFileContentProvider { - private static final class NeedToParseException extends Exception {} private static final String GAP = "__gap__"; //$NON-NLS-1$ private final IIndex fIndex; @@ -135,7 +134,7 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv // Report pragma once inclusions, only if no exception was thrown. fPragmaOnce.putAll(newPragmaOnce); return new InternalFileContent(path, macros, directives, files, toList(preLoaded)); - } catch (NeedToParseException e) { + } catch (DependsOnOutdatedFileException e) { } } } catch (CoreException e) { @@ -188,7 +187,7 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv Map newPragmaOnce, LinkedHashSet preLoaded, List files, List macros, List usingDirectives, - Set preventRecursion) throws CoreException, NeedToParseException { + Set preventRecursion) throws CoreException, DependsOnOutdatedFileException { if (file.equals(stopAt)) return true; @@ -211,8 +210,6 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv final Object[] pds; if (fRelatedIndexerTask != null) { IndexFileContent content= fRelatedIndexerTask.getFileContent(fLinkage, ifl, file); - if (content == null) - throw new NeedToParseException(); uds= content.getUsingDirectives(); pds= content.getPreprocessingDirectives(); } else { @@ -252,7 +249,7 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv @Override public InternalFileContent getContentForContextToHeaderGap(String path, - IMacroDictionary macroDictionary) { + IMacroDictionary macroDictionary) throws DependsOnOutdatedFileException { if (fContextToHeaderGap == null) { return null; } @@ -268,12 +265,8 @@ public final class IndexBasedFileContentProvider extends InternalFileContentProv ArrayList macros= new ArrayList(); ArrayList directives= new ArrayList(); LinkedHashSet preLoaded= new LinkedHashSet(); - try { - if (!collectFileContent(contextFile, targetFile, newPragmaOnce, preLoaded, - filesIncluded, macros, directives, new HashSet())) { - return null; - } - } catch (NeedToParseException e) { + if (!collectFileContent(contextFile, targetFile, newPragmaOnce, preLoaded, + filesIncluded, macros, directives, new HashSet())) { return 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 c84bd8ff4da..7f216f7b0a6 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 @@ -57,6 +57,7 @@ import org.eclipse.cdt.internal.core.parser.IMacroDictionary; import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator.EvalException; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.FileVersion; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.InclusionKind; +import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContentProvider.DependsOnOutdatedFileException; import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions; import org.eclipse.cdt.internal.core.parser.scanner.MacroDefinitionParser.InvalidMacroDefinitionException; import org.eclipse.cdt.internal.core.parser.scanner.ScannerContext.BranchKind; @@ -465,8 +466,14 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { fPreIncludedFiles= null; } final String location = fLocationMap.getTranslationUnitPath(); - InternalFileContent content= fFileContentProvider.getContentForContextToHeaderGap(location, - fMacroDictionaryFacade); + InternalFileContent content; + try { + content = fFileContentProvider.getContentForContextToHeaderGap(location, + fMacroDictionaryFacade); + } catch (DependsOnOutdatedFileException e) { + // Abort the parser, handled by the abstract indexer task. + throw new RuntimeException(e); + } if (content != null && content.getKind() == InclusionKind.FOUND_IN_INDEX) { processInclusionFromIndex(0, content, false); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContentProvider.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContentProvider.java index 82668c6293b..ed41e88c356 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContentProvider.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/InternalFileContentProvider.java @@ -25,6 +25,7 @@ import org.eclipse.cdt.core.index.IIndexFileLocation; import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics; +import org.eclipse.cdt.internal.core.index.IIndexFragmentFile; import org.eclipse.cdt.internal.core.parser.IMacroDictionary; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.InclusionKind; @@ -32,6 +33,15 @@ import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContent.Inclusio * Internal implementation of the file content providers */ public abstract class InternalFileContentProvider extends IncludeFileContentProvider { + public static final class DependsOnOutdatedFileException extends Exception { + public final Object fTu; + public final IIndexFragmentFile fIndexFile; + public DependsOnOutdatedFileException(Object tu, IIndexFragmentFile file) { + fTu= tu; + fIndexFile= file; + } + } + private IIncludeFileResolutionHeuristics fIncludeResolutionHeuristics; private final Map fPragmaOnce= new HashMap(); private final Map> fLoadedVersions= new HashMap>(); @@ -64,9 +74,10 @@ public abstract class InternalFileContentProvider extends IncludeFileContentProv * or null if this cannot be done. * @param filePath the absolute location of the file. * @param macroDictionary macros defined at the inclusion point. + * @throws DependsOnOutdatedFileException */ public InternalFileContent getContentForContextToHeaderGap(String filePath, - IMacroDictionary macroDictionary) { + IMacroDictionary macroDictionary) throws DependsOnOutdatedFileException { return null; } 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 841882a5e13..ffc4d33176f 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 @@ -24,6 +24,7 @@ import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMIndexerTask; @@ -54,6 +55,7 @@ import org.eclipse.cdt.internal.core.index.IWritableIndex; import org.eclipse.cdt.internal.core.index.IndexBasedFileContentProvider; import org.eclipse.cdt.internal.core.parser.IMacroDictionary; import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContentProvider; +import org.eclipse.cdt.internal.core.parser.scanner.InternalFileContentProvider.DependsOnOutdatedFileException; import org.eclipse.cdt.internal.core.parser.util.LRUCache; import org.eclipse.cdt.utils.EFSExtensionManager; import org.eclipse.core.runtime.CoreException; @@ -783,7 +785,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { return; final Object tu = locTask.fTu; final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); - parseFile(tu, linkageID, ifl, scannerInfo, null, monitor); + parseFile(tu, getLanguage(tu, linkageID), ifl, scannerInfo, null, monitor); } } @@ -817,7 +819,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { return; final Object tu = locTask.fTu; final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); - parseFile(tu, linkageID, ifl, scannerInfo, null, monitor); + parseFile(tu, getLanguage(tu, linkageID), ifl, scannerInfo, null, monitor); if (locTask.isCompleted()) it.remove(); @@ -870,8 +872,24 @@ public abstract class AbstractIndexerTask extends PDOMWriter { return; final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, contextTu); - FileContext ctx= new FileContext(ctxFile, headerFile); - parseFile(tu, linkageID, ifl, scannerInfo, ctx, monitor); + final AbstractLanguage language = getLanguage(contextTu, linkageID); + final FileContext ctx= new FileContext(ctxFile, headerFile); + Set dependencies= null; + boolean done= false; + while (!done) { + done= true; + DependsOnOutdatedFileException d= parseFile(tu, language, ifl, scannerInfo, ctx, monitor); + if (d != null) { + // File was not parsed, because there is a dependency that needs to be + // handled before + if (dependencies == null) + dependencies= new HashSet(); + if (dependencies.add(d.fIndexFile)) { + if (parseFile(d.fTu, language, d.fIndexFile.getLocation(), scannerInfo, new FileContext(ctxFile, d.fIndexFile), monitor) == null) + done= false; + } + } + } if (!ctx.fLostPragmaOnceSemantics) return; @@ -929,21 +947,9 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } - private void parseFile(Object tu, int linkageID, IIndexFileLocation ifl, IScannerInfo scanInfo, + private DependsOnOutdatedFileException parseFile(Object tu, AbstractLanguage lang, IIndexFileLocation ifl, IScannerInfo scanInfo, FileContext ctx, IProgressMonitor pm) throws CoreException, InterruptedException { IPath path= getLabel(ifl); - AbstractLanguage[] langs= fResolver.getLanguages(tu, true); - AbstractLanguage lang= null; - for (AbstractLanguage lang2 : langs) { - if (lang2.getLinkageID() == linkageID) { - lang= lang2; - break; - } - } - if (lang == null) { - return; - } - Throwable th= null; try { if (fShowActivity) { @@ -951,18 +957,21 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } pm.subTask(getMessage(MessageKind.parsingFileTask, path.lastSegment(), path.removeLastSegments(1).toString())); - long start= System.currentTimeMillis(); FileContent codeReader= fResolver.getCodeReader(tu); - IIndexFile[] ctxFiles = ctx == null ? null : new IIndexFile[] {ctx.fContext, ctx.fOldFile}; + final boolean isSource = fResolver.isSourceUnit(tu); - IASTTranslationUnit ast= createAST(tu, lang, codeReader, scanInfo, fASTOptions, ctxFiles, pm); + long start= System.currentTimeMillis(); + IASTTranslationUnit ast= createAST(lang, codeReader, scanInfo, isSource, fASTOptions, ctx, pm); fStatistics.fParsingTime += System.currentTimeMillis() - start; if (ast != null) { - writeToIndex(linkageID, ast, codeReader.getContentsHash(), ctx, pm); + writeToIndex(lang.getLinkageID(), ast, codeReader.getContentsHash(), ctx, pm); } } catch (CoreException e) { th= e; } catch (RuntimeException e) { + final Throwable cause = e.getCause(); + if (cause instanceof DependsOnOutdatedFileException) + return (DependsOnOutdatedFileException) cause; th= e; } catch (StackOverflowError e) { th= e; @@ -976,6 +985,16 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (th != null) { swallowError(path, th); } + return null; + } + + private AbstractLanguage getLanguage(Object tu, int linkageID) { + for (AbstractLanguage language : fResolver.getLanguages(tu, true)) { + if (language.getLinkageID() == linkageID) { + return language; + } + } + return null; } private IPath getLabel(IIndexFileLocation ifl) { @@ -1033,13 +1052,13 @@ public abstract class AbstractIndexerTask extends PDOMWriter { return e; } - private final IASTTranslationUnit createAST(Object tu, AbstractLanguage language, - FileContent codeReader, IScannerInfo scanInfo, int options, - IIndexFile[] ctx2header, IProgressMonitor pm) throws CoreException { + private final IASTTranslationUnit createAST(AbstractLanguage language, FileContent codeReader, + IScannerInfo scanInfo, boolean isSource, int options, + FileContext ctx, IProgressMonitor pm) throws CoreException { if (codeReader == null) { return null; } - if (fResolver.isSourceUnit(tu)) { + if (isSource) { options |= ILanguage.OPTION_IS_SOURCE_UNIT; } if (fFileSizeLimit > 0 && fResolver.getFileSize(codeReader.getFileLocation()) > fFileSizeLimit) { @@ -1048,6 +1067,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } return null; } + final IIndexFile[] ctx2header = ctx == null ? null : new IIndexFile[] {ctx.fContext, ctx.fOldFile}; if (fCodeReaderFactory == null) { InternalFileContentProvider fileContentProvider = createInternalFileContentProvider(); if (fIsFastIndexer) { @@ -1163,14 +1183,14 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } public final IndexFileContent getFileContent(int linkageID, IIndexFileLocation ifl, - IIndexFile file) throws CoreException { + IIndexFile file) throws CoreException, DependsOnOutdatedFileException { LinkageTask map = findRequestMap(linkageID); if (map != null) { LocationTask request= map.find(ifl); if (request != null) { FileVersionTask task= request.findVersion(file); if (task != null && task.fOutdated) - return null; + throw new DependsOnOutdatedFileException(request.fTu, task.fIndexFile); } } IndexFileContent fc= fIndexContentCache.get(file);