diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexIncludeTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexIncludeTest.java index 4f59f62f746..805e6e1ad7d 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexIncludeTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexIncludeTest.java @@ -14,7 +14,11 @@ *******************************************************************************/ package org.eclipse.cdt.internal.index.tests; +import static org.eclipse.cdt.core.testplugin.util.TestSourceReader.createFile; + import java.io.ByteArrayInputStream; +import java.util.HashSet; +import java.util.Set; import java.util.regex.Pattern; import org.eclipse.cdt.core.CCorePlugin; @@ -25,6 +29,7 @@ import org.eclipse.cdt.core.dom.ast.IVariable; 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.IIndexInclude; import org.eclipse.cdt.core.index.IndexFilter; import org.eclipse.cdt.core.index.IndexLocationFactory; @@ -36,11 +41,13 @@ import org.eclipse.cdt.core.testplugin.TestScannerProvider; import org.eclipse.cdt.core.testplugin.util.TestSourceReader; import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; +import org.junit.Assert; import junit.framework.TestSuite; @@ -642,6 +649,143 @@ public class IndexIncludeTest extends IndexTestBase { } } + // #pragma once + // #ifdef ABC + // int x = 5; + // #endif + + // #pragma once + // #include "b.hpp" + + // #pragma once + // #include "b.hpp" + + // #include "a1.hpp" + // #include "a2.hpp" + public void testSignificantMacrosWithPragmeOnceSemantic() throws Exception { + waitForIndexer(); + IProject prj = fProject.getProject(); + TestScannerProvider.sIncludes = new String[] { prj.getLocation().toOSString() }; + CharSequence[] contents = getContentsForTest(5); + + IFile b = createFile(prj, "b.hpp", contents[0].toString()); + IFile a1 = createFile(prj, "a1.hpp", contents[1].toString()); + IFile a2 = createFile(prj, "a2.hpp", contents[2].toString()); + + final IFile main = createFile(prj, "UltimateTest.cpp", contents[3].toString()); + + waitUntilFileIsIndexed(fIndex, b); + waitUntilFileIsIndexed(fIndex, a1); + waitUntilFileIsIndexed(fIndex, a2); + waitUntilFileIsIndexed(fIndex, main); + + fIndex.acquireReadLock(); + try { + IIndexFile[] indexFiles = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, + IndexLocationFactory.getWorkspaceIFL(main)); + + IIndexFile ultimateTestCppIdx = indexFiles[0]; + IIndexFile includes[] = new IIndexFile[3]; + includes[0] = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(b))[0]; + includes[1] = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(a1))[0]; + includes[2] = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(a2))[0]; + + for (int i = 0; i < includes.length; i++) { + IIndexFile include = includes[i]; + outputUnresolvedIncludes(fIndex, include.getLocation(), ultimateTestCppIdx, new HashSet()); + } + } finally { + fIndex.releaseReadLock(); + } + } + + // #pragma once + // #ifdef ABC + // int x = 5; + // #endif + + // #pragma once + // #include "b.hpp" + + // #pragma once + // #include "b.hpp" + + // #pragma once + // #include "b.hpp" + + // #pragma once + // #include "b.hpp" + + // #include "a1.hpp" + // #include "a2.hpp" + + // #include "a3.hpp" + // #include "a4.hpp" + public void testSignificantMacrosWithPragmeOnceFromIdxSemantic() throws Exception { + waitForIndexer(); + IProject prj = fProject.getProject(); + TestScannerProvider.sIncludes = new String[] { prj.getLocation().toOSString() }; + CharSequence[] contents = getContentsForTest(7); + + IFile b = createFile(prj, "b.hpp", contents[0].toString()); + IFile a1 = createFile(prj, "a1.hpp", contents[1].toString()); + IFile a2 = createFile(prj, "a2.hpp", contents[2].toString()); + IFile a3 = createFile(prj, "a3.hpp", contents[3].toString()); + IFile a4 = createFile(prj, "a4.hpp", contents[4].toString()); + + final IFile s1 = createFile(prj, "s1.cpp", contents[5].toString()); + final IFile s2 = createFile(prj, "s2.cpp", contents[6].toString()); + + waitUntilFileIsIndexed(fIndex, b); + waitUntilFileIsIndexed(fIndex, a1); + waitUntilFileIsIndexed(fIndex, a2); + waitUntilFileIsIndexed(fIndex, a3); + waitUntilFileIsIndexed(fIndex, a4); + waitUntilFileIsIndexed(fIndex, s1); + waitUntilFileIsIndexed(fIndex, s2); + + fIndex.acquireReadLock(); + try { + IIndexFile[] indexFiles = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, + IndexLocationFactory.getWorkspaceIFL(s1)); + + IIndexFile ultimateTestCppIdx = indexFiles[0]; + IIndexFile includes[] = new IIndexFile[5]; + includes[0] = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(b))[0]; + includes[1] = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(a1))[0]; + includes[2] = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(a2))[0]; + includes[3] = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(a3))[0]; + includes[4] = fIndex.getFiles(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(a4))[0]; + + for (int i = 0; i < includes.length; i++) { + IIndexFile include = includes[i]; + outputUnresolvedIncludes(fIndex, include.getLocation(), ultimateTestCppIdx, new HashSet()); + } + } finally { + fIndex.releaseReadLock(); + } + } + + private void outputUnresolvedIncludes(IIndex index, IIndexFileLocation ifl, IIndexFile ifile, + Set handled) throws CoreException { + if (ifile == null) { + Assert.fail(ifl.getURI() + " is not indexed"); + } else if (handled.add(ifile)) { + IIndexInclude[] includes = ifile.getIncludes(); + for (IIndexInclude inc : includes) { + if (inc.isActive()) { + if (inc.isResolved()) { + IIndexFile next = index.resolveInclude(inc); + outputUnresolvedIncludes(index, inc.getIncludesLocation(), next, handled); + } else { + Assert.fail("Unresolved inclusion: " + inc.getFullName() + " in file " + + inc.getIncludedByLocation().getURI()); + } + } + } + } + } + private void standardCheckUpdateIncludes(IFile header, IFile s1, String tag) throws Exception { fIndex.acquireReadLock(); try { 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 344d05c50f5..db48df4bc06 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 @@ -185,7 +185,13 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { final InternalFileContent fc; IFileNomination once = fFileContentProvider.isIncludedWithPragmaOnceSemantics(path); if (once != null) { - fc = new InternalFileContent(path, InclusionKind.SKIP_FILE); + ISignificantMacros significantMacros = ISignificantMacros.NONE; + try { + significantMacros = once.getSignificantMacros(); + } catch (CoreException e) { + e.printStackTrace(); + } + fc = new InternalFileContent(path, InclusionKind.SKIP_PRAGMA_ONCE_FILE, significantMacros); } else { fc = fFileContentProvider.getContentForInclusion(path, fMacroDictionaryFacade); } @@ -1790,11 +1796,19 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { case SKIP_FILE: // Already included or fast parsing mode. break; + + case SKIP_PRAGMA_ONCE_FILE: + fCurrentContext.addSignificantMacros(fi.getSignificantMacros()); + break; } if (stmt == null) { // Found in index or skipped. stmt = fLocationMap.encounterPoundInclude(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, headerName, path, userInclude, active, isHeuristic, nominationDelegate); + if (fi.getKind() == InclusionKind.SKIP_PRAGMA_ONCE_FILE) { + stmt.setSignificantMacros(fi.getSignificantMacros()); + stmt.setPragamOnceSemantics(true); + } } // In a pragma once context store loaded versions of this non-pragma-once include if (pragmaOnceContext && loadedVerisons != null && !loadedVerisons.isEmpty()) { @@ -1812,6 +1826,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { for (FileVersion version : fi.getNonPragmaOnceVersions()) { fFileContentProvider.addLoadedVersions(version.fPath, Integer.MAX_VALUE, version.fSigMacros); } + fLocationMap.skippedFile(fLocationMap.getSequenceNumberForOffset(offset), fi); } 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 0d78aa1dc89..e5889f72936 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 @@ -32,6 +32,11 @@ public class InternalFileContent extends FileContent { * Instruct the preprocessor to skip this inclusion. */ SKIP_FILE, + /** + * Instruct the preprocessor to skip this inclusion because it has pragma + * once semantic and has already been include for current translation unit. + */ + SKIP_PRAGMA_ONCE_FILE, /** * The file and its dependents are indexed, required information is read * from there. @@ -67,6 +72,7 @@ public class InternalFileContent extends FileContent { private final long fTimestamp; private final long fFileSize; private final long fReadTime; + private final ISignificantMacros fSignificantMacros; /** * For skipping include files. @@ -88,6 +94,33 @@ public class InternalFileContent extends FileContent { fTimestamp = NULL_TIMESTAMP; fFileSize = NULL_FILE_SIZE; fReadTime = 0; + fSignificantMacros = null; + } + + /** + * For skipping include files that have pragma once semantic and have already been include + * in the translation unit. Only the significant macros need to be forwarded to includer. + * @param fileLocation the location of the file. + * @param kind must be {@link InclusionKind#SKIP_FILE}. + * @param significantMacros The significant macros this file. + * @throws IllegalArgumentException if fileLocation is null or the kind value is illegal for + * this constructor. + */ + public InternalFileContent(String fileLocation, InclusionKind kind, ISignificantMacros significantMacros) + throws IllegalArgumentException { + if (fileLocation == null || kind != InclusionKind.SKIP_PRAGMA_ONCE_FILE) { + throw new IllegalArgumentException(); + } + fKind = kind; + fFileLocation = fileLocation; + fMacroDefinitions = null; + fUsingDirectives = null; + fSource = null; + fNonPragmaOnceFiles = null; + fTimestamp = NULL_TIMESTAMP; + fFileSize = NULL_FILE_SIZE; + fReadTime = 0; + fSignificantMacros = significantMacros; } /** @@ -111,6 +144,7 @@ public class InternalFileContent extends FileContent { fTimestamp = timestamp; fFileSize = fileSize; fReadTime = fileReadTime; + fSignificantMacros = null; } /** @@ -133,6 +167,7 @@ public class InternalFileContent extends FileContent { fTimestamp = NULL_TIMESTAMP; fFileSize = NULL_FILE_SIZE; fReadTime = 0; + fSignificantMacros = null; } /** @@ -154,6 +189,7 @@ public class InternalFileContent extends FileContent { fTimestamp = NULL_TIMESTAMP; fFileSize = NULL_FILE_SIZE; fReadTime = 0; + fSignificantMacros = null; } /** @@ -274,4 +310,11 @@ public class InternalFileContent extends FileContent { public String toString() { return getSource().toString(); } + + public ISignificantMacros getSignificantMacros() { + if (fKind != InclusionKind.SKIP_PRAGMA_ONCE_FILE) { + throw new IllegalArgumentException(); + } + return fSignificantMacros; + } }