From e6bae4030859721c97f66759a16686fc460c729e Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Fri, 22 Mar 2013 16:37:53 -0700 Subject: [PATCH] Bug 45203. Added support for IWYU export pragmas. --- .../core/parser/tests/ast2/TestLexerLog.java | 4 +- .../tests/scanner/LocationMapTests.java | 30 ++++--- .../cdt/core/testplugin/TestScannerInfo.java | 6 +- .../core/testplugin/TestScannerProvider.java | 2 +- .../internal/core/model/AsmModelBuilder.java | 4 +- .../internal/core/model/TranslationUnit.java | 9 ++- .../ast/IASTPreprocessorIncludeStatement.java | 10 ++- .../eclipse/cdt/core/index/IIndexInclude.java | 17 ++-- .../cdt/core/index/IndexLocationFactory.java | 2 +- .../cdt/core/parser/ExtendedScannerInfo.java | 30 ++++++- .../org/eclipse/cdt/core/parser/IScanner.java | 28 ++++--- .../core/parser/IncludeExportPatterns.java | 63 +++++++++++++++ .../parser/scanner/ASTPreprocessorNode.java | 11 ++- .../parser/scanner/AbstractCharArray.java | 45 ++++++++++- .../core/parser/scanner/CPreprocessor.java | 15 +++- .../core/parser/scanner/ILexerLog.java | 5 +- .../internal/core/parser/scanner/Lexer.java | 10 ++- .../core/parser/scanner/LocationCtxFile.java | 37 ++++++--- .../core/parser/scanner/LocationMap.java | 79 ++++++++++++++++--- .../core/pdom/AbstractIndexerTask.java | 27 +++++-- .../internal/core/pdom/dom/PDOMInclude.java | 11 ++- .../pdom/indexer/AbstractPDOMIndexer.java | 14 ++-- .../core/pdom/indexer/PDOMIndexerTask.java | 18 ++++- .../indexer/ProjectIndexerInputAdapter.java | 4 +- .../cdt/core/CCorePreferenceConstants.java | 46 ++++++++++- .../core/CCorePreferenceInitializer.java | 19 +++-- ...desTest.java => IncludeOrganizerTest.java} | 44 +++++++++-- .../includes/IncludesTestSuite.java | 2 +- .../ui/refactoring/includes/IncludeMap.java | 49 +++++++++++- .../includes/IncludeOrganizer.java | 9 ++- .../includes/IncludePreferences.java | 2 +- .../includes/InclusionContext.java | 42 ++++++++++ 32 files changed, 576 insertions(+), 118 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IncludeExportPatterns.java rename core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/{OrganizeIncludesTest.java => IncludeOrganizerTest.java} (90%) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/TestLexerLog.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/TestLexerLog.java index 9be07b6f987..6cb310483ea 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/TestLexerLog.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/TestLexerLog.java @@ -12,10 +12,10 @@ package org.eclipse.cdt.core.parser.tests.ast2; import java.util.ArrayList; +import org.eclipse.cdt.internal.core.parser.scanner.AbstractCharArray; import org.eclipse.cdt.internal.core.parser.scanner.ILexerLog; public class TestLexerLog implements ILexerLog { - private ArrayList fComments= new ArrayList(); private ArrayList fProblems= new ArrayList(); private String fInput; @@ -25,7 +25,7 @@ public class TestLexerLog implements ILexerLog { } @Override - public void handleComment(boolean isBlockComment, int offset, int endOffset) { + public void handleComment(boolean isBlockComment, int offset, int endOffset, AbstractCharArray input) { fComments.add(fInput.substring(offset, endOffset)); } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java index 661231fea6f..d0f6d6ccad9 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/scanner/LocationMapTests.java @@ -106,6 +106,7 @@ public class LocationMapTests extends BaseTestCase { } private LocationMap fLocationMap; private CPPASTTranslationUnit fTu; + private CharArray fContent; public static TestSuite suite() { return suite(LocationMapTests.class); @@ -129,7 +130,8 @@ public class LocationMapTests extends BaseTestCase { } private void init(char[] content) { - fLocationMap.pushTranslationUnit(FN, new CharArray(content)); + fContent = new CharArray(content); + fLocationMap.pushTranslationUnit(FN, fContent); fTu= new CPPASTTranslationUnit(); fTu.setLocationResolver(fLocationMap); } @@ -146,8 +148,7 @@ public class LocationMapTests extends BaseTestCase { IASTFileLocation loc= node.getFileLocation(); checkLocation(loc, filename, offset, length, line, endline); assertEquals(sig, node.getRawSignature()); - } - else { + } else { assertNull(node.getFileLocation()); } } @@ -169,8 +170,7 @@ public class LocationMapTests extends BaseTestCase { if (loc == null) { assertEquals(0, offset); assertEquals(0, length); - } - else { + } else { assertEquals(filename, loc.getFileName()); assertEquals(offset, loc.getNodeOffset()); assertEquals(length, loc.getNodeLength()); @@ -301,9 +301,9 @@ public class LocationMapTests extends BaseTestCase { public void testComment() { init(DIGITS); - fLocationMap.encounteredComment(0, 0, false); - fLocationMap.encounteredComment(1,3, true); - fLocationMap.encounteredComment(5,16,true); + fLocationMap.encounteredComment(0, 0, false, fContent); + fLocationMap.encounteredComment(1, 3, true, fContent); + fLocationMap.encounteredComment(5, 16, true, fContent); IASTComment[] comments= fLocationMap.getComments(); assertEquals(3, comments.length); checkComment(comments[0], "", false, FN, 0, 0, 1, 1); @@ -311,7 +311,6 @@ public class LocationMapTests extends BaseTestCase { checkComment(comments[2], "56789abcdef", true, FN, 5,11,1,1); } - public void testProblems() { init(DIGITS); fLocationMap.encounterProblem(0, null, 0, 0); @@ -479,9 +478,9 @@ public class LocationMapTests extends BaseTestCase { IASTName name2= fLocationMap.encounterImplicitMacroExpansion(macro2, null); ILocationCtx me = fLocationMap.pushMacroExpansion(110, 115, 125, 30, macro3, new IASTName[]{name1, name2}, new ImageLocationInfo[0]); // Comment in expansion - fLocationMap.encounteredComment(116, 120, false); + fLocationMap.encounteredComment(116, 120, false, fContent); // Comment right after expansion, reported before expansion completes. - fLocationMap.encounteredComment(125, 140, false); + fLocationMap.encounteredComment(125, 140, false, fContent); fLocationMap.popContext(me); checkComment(fLocationMap.getComments()[0], new String(LONGDIGITS, 116, 4), false, FN, 116, 4, 2, 2); checkComment(fLocationMap.getComments()[1], new String(LONGDIGITS, 125, 15), false, FN, 125, 15, 2, 2); @@ -513,14 +512,14 @@ public class LocationMapTests extends BaseTestCase { // number: [6,15)[25,26) ILocationCtx i1= fLocationMap.pushInclusion(0, 2, 4, 6, new CharArray("b1b2b3b4b5"), "pre1", "pre1".toCharArray(), false, false, false); assertEquals("pre1", fLocationMap.getCurrentFilePath()); - fLocationMap.encounteredComment(2,4,true); + fLocationMap.encounteredComment(2, 4, true, fContent); // number: [15,25) ILocationCtx i2= fLocationMap.pushInclusion(6, 7, 8, 9, new CharArray("c1c2c3c4c5"), "pre11", "pre11".toCharArray(), false, false, false); assertEquals("pre11", fLocationMap.getCurrentFilePath()); - fLocationMap.encounteredComment(2,6,true); + fLocationMap.encounteredComment(2, 6, true, fContent); fLocationMap.popContext(i2); // add a comment before the include - fLocationMap.encounteredComment(4,6,false); + fLocationMap.encounteredComment(4, 6, false, fContent); assertEquals("pre1", fLocationMap.getCurrentFilePath()); fLocationMap.popContext(i1); @@ -530,12 +529,11 @@ public class LocationMapTests extends BaseTestCase { // number [36, 46) ILocationCtx i3= fLocationMap.pushInclusion(0, 2, 4, 6, new CharArray("d1d2d3d4d5"), "pre2", "pre2".toCharArray(), false, false, false); assertEquals("pre2", fLocationMap.getCurrentFilePath()); - fLocationMap.encounteredComment(0,2,true); + fLocationMap.encounteredComment(0, 2, true, fContent); fLocationMap.popContext(i3); fLocationMap.popContext(pre1); assertEquals(FN, fLocationMap.getCurrentFilePath()); - IASTComment[] comments= fLocationMap.getComments(); checkComment(comments[0], "b2", true, "pre1", 2, 2, 1, 1); checkComment(comments[1], "c2c3", true, "pre11", 2, 4, 1, 1); diff --git a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/TestScannerInfo.java b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/TestScannerInfo.java index 94175fac895..6235fbc4b19 100644 --- a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/TestScannerInfo.java +++ b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/TestScannerInfo.java @@ -14,15 +14,15 @@ package org.eclipse.cdt.core.testplugin; import java.util.Collections; import java.util.Map; -import org.eclipse.cdt.core.parser.IExtendedScannerInfo; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; -public class TestScannerInfo implements IExtendedScannerInfo { +public class TestScannerInfo extends ExtendedScannerInfo { private static final String[] EMPTY = {}; private String[] fIncludes; private String[] fIncludeFiles; private String[] fMacroFiles; - public TestScannerInfo(String[] includes, String[] includeFiles, String[] macroFiles) { + public TestScannerInfo(String[] includes, String[] macroFiles, String[] includeFiles) { fIncludes= includes; fIncludeFiles= includeFiles; fMacroFiles= macroFiles; diff --git a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/TestScannerProvider.java b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/TestScannerProvider.java index d1f0fbac1c0..6fa5de23567 100644 --- a/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/TestScannerProvider.java +++ b/core/org.eclipse.cdt.core.tests/suite/org/eclipse/cdt/core/testplugin/TestScannerProvider.java @@ -29,7 +29,7 @@ public class TestScannerProvider extends AbstractCExtension implements IScannerI @Override public IScannerInfo getScannerInformation(IResource resource) { - return new TestScannerInfo(sIncludes, sIncludeFiles, sMacroFiles); + return new TestScannerInfo(sIncludes, sMacroFiles, sIncludeFiles); } @Override diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/AsmModelBuilder.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/AsmModelBuilder.java index a9bf1726d20..e7edaaa31ee 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/AsmModelBuilder.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/AsmModelBuilder.java @@ -20,6 +20,7 @@ import org.eclipse.cdt.core.model.IContributedModelBuilder; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.parser.IToken; import org.eclipse.cdt.core.parser.OffsetLimitReachedException; +import org.eclipse.cdt.internal.core.parser.scanner.AbstractCharArray; import org.eclipse.cdt.internal.core.parser.scanner.ILexerLog; import org.eclipse.cdt.internal.core.parser.scanner.Lexer; import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions; @@ -42,7 +43,8 @@ public class AsmModelBuilder implements IContributedModelBuilder { private static final class LexerLog implements ILexerLog { @Override - public void handleComment(boolean isBlockComment, int offset, int endOffset) { + public void handleComment(boolean isBlockComment, int offset, int endOffset, + AbstractCharArray input) { } @Override public void handleProblem(int problemID, char[] info, int offset, int endOffset) { diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnit.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnit.java index 930ac7c345b..7325f61bf5e 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnit.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnit.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 QNX Software Systems and others. + * Copyright (c) 2000, 2013 QNX Software Systems 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 @@ -58,13 +58,13 @@ import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.IUsing; import org.eclipse.cdt.core.model.IWorkingCopy; import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; import org.eclipse.cdt.core.parser.FileContent; import org.eclipse.cdt.core.parser.IParserLogService; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.IScannerInfoProvider; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; import org.eclipse.cdt.core.parser.ParserUtil; -import org.eclipse.cdt.core.parser.ScannerInfo; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit; @@ -1045,14 +1045,15 @@ public class TranslationUnit extends Openable implements ITranslationUnit { return scanInfo; } if (force) { - return new ScannerInfo(); + return new ExtendedScannerInfo(); } return null; } /** * Return the language of the context this file was parsed in. Works only after using - * {@link #getAST(IIndex, int, IProgressMonitor)} with the flag {@link ITranslationUnit#AST_CONFIGURE_USING_SOURCE_CONTEXT}. + * {@link #getAST(IIndex, int, IProgressMonitor)} with the flag + * {@link ITranslationUnit#AST_CONFIGURE_USING_SOURCE_CONTEXT}. */ public ILanguage getLanguageOfContext() throws CoreException { final ILanguage result= fLanguageOfContext; 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 998f3ada3ee..27f1237424d 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2012 IBM Corporation and others. + * Copyright (c) 2004, 2013 IBM Corporation 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 @@ -106,6 +106,14 @@ public interface IASTPreprocessorIncludeStatement extends IASTPreprocessorStatem */ public boolean isErrorInIncludedFile(); + /** + * Returns {@code true} if the included file is exported by the including header. + * + * @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas" + * @since 5.5 + */ + public boolean isIncludedFileExported(); + /** * Returns {@code true}, if an attempt will be or has been made to create AST for the target * of this inclusion. diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexInclude.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexInclude.java index 0e6d479036f..cb52b4ffb8a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexInclude.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexInclude.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2009 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2013 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 @@ -97,21 +97,28 @@ public interface IIndexInclude { * Test whether this include has been resolved (found in the file system). * Inactive includes are not resolved, unless they constitute a hidden dependency. * This is the case when an include is inactive because it has been included before: - * + *
 	 *   #ifndef _header_h
 	 *   #include "header.h"
 	 *   #endif
-	 * 
-	 * 
+	 * 
+ * * @return whether this is a resolved include * @throws CoreException */ boolean isResolved() throws CoreException; - + /** * Tests whether this include has been resolved using a heuristics rather than relying on * the include search path. * @since 5.1 */ boolean isResolvedByHeuristics() throws CoreException; + + /** + * Returns {@code true} if the included file is exported by the including header. + * @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas" + * @since 5.5 + */ + boolean isIncludedFileExported() throws CoreException; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IndexLocationFactory.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IndexLocationFactory.java index faf7147a02b..e5f3a098e53 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IndexLocationFactory.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IndexLocationFactory.java @@ -142,7 +142,7 @@ public class IndexLocationFactory { public static IIndexFileLocation getIFL(ITranslationUnit tu) { IResource res = tu.getResource(); if (res instanceof IFile) { - return getWorkspaceIFL((IFile)res); + return getWorkspaceIFL((IFile) res); } IPath location = tu.getLocation(); if (location != null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ExtendedScannerInfo.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ExtendedScannerInfo.java index cd34f777dfb..d6872ced177 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ExtendedScannerInfo.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/ExtendedScannerInfo.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2009 IBM Corporation and others. + * Copyright (c) 2005, 2013 IBM Corporation 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 @@ -8,6 +8,7 @@ * Contributors: * IBM Rational Software - Initial API and implementation * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.core.parser; @@ -16,12 +17,14 @@ import java.util.Map; /** * Implementation for the {@link IExtendedScannerInfo} interface. Allows to configure * the preprocessor. + * @since 5.5 */ public class ExtendedScannerInfo extends ScannerInfo implements IExtendedScannerInfo { private static final String[] EMPTY_STRING_ARRAY = {}; private String[] macroFiles; private String[] includeFiles; private String[] localIncludePaths; + private IncludeExportPatterns includeExportPatterns; public ExtendedScannerInfo() { } @@ -56,6 +59,9 @@ public class ExtendedScannerInfo extends ScannerInfo implements IExtendedScanner includeFiles = einfo.getIncludeFiles(); localIncludePaths = einfo.getLocalIncludePath(); } + if (info instanceof ExtendedScannerInfo) { + includeExportPatterns = ((ExtendedScannerInfo) info).includeExportPatterns; + } } @Override @@ -78,4 +84,26 @@ public class ExtendedScannerInfo extends ScannerInfo implements IExtendedScanner return EMPTY_STRING_ARRAY; return localIncludePaths; } + + /** + * Returns the regular expression patterns matching export directives for included files. + * @see IncludeExportPatterns + * + * @noreference This method is not intended to be referenced by clients. + * @since 5.5 + */ + public IncludeExportPatterns getIncludeExportPatterns() { + return includeExportPatterns; + } + + /** + * Sets the regular expression patterns matching export directives for included files. + * @see IncludeExportPatterns + * + * @noreference This method is not intended to be referenced by clients. + * @since 5.5 + */ + public void setIncludeExportPatterns(IncludeExportPatterns patterns) { + includeExportPatterns= patterns; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IScanner.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IScanner.java index e23d3047bda..03c10741081 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IScanner.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IScanner.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2003, 2009 IBM Corporation and others. + * Copyright (c) 2003, 2013 IBM Corporation 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 @@ -8,24 +8,19 @@ * Contributors: * IBM Corporation - initial API and implementation * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.core.parser; import java.util.Map; -import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver; import org.eclipse.cdt.internal.core.parser.scanner.Lexer; /** * Interface between the parser and the preprocessor. - *

- * EXPERIMENTAL. This class or interface has been added as - * part of a work in progress. There is no guarantee that this API will - * work or that it will remain the same. Please do not use this API without - * consulting with the CDT team. - *

+ * * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ @@ -75,12 +70,25 @@ public interface IScanner { /** * Turns on/off creation of image locations. - * @see IASTName#getImageLocation() + * @see org.eclipse.cdt.core.dom.ast.IASTName#getImageLocation() * @noreference This method is not intended to be referenced by clients. * @since 5.0 */ public void setComputeImageLocations(boolean val); - + + /** + * Turns on/off tracking if exported included files. + * @see org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement#isIncludedFileExported() + * @see IncludeExportPatterns + * + * @param patterns if not {{@code null}, include export tracking is enabled, otherwise it is + * disabled + * + * @noreference This method is not intended to be referenced by clients. + * @since 5.5 + */ + public void setTrackIncludeExport(IncludeExportPatterns patterns); + /** * Toggles generation of tokens for inactive code branches. When turned on, * each inactive code branch is preceded by a token of kind {@link IToken#tINACTIVE_CODE_START} and diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IncludeExportPatterns.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IncludeExportPatterns.java new file mode 100644 index 00000000000..e0f5ded669c --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/IncludeExportPatterns.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2013 Google, 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: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.parser; + +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Container for include export patterns, for example "IWYU pragma: export", + * "IWYU pragma: begin_exports" and "IWYU pragma: end_exports". + * @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas" + * + * @since 5.5 + */ +public class IncludeExportPatterns { + private final Pattern includeExportPattern; + private final Pattern includeBeginExportsPattern; + private final Pattern includeEndExportsPattern; + + public IncludeExportPatterns(String exportPattern, String beginExportsPattern, + String endExportsPattern) { + this.includeExportPattern = compilePattern(exportPattern); + this.includeBeginExportsPattern = compilePattern(beginExportsPattern); + this.includeEndExportsPattern = compilePattern(endExportsPattern); + } + + private Pattern compilePattern(String pattern) { + try { + return pattern == null ? null : Pattern.compile(pattern); + } catch (PatternSyntaxException e) { + return null; + } + } + + /** + * Returns the include export pattern, e.g. "IWYU pragma: export". + */ + public Pattern getIncludeExportPattern() { + return includeExportPattern; + } + + /** + * Returns the include export pattern, e.g. "IWYU pragma: begin_exports". + */ + public Pattern getIncludeBeginExportsPattern() { + return includeBeginExportsPattern; + } + + /** + * Returns the include export pattern, e.g. "IWYU pragma: end_exports". + */ + public Pattern getIncludeEndExportsPattern() { + return includeEndExportsPattern; + } +} 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 993acd2402a..0e780560f94 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2012 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2013 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 @@ -291,6 +291,7 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces private final boolean fIsResolved; private final boolean fIsSystemInclude; private final boolean fFoundByHeuristics; + private final boolean fIncludedFileExported; private final IFileNomination fNominationDelegate; private boolean fPragmaOnce; private boolean fCreatesAST; @@ -305,7 +306,7 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces public ASTInclusionStatement(IASTTranslationUnit parent, int startNumber, int nameStartNumber, int nameEndNumber, int endNumber, char[] headerName, String filePath, boolean userInclude, boolean active, boolean heuristic, - IFileNomination nominationDelegate) { + boolean exportedFile, IFileNomination nominationDelegate) { super(parent, IASTTranslationUnit.PREPROCESSOR_STATEMENT, startNumber, endNumber); fName= new ASTPreprocessorName(this, IASTPreprocessorIncludeStatement.INCLUDE_NAME, nameStartNumber, nameEndNumber, headerName, null); @@ -315,6 +316,7 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces fFoundByHeuristics= heuristic; fSignificantMacros= ISignificantMacros.NONE; fNominationDelegate= nominationDelegate; + fIncludedFileExported= exportedFile; if (!active) { setInactive(); } @@ -459,6 +461,11 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces fErrorInIncludedFile= error; } + @Override + public boolean isIncludedFileExported() { + return fIncludedFileExported; + } + @Override public boolean createsAST() { return fCreatesAST; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/AbstractCharArray.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/AbstractCharArray.java index dfe7e27a2da..360a4950366 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/AbstractCharArray.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/AbstractCharArray.java @@ -48,11 +48,18 @@ public abstract class AbstractCharArray { public abstract char get(int offset); /** - * Copy a range of characters to the given destination. Subclasses do not have to do any + * Copies a range of characters to the given destination. Subclasses do not have to do any * range checks. */ public abstract void arraycopy(int offset, char[] destination, int destinationPos, int length); + /** + * Returns the {@link CharSequence} representing a range in the character array. + */ + public CharSequence subSequence(int start, int end) { + return new SubArray(start, end); + } + /** * Returns {@code true} if there were I/O errors while retrieving contents of this array. */ @@ -69,4 +76,40 @@ public abstract class AbstractCharArray { } return buf.toString(); } + + private class SubArray implements CharSequence { + private final int start; + private final int end; + + SubArray(int start, int end) { + checkStartEnd(start, end); + this.start = start; + this.end = end; + } + + @Override + public int length() { + return end - start; + } + + @Override + public char charAt(int index) { + return get(start + index); + } + + @Override + public CharSequence subSequence(int start, int end) { + checkStartEnd(start, end); + if (end > this.end - this.start) + throw new IndexOutOfBoundsException(String.valueOf(end)); + return new SubArray(this.start + start, this.start + end); + } + + private void checkStartEnd(int start, int end) { + if (start < 0) + throw new IndexOutOfBoundsException(String.valueOf(start)); + if (end < start) + throw new IndexOutOfBoundsException(String.valueOf(end) + " < " + String.valueOf(start)); //$NON-NLS-1$ + } + } } 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 6d6518d4200..1b1166f3e75 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2012 IBM Corporation and others. + * Copyright (c) 2004, 2013 IBM Corporation 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 @@ -32,6 +32,7 @@ import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.parser.AbstractParserLogService; import org.eclipse.cdt.core.parser.EndOfFileException; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; import org.eclipse.cdt.core.parser.FileContent; import org.eclipse.cdt.core.parser.IExtendedScannerInfo; import org.eclipse.cdt.core.parser.IMacro; @@ -42,6 +43,7 @@ import org.eclipse.cdt.core.parser.IScanner; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.ISignificantMacros; import org.eclipse.cdt.core.parser.IToken; +import org.eclipse.cdt.core.parser.IncludeExportPatterns; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; import org.eclipse.cdt.core.parser.Keywords; import org.eclipse.cdt.core.parser.OffsetLimitReachedException; @@ -290,6 +292,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { fLexOptions.fSupportSlashPercentComments= configuration.supportSlashPercentComments(); fLexOptions.fSupportUTFLiterals = configuration.supportUTFLiterals(); fLexOptions.fSupportRawStringLiterals = configuration.supportRawStringLiterals(); + if (info instanceof ExtendedScannerInfo) + fLexOptions.fIncludeExportPatterns = ((ExtendedScannerInfo) info).getIncludeExportPatterns(); fLocationMap= new LocationMap(fLexOptions); fKeywords= new CharArrayIntMap(40, -1); fPPKeywords= new CharArrayIntMap(40, -1); @@ -349,6 +353,11 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { fLexOptions.fCreateImageLocations= val; } + @Override + public void setTrackIncludeExport(IncludeExportPatterns patterns) { + fLexOptions.fIncludeExportPatterns= patterns; + } + @Override public void setContentAssistMode(int offset) { fContentAssistLimit= offset; @@ -1205,8 +1214,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable { } @Override - public void handleComment(boolean isBlockComment, int offset, int endOffset) { - fLocationMap.encounteredComment(offset, endOffset, isBlockComment); + public void handleComment(boolean isBlockComment, int offset, int endOffset, AbstractCharArray input) { + fLocationMap.encounteredComment(offset, endOffset, isBlockComment, input); } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILexerLog.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILexerLog.java index bb1837e07c8..c8f46769774 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILexerLog.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/ILexerLog.java @@ -19,7 +19,7 @@ import org.eclipse.cdt.core.parser.IProblem; public interface ILexerLog { ILexerLog NULL = new ILexerLog() { @Override - public void handleComment(boolean isBlockComment, int offset, int endOffset) {} + public void handleComment(boolean isBlockComment, int offset, int endOffset, AbstractCharArray input) {} @Override public void handleProblem(int problemID, char[] info, int offset, int endOffset) {} }; @@ -39,6 +39,7 @@ public interface ILexerLog { * @param source the input of the lexer. * @param offset the offset where the comment starts * @param endOffset the offset where the comment ends + * @param input the contents of the file being parsed */ - void handleComment(boolean isBlockComment, int offset, int endOffset); + void handleComment(boolean isBlockComment, int offset, int endOffset, AbstractCharArray input); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java index f65f9dcb5da..90c2925af9f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/Lexer.java @@ -15,6 +15,7 @@ package org.eclipse.cdt.internal.core.parser.scanner; import org.eclipse.cdt.core.parser.IGCCToken; import org.eclipse.cdt.core.parser.IProblem; import org.eclipse.cdt.core.parser.IToken; +import org.eclipse.cdt.core.parser.IncludeExportPatterns; import org.eclipse.cdt.core.parser.OffsetLimitReachedException; import org.eclipse.cdt.core.parser.util.CharArrayUtils; @@ -56,6 +57,7 @@ final public class Lexer implements ITokenSequence { public boolean fSupportSlashPercentComments= false; public boolean fSupportUTFLiterals= true; public boolean fSupportRawStringLiterals= false; + public IncludeExportPatterns fIncludeExportPatterns; @Override public Object clone() { @@ -694,21 +696,21 @@ final public class Lexer implements ITokenSequence { } private void blockComment(final int start, final char trigger) { - // we can ignore line-splices, trigraphs and windows newlines when searching for the '*' + // We can ignore line-splices, trigraphs and windows newlines when searching for the '*' int pos= fEndOffset; while (isValidOffset(pos)) { if (fInput.get(pos++) == trigger) { fEndOffset= pos; if (nextCharPhase3() == '/') { nextCharPhase3(); - fLog.handleComment(true, start, fOffset); + fLog.handleComment(true, start, fOffset, fInput); return; } } } fCharPhase3= END_OF_INPUT; fOffset= fEndOffset= pos; - fLog.handleComment(true, start, pos); + fLog.handleComment(true, start, pos, fInput); } private void lineComment(final int start) { @@ -717,7 +719,7 @@ final public class Lexer implements ITokenSequence { switch (c) { case END_OF_INPUT: case '\n': - fLog.handleComment(false, start, fOffset); + fLog.handleComment(false, start, fOffset, fInput); return; } c= nextCharPhase3(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java index a33b6195dbc..d9c82e5f5b9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationCtxFile.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2009 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2013 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 @@ -7,6 +7,7 @@ * * Contributors: * Markus Schorn - initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.parser.scanner; @@ -24,6 +25,8 @@ class LocationCtxFile extends LocationCtxContainer { private final String fFilename; private final ASTInclusionStatement fASTInclude; private final boolean fIsSource; + private boolean fInsideIncludeExportBlock; + private int fOffsetOfIncludeExport = -1; public LocationCtxFile(LocationCtxContainer parent, String filename, AbstractCharArray source, int parentOffset, int parentEndOffset, int sequenceNumber, @@ -46,9 +49,9 @@ class LocationCtxFile extends LocationCtxContainer { @Override public ASTFileLocation findMappedFileLocation(int sequenceNumber, int length) { - // try to delegate to a child. + // Try to delegate to a child. final int testEnd= length > 1 ? sequenceNumber + length - 1 : sequenceNumber; - final int sequenceEnd= sequenceNumber+length; + final int sequenceEnd= sequenceNumber + length; final LocationCtx child1= findChildLessOrEqualThan(sequenceNumber, false); final LocationCtx child2= testEnd == sequenceNumber ? child1 : findChildLessOrEqualThan(testEnd, false); @@ -58,17 +61,17 @@ class LocationCtxFile extends LocationCtxContainer { return child1.findMappedFileLocation(sequenceNumber, length); } - // handle here + // Handle here. int startOffset; int endOffset; if (child1 == null) { - startOffset= sequenceNumber-fSequenceNumber; + startOffset= sequenceNumber - fSequenceNumber; } else { int childSequenceEnd= child1.fSequenceNumber + child1.getSequenceLength(); if (sequenceNumber < childSequenceEnd) { startOffset= child1.fOffsetInParent; - } else { // start beyond child1 + } else { // Start beyond child1 startOffset= child1.fEndOffsetInParent + sequenceNumber - childSequenceEnd; } } @@ -76,7 +79,7 @@ class LocationCtxFile extends LocationCtxContainer { endOffset= sequenceEnd - fSequenceNumber; } else { int childSequenceEnd= child2.fSequenceNumber + child2.getSequenceLength(); - if (childSequenceEnd < sequenceEnd) { // beyond child2 + if (childSequenceEnd < sequenceEnd) { // Beyond child2 endOffset= child2.fEndOffsetInParent + sequenceEnd - childSequenceEnd; } else { endOffset= child2.fEndOffsetInParent; @@ -112,12 +115,12 @@ class LocationCtxFile extends LocationCtxContainer { ArrayList list) { Collection children= getChildren(); for (LocationCtx ctx : children) { - // context must start before the end of the search range + // Context must start before the end of the search range. if (ctx.fOffsetInParent >= offset+length) { break; } if (ctx instanceof LocationCtxMacroExpansion) { - // expansion must end after the search start + // Expansion must end after the search start. if (ctx.fEndOffsetInParent > offset) { IASTNode macroExpansion = ((LocationCtxMacroExpansion) ctx).getMacroReference().getParent(); @@ -136,4 +139,20 @@ class LocationCtxFile extends LocationCtxContainer { public String toString() { return fFilename; } + + public boolean isInsideIncludeExportBlock() { + return fInsideIncludeExportBlock; + } + + public void setInsideIncludeExportBlock(boolean fInsideIncludeExportBlock) { + this.fInsideIncludeExportBlock = fInsideIncludeExportBlock; + } + + public int getOffsetOfIncludeExport() { + return fOffsetOfIncludeExport; + } + + public void setOffsetOfIncludeExport(int fOffsetOfIncludeExport) { + this.fOffsetOfIncludeExport = fOffsetOfIncludeExport; + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java index 5c361fb2597..f3cd240af81 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/scanner/LocationMap.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2013 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 @@ -7,6 +7,7 @@ * * Contributors: * Markus Schorn - Initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.parser.scanner; @@ -32,6 +33,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IFileNomination; import org.eclipse.cdt.core.dom.ast.IMacroBinding; import org.eclipse.cdt.core.parser.ISignificantMacros; +import org.eclipse.cdt.core.parser.IncludeExportPatterns; import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; @@ -126,17 +128,21 @@ public class LocationMap implements ILocationResolver { * @param name name of the include without delimiters ("" or <>) * @param userInclude true when specified with double-quotes. */ - public ILocationCtx pushInclusion(int startOffset, int nameOffset, int nameEndOffset, int endOffset, - AbstractCharArray buffer, String filename, char[] name, boolean userInclude, boolean heuristic, boolean isSource) { + public ILocationCtx pushInclusion(int startOffset, int nameOffset, int nameEndOffset, + int endOffset, AbstractCharArray buffer, String filename, char[] name, + boolean userInclude, boolean heuristic, boolean isSource) { assert fCurrentContext instanceof LocationCtxContainer; int startNumber= getSequenceNumberForOffset(startOffset); int nameNumber= getSequenceNumberForOffset(nameOffset); int nameEndNumber= getSequenceNumberForOffset(nameEndOffset); int endNumber= getSequenceNumberForOffset(endOffset); + boolean exported = isExportedIncludeAt(endOffset); final ASTInclusionStatement inclusionStatement= - new ASTInclusionStatement(fTranslationUnit, startNumber, nameNumber, nameEndNumber, endNumber, name, filename, userInclude, true, heuristic, null); + new ASTInclusionStatement(fTranslationUnit, startNumber, nameNumber, nameEndNumber, + endNumber, name, filename, userInclude, true, heuristic, exported, null); fDirectives.add(inclusionStatement); - fCurrentContext= new LocationCtxFile((LocationCtxContainer) fCurrentContext, filename, buffer, startOffset, endOffset, endNumber, inclusionStatement, isSource); + fCurrentContext= new LocationCtxFile((LocationCtxContainer) fCurrentContext, filename, buffer, + startOffset, endOffset, endNumber, inclusionStatement, isSource); fLastChildInsertionOffset= 0; return fCurrentContext; } @@ -230,21 +236,70 @@ public class LocationMap implements ILocationResolver { * @param userInclude true when specified with double-quotes. * @param active true when include appears in active code. */ - public ASTInclusionStatement encounterPoundInclude(int startOffset, int nameOffset, int nameEndOffset, int endOffset, - char[] name, String filename, boolean userInclude, boolean active, boolean heuristic, - IFileNomination nominationDelegate) { + public ASTInclusionStatement encounterPoundInclude(int startOffset, int nameOffset, int nameEndOffset, + int endOffset, char[] name, String filename, boolean userInclude, boolean active, + boolean heuristic, IFileNomination nominationDelegate) { + boolean exported = isExportedIncludeAt(endOffset); startOffset= getSequenceNumberForOffset(startOffset); nameOffset= getSequenceNumberForOffset(nameOffset); nameEndOffset= getSequenceNumberForOffset(nameEndOffset); endOffset= getSequenceNumberForOffset(endOffset); - final ASTInclusionStatement inc = new ASTInclusionStatement(fTranslationUnit, startOffset, nameOffset, - nameEndOffset, endOffset, name, filename, userInclude, active, heuristic, nominationDelegate); + final ASTInclusionStatement inc = new ASTInclusionStatement(fTranslationUnit, startOffset, + nameOffset, nameEndOffset, endOffset, name, filename, userInclude, active, heuristic, + exported, nominationDelegate); fDirectives.add(inc); return inc; } - public void encounteredComment(int offset, int endOffset, boolean isBlockComment) { - fComments.add(new ASTComment(fTranslationUnit, getCurrentFilePath(), offset, endOffset, isBlockComment)); + private boolean isExportedIncludeAt(int includeEndOffset) { + boolean exported = false; + if (fLexerOptions.fIncludeExportPatterns != null && fCurrentContext instanceof LocationCtxFile) { + LocationCtxFile context = (LocationCtxFile) fCurrentContext; + exported = context.isInsideIncludeExportBlock(); + if (!exported) { + int distance = context.getOffsetOfIncludeExport() - includeEndOffset; + if (distance >= 0 && + CharArrayUtils.indexOf('\n', context.getSource(includeEndOffset, distance)) < 0) { + exported = true; + } + } + } + return exported; + } + + public void encounteredComment(int offset, int endOffset, boolean isBlockComment, AbstractCharArray input) { + ASTComment comment = new ASTComment(fTranslationUnit, getCurrentFilePath(), offset, endOffset, isBlockComment); + if (fLexerOptions.fIncludeExportPatterns != null && fCurrentContext instanceof LocationCtxFile) { + CharSequence text = getTrimmedCommentText(input.subSequence(offset, endOffset), isBlockComment); + IncludeExportPatterns patterns = fLexerOptions.fIncludeExportPatterns; + if (patterns.getIncludeExportPattern() != null + && patterns.getIncludeExportPattern().matcher(text).matches()) { + ((LocationCtxFile) fCurrentContext).setOffsetOfIncludeExport(offset); + } else if (patterns.getIncludeBeginExportsPattern() != null + && patterns.getIncludeBeginExportsPattern().matcher(text).matches()) { + ((LocationCtxFile) fCurrentContext).setInsideIncludeExportBlock(true); + } else if (patterns.getIncludeEndExportsPattern() != null + && patterns.getIncludeEndExportsPattern().matcher(text).matches()) { + ((LocationCtxFile) fCurrentContext).setInsideIncludeExportBlock(false); + } + } + fComments.add(comment); + } + + private CharSequence getTrimmedCommentText(CharSequence comment, boolean isBlockComment) { + int end = comment.length() - (isBlockComment ? 2 : 0); + int begin; + for (begin = 2; begin < end; begin++) { + if (!Character.isWhitespace(comment.charAt(begin))) + break; + } + if (end <= begin) + return ""; //$NON-NLS-1$ + while (--end >= begin) { + if (!Character.isWhitespace(comment.charAt(end))) + break; + } + return comment.subSequence(begin, end + 1); } public void encounterProblem(int id, char[] arg, int offset, int endOffset) { 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 e579274828d..9150a63b971 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2012 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2013 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 @@ -42,10 +42,12 @@ import org.eclipse.cdt.core.index.IndexLocationFactory; import org.eclipse.cdt.core.model.AbstractLanguage; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; import org.eclipse.cdt.core.parser.FileContent; import org.eclipse.cdt.core.parser.IParserLogService; import org.eclipse.cdt.core.parser.IScannerInfo; import org.eclipse.cdt.core.parser.ISignificantMacros; +import org.eclipse.cdt.core.parser.IncludeExportPatterns; import org.eclipse.cdt.core.parser.IncludeFileContentProvider; import org.eclipse.cdt.core.parser.ParserUtil; import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics; @@ -394,6 +396,10 @@ public abstract class AbstractIndexerTask extends PDOMWriter { return null; } + protected IncludeExportPatterns getIncludeExportPatterns() { + return null; + } + /** * @return array of linkage IDs that shall be parsed */ @@ -483,6 +489,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { fASTOptions= ILanguage.OPTION_NO_IMAGE_LOCATIONS | ILanguage.OPTION_SKIP_TRIVIAL_EXPRESSIONS_IN_AGGREGATE_INITIALIZERS; + if (getSkipReferences() == SKIP_ALL_REFERENCES) { fASTOptions |= ILanguage.OPTION_SKIP_FUNCTION_BODIES; } @@ -826,7 +833,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (monitor.isCanceled() || hasUrgentTasks()) return; final Object tu = locTask.fTu; - final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); + final IScannerInfo scannerInfo = getScannerInfo(linkageID, tu); parseFile(tu, getLanguage(tu, linkageID), ifl, scannerInfo, null, monitor); } } @@ -860,7 +867,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (monitor.isCanceled() || hasUrgentTasks()) return; final Object tu = locTask.fTu; - final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, tu); + final IScannerInfo scannerInfo= getScannerInfo(linkageID, tu); parseFile(tu, getLanguage(tu, linkageID), ifl, scannerInfo, null, monitor); if (locTask.isCompleted()) it.remove(); @@ -904,7 +911,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { final int safeguardSize= safeGuard.size(); while (true) { - // Look for a context and parse the file + // Look for a context and parse the file. IIndexFragmentFile ctxFile = findContextFile(linkageID, map, versionTask, safeGuard, monitor); if (ctxFile == null || ctxFile == headerFile) return; @@ -913,7 +920,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { if (contextTu == null) return; - final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, contextTu); + final IScannerInfo scannerInfo = getScannerInfo(linkageID, contextTu); final AbstractLanguage language = getLanguage(contextTu, linkageID); final FileContext ctx= new FileContext(ctxFile, headerFile); Set dependencies= null; @@ -923,7 +930,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter { 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 + // handled before. if (dependencies == null) dependencies= new HashSet(); if (dependencies.add(d.fIndexFile)) { @@ -940,6 +947,14 @@ public abstract class AbstractIndexerTask extends PDOMWriter { } } + private IScannerInfo getScannerInfo(int linkageID, Object contextTu) { + final IScannerInfo scannerInfo= fResolver.getBuildConfiguration(linkageID, contextTu); + if (scannerInfo instanceof ExtendedScannerInfo) { + ((ExtendedScannerInfo) scannerInfo).setIncludeExportPatterns(getIncludeExportPatterns()); + } + return scannerInfo; + } + private void restoreSet(LinkedHashSet set, int restoreSize) { for (Iterator it = set.iterator(); it.hasNext();) { it.next(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMInclude.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMInclude.java index c5c086d5257..a915db28f60 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMInclude.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMInclude.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 QNX Software Systems and others. + * Copyright (c) 2006, 2013 QNX Software Systems 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 @@ -46,6 +46,7 @@ public class PDOMInclude implements IIndexFragmentInclude { private static final int FLAG_INACTIVE_INCLUDE = 0x02; private static final int FLAG_RESOLVED_BY_HEURISTICS= 0x04; private static final int FLAG_DEDUCIBLE_NAME = 0x08; + private static final int FLAG_EXPORTED_FILE = 0x10; private final PDOMLinkage linkage; private final long record; @@ -97,6 +98,9 @@ public class PDOMInclude implements IIndexFragmentInclude { } else if (include.isResolvedByHeuristics()) { flags |= FLAG_RESOLVED_BY_HEURISTICS; } + if (include.isIncludedFileExported()) { + flags |= FLAG_EXPORTED_FILE; + } if (deducible_name) { flags |= FLAG_DEDUCIBLE_NAME; } @@ -254,6 +258,11 @@ public class PDOMInclude implements IIndexFragmentInclude { return (getFlag() & FLAG_RESOLVED_BY_HEURISTICS) != 0; } + @Override + public boolean isIncludedFileExported() throws CoreException { + return (getFlag() & FLAG_EXPORTED_FILE) != 0; + } + @Override public int getNameOffset() throws CoreException { return linkage.getDB().get3ByteUnsignedInt(record + NODE_OFFSET); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/AbstractPDOMIndexer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/AbstractPDOMIndexer.java index 1f7cd826c3f..77a9e7382be 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/AbstractPDOMIndexer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/AbstractPDOMIndexer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2013 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 @@ -54,13 +54,13 @@ public abstract class AbstractPDOMIndexer implements IPDOMIndexer { @Override public boolean needsToRebuildForProperties(Properties props) { - for (Map.Entry entry : fProperties.entrySet()) { + for (Map.Entry entry : fProperties.entrySet()) { String key = (String) entry.getKey(); - String myval = (String) entry.getValue(); + String val = (String) entry.getValue(); - if (myval != null) { // relevant property + if (val != null) { // relevant property String v2= (String) props.get(key); - if (v2 != null && !myval.equals(v2)) { + if (v2 != null && !val.equals(v2)) { return true; } } @@ -74,8 +74,8 @@ public abstract class AbstractPDOMIndexer implements IPDOMIndexer { @Override public void setProperties(Properties props) { - // only set relevant properties as initialized in the constructor - for (Map.Entry entry : props.entrySet()) { + // Only set relevant properties as initialized in the constructor. + for (Map.Entry entry : props.entrySet()) { String key = (String) entry.getKey(); String val = (String) entry.getValue(); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMIndexerTask.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMIndexerTask.java index 3a135b68bda..35a07a53b46 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMIndexerTask.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/PDOMIndexerTask.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2010 Wind River Systems, Inc. and others. + * Copyright (c) 2006, 2013 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 @@ -17,11 +17,13 @@ import java.util.Comparator; import java.util.HashSet; import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.CCorePreferenceConstants; import org.eclipse.cdt.core.dom.IPDOMIndexer; import org.eclipse.cdt.core.dom.IPDOMIndexerTask; import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.parser.IncludeExportPatterns; import org.eclipse.cdt.internal.core.index.IWritableIndex; import org.eclipse.cdt.internal.core.index.IWritableIndexManager; import org.eclipse.cdt.internal.core.model.CProject; @@ -181,6 +183,20 @@ public abstract class PDOMIndexerTask extends AbstractIndexerTask implements IPD return new TodoTaskUpdater(); } + @Override + protected final IncludeExportPatterns getIncludeExportPatterns() { + ICProject project = getCProject(); + String exportPattern = CCorePreferenceConstants.getPreference( + CCorePreferenceConstants.INCLUDE_EXPORT_PATTERN, project, null); + String beginExportsPattern = CCorePreferenceConstants.getPreference( + CCorePreferenceConstants.INCLUDE_BEGIN_EXPORTS_PATTERN, project, null); + String endExportsPattern = CCorePreferenceConstants.getPreference( + CCorePreferenceConstants.INCLUDE_END_EXPORTS_PATTERN, project, null); + if (exportPattern == null && beginExportsPattern == null && endExportsPattern == null) + return null; + return new IncludeExportPatterns(exportPattern, beginExportsPattern, endExportsPattern); + } + protected void traceEnd(long start, IWritableIndex index, boolean wasCancelled) { // log entry if (fWriteInfoToLog && !wasCancelled && index != null) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/ProjectIndexerInputAdapter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/ProjectIndexerInputAdapter.java index e24dce8546a..695044c7902 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/ProjectIndexerInputAdapter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/ProjectIndexerInputAdapter.java @@ -25,9 +25,9 @@ import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ILanguage; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.model.LanguageManager; +import org.eclipse.cdt.core.parser.ExtendedScannerInfo; import org.eclipse.cdt.core.parser.FileContent; import org.eclipse.cdt.core.parser.IScannerInfo; -import org.eclipse.cdt.core.parser.ScannerInfo; import org.eclipse.cdt.internal.core.CCoreInternals; import org.eclipse.cdt.internal.core.parser.InternalParserUtil; import org.eclipse.cdt.internal.core.pdom.AbstractIndexerTask.UnusedHeaderStrategy; @@ -156,7 +156,7 @@ public class ProjectIndexerInputAdapter extends IndexerInputAdapter { public IScannerInfo getBuildConfiguration(int linkageID, Object tu) { IScannerInfo info= ((ITranslationUnit) tu).getScannerInfo(true); if (info == null) { - info= new ScannerInfo(); + info= new ExtendedScannerInfo(); } return info; } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePreferenceConstants.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePreferenceConstants.java index 2f5760fe1f1..88b72cd45e1 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePreferenceConstants.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePreferenceConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 QNX Software Systems and others. + * Copyright (c) 2000, 2013 QNX Software Systems 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 @@ -173,6 +173,50 @@ public class CCorePreferenceConstants { */ public static final String PREF_BUILD_CONFIGS_RESOURCE_CHANGES = "build.proj.ref.configs.enabled"; //$NON-NLS-1$ + /** + * Default value for {@link #INCLUDE_EXPORT_PATTERN}. + * @since 5.5 + */ + public static final String DEFAULT_INCLUDE_EXPORT_PATTERN = "IWYU\\s+(pragma:?\\s+)?export"; //$NON-NLS-1$ + + /** + * Preference key for the regular expression pattern that, when appears in a comment on the same + * line as include statement, indicates the the included header file is exported. + * @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas" + * + * @since 5.5 + */ + public static final String INCLUDE_EXPORT_PATTERN = "includes.exportPattern"; //$NON-NLS-1$ + + /** + * Default value for {@link #INCLUDE_BEGIN_EXPORTS_PATTERN}. + * @since 5.5 + */ + public static final String DEFAULT_INCLUDE_BEGIN_EXPORTS_PATTERN = "IWYU\\s+(pragma:?\\s+)?begin_exports?"; //$NON-NLS-1$ + + /** + * Preference key for the regular expression pattern that, when appears in a comment, marks + * the beginning of a sequence of include statements that export the included header files. + * @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas" + * + * @since 5.5 + */ + public static final String INCLUDE_BEGIN_EXPORTS_PATTERN = "includes.beginExportsPattern"; //$NON-NLS-1$ + + /** + * Default value for {@link #INCLUDE_END_EXPORTS_PATTERN}. + * @since 5.5 + */ + public static final String DEFAULT_INCLUDE_END_EXPORTS_PATTERN = "IWYU\\s+(pragma:?\\s+)?end_exports?"; //$NON-NLS-1$ + + /** + * Preference key for the regular expression pattern that, when appears in a comment, marks + * the end of a sequence of include statements that export the included header files. + * @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas" + * + * @since 5.5 + */ + public static final String INCLUDE_END_EXPORTS_PATTERN = "includes.endExportsPattern"; //$NON-NLS-1$ /** * Returns the node in the preference in the given context. diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePreferenceInitializer.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePreferenceInitializer.java index 3eb7839aa2d..9720c7e9be0 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePreferenceInitializer.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/CCorePreferenceInitializer.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2011 QNX Software Systems and others. + * Copyright (c) 2000, 2013 QNX Software Systems 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 @@ -28,18 +28,14 @@ import org.eclipse.core.runtime.preferences.DefaultScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; public class CCorePreferenceInitializer extends AbstractPreferenceInitializer { - - /* (non-Javadoc) - * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences() - */ @Override public void initializeDefaultPreferences() { HashSet optionNames = CModelManager.OptionNames; - // Formatter settings + // Formatter settings. Map defaultOptionsMap = DefaultCodeFormatterConstants.getDefaultSettings(); // code formatter defaults - // Compiler settings + // Compiler settings. defaultOptionsMap.put(CCorePreferenceConstants.TODO_TASK_TAGS, CCorePreferenceConstants.DEFAULT_TASK_TAGS); defaultOptionsMap.put(CCorePreferenceConstants.TODO_TASK_PRIORITIES, CCorePreferenceConstants.DEFAULT_TASK_PRIORITY); defaultOptionsMap.put(CCorePreferenceConstants.TODO_TASK_CASE_SENSITIVE, CCorePreferenceConstants.DEFAULT_TASK_CASE_SENSITIVE); @@ -49,7 +45,7 @@ public class CCorePreferenceInitializer extends AbstractPreferenceInitializer { defaultOptionsMap.put(CCorePreferenceConstants.WORKSPACE_LANGUAGE_MAPPINGS, CCorePreferenceConstants.DEFAULT_WORKSPACE_LANGUAGE_MAPPINGS); defaultOptionsMap.put(CodeReaderCache.CODE_READER_BUFFER, CodeReaderCache.DEFAULT_CACHE_SIZE_IN_MB_STRING); - // Store default values to default preferences + // Store default values to default preferences. IEclipsePreferences defaultPreferences = DefaultScope.INSTANCE.getNode(CCorePlugin.PLUGIN_ID); for (Map.Entry entry : defaultOptionsMap.entrySet()) { String optionName = entry.getKey(); @@ -62,11 +58,14 @@ public class CCorePreferenceInitializer extends AbstractPreferenceInitializer { defaultPreferences.putBoolean(CCorePreferenceConstants.FILE_PATH_CANONICALIZATION, true); defaultPreferences.putBoolean(CCorePreferenceConstants.SHOW_SOURCE_ROOTS_AT_TOP_LEVEL_OF_PROJECT, true); - // build defaults + // Build defaults. defaultPreferences.putBoolean(CCorePreferenceConstants.PREF_BUILD_ALL_CONFIGS, false); defaultPreferences.putBoolean(CCorePreferenceConstants.PREF_BUILD_CONFIGS_RESOURCE_CHANGES, false); - // indexer defaults + // Indexer defaults. IndexerPreferences.initializeDefaultPreferences(defaultPreferences); + defaultPreferences.put(CCorePreferenceConstants.INCLUDE_EXPORT_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_EXPORT_PATTERN); + defaultPreferences.put(CCorePreferenceConstants.INCLUDE_BEGIN_EXPORTS_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_BEGIN_EXPORTS_PATTERN); + defaultPreferences.put(CCorePreferenceConstants.INCLUDE_END_EXPORTS_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_END_EXPORTS_PATTERN); } } diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/OrganizeIncludesTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludeOrganizerTest.java similarity index 90% rename from core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/OrganizeIncludesTest.java rename to core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludeOrganizerTest.java index 50fa7d63d68..63e27c9ea5e 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/OrganizeIncludesTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludeOrganizerTest.java @@ -26,20 +26,20 @@ import org.eclipse.cdt.internal.ui.refactoring.includes.IHeaderChooser; import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeOrganizer; /** - * Tests for Extract Function refactoring. + * Tests for IncludeOrganizer. */ -public class OrganizeIncludesTest extends IncludesTestBase { +public class IncludeOrganizerTest extends IncludesTestBase { - public OrganizeIncludesTest() { + public IncludeOrganizerTest() { super(); } - public OrganizeIncludesTest(String name) { + public IncludeOrganizerTest(String name) { super(name); } public static Test suite() { - return suite(OrganizeIncludesTest.class); + return suite(IncludeOrganizerTest.class); } @Override @@ -295,4 +295,38 @@ public class OrganizeIncludesTest extends IncludesTestBase { getPreferenceStore().setValue(PreferenceConstants.INCLUDES_ALLOW_REORDERING, false); assertExpectedResults(); } + + //h1.h + //class A {}; + + //h2.h + //class B {}; + + //h3.h + //#include "h2.h" // IWYU pragma: export + //class C {}; + + //h4.h + //#include "h1.h" + ///* IWYU pragma: begin_exports */ + //#include "h3.h" + ///* IWYU pragma: end_exports */ + //class D {}; + + //source.cpp + //A a; + //B b; + //C c; + //D d; + //==================== + //#include "h1.h" + //#include "h4.h" + // + //A a; + //B b; + //C c; + //D d; + public void testHeaderExport() throws Exception { + assertExpectedResults(); + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestSuite.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestSuite.java index cb49b4da418..4a18f4c7a0a 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestSuite.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludesTestSuite.java @@ -18,7 +18,7 @@ public class IncludesTestSuite extends TestSuite { public static Test suite() throws Exception { IncludesTestSuite suite = new IncludesTestSuite(); suite.addTest(BindingClassifierTest.suite()); - suite.addTest(OrganizeIncludesTest.suite()); + suite.addTest(IncludeOrganizerTest.suite()); return suite; } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeMap.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeMap.java index 13e583b228f..8af9db94b88 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeMap.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeMap.java @@ -10,16 +10,28 @@ *******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring.includes; +import java.io.StringReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.ui.IMemento; +import org.eclipse.ui.WorkbenchException; +import org.eclipse.ui.XMLMemento; class IncludeMap { + private static final String TAG_CPP_ONLY = "cpp_only"; //$NON-NLS-1$ + private static final String TAG_FORCED_REPLACEMENT = "forced_replacement"; //$NON-NLS-1$ + private static final String TAG_MAPPING = "mapping"; //$NON-NLS-1$ + private static final String TAG_KEY = "key"; //$NON-NLS-1$ + private static final String TAG_VALUE = "value"; //$NON-NLS-1$ + private final boolean forcedReplacement; - private final Map> map; private final boolean cppOnly; + private final Map> map; public IncludeMap(boolean forcedReplacement, boolean cppOnly) { this.forcedReplacement = forcedReplacement; @@ -113,4 +125,39 @@ class IncludeMap { public boolean isCppOnly() { return cppOnly; } + + // XXX Define a class containing two Includemaps, week and strong + public void saveToMemento(IMemento memento) { + memento.putBoolean(TAG_CPP_ONLY, cppOnly); + memento.putBoolean(TAG_FORCED_REPLACEMENT, forcedReplacement); + for (Entry> entry : map.entrySet()) { + String key = entry.getKey().toString(); + for (IncludeInfo value : entry.getValue()) { + IMemento mapping = memento.createChild(TAG_MAPPING); + mapping.putString(TAG_KEY, key); + mapping.putString(TAG_VALUE, value.toString()); + } + } + } + + public static IncludeMap fromMemento(IMemento memento) { + Boolean cppOnly = memento.getBoolean(TAG_CPP_ONLY); + Boolean forcedReplacement = memento.getBoolean(TAG_FORCED_REPLACEMENT); + IncludeMap includeMap = new IncludeMap(cppOnly, forcedReplacement); + for (IMemento mapping : memento.getChildren(TAG_MAPPING)) { + includeMap.addMapping(mapping.getString(TAG_KEY), mapping.getString(TAG_VALUE)); + } + return includeMap; + } + + public static IncludeMap fromString(String str) { + StringReader reader = new StringReader(str); + XMLMemento memento; + try { + memento = XMLMemento.createReadRoot(reader); + } catch (WorkbenchException e) { + return null; + } + return fromMemento(memento); + } } \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeOrganizer.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeOrganizer.java index 072a9b4a3b4..1a3ae5d5889 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeOrganizer.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeOrganizer.java @@ -875,7 +875,7 @@ public class IncludeOrganizer { } private void processInclusionRequests(List requests, - HeaderSubstitutor headerSubstitutor) { + HeaderSubstitutor headerSubstitutor) throws CoreException { // Add partner header if necessary. HashSet includedByPartner = fContext.getPreferences().allowPartnerIndirectInclusion ? new HashSet() : null; @@ -954,8 +954,6 @@ public class IncludeOrganizer { } // Resolve ambiguous inclusion requests. - - // Maps a set of header files presented to the user to the file selected by the user. for (InclusionRequest request : requests) { if (!request.isResolved()) { List candidatePaths = request.getCandidatePaths(); @@ -976,9 +974,12 @@ public class IncludeOrganizer { } } } + + // Remove headers that are exported by other headers. + fContext.removeExportedHeaders(); } - private IPath getPath(IIndexFileLocation location) { + private static IPath getPath(IIndexFileLocation location) { return IndexLocationFactory.getAbsolutePath(location); } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludePreferences.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludePreferences.java index 3d65250a960..3af76a9557e 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludePreferences.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludePreferences.java @@ -38,7 +38,7 @@ public class IncludePreferences { public final boolean forwardDeclareCompositeTypes; public final boolean forwardDeclareEnums; public final boolean forwardDeclareFunctions; - // TODO(sprigogin): Create a preference. + // TODO(sprigogin): Create a preference for this. public final boolean forwardDeclareExternalVariables = false; public final boolean forwardDeclareTemplates; public final boolean forwardDeclareNamespaceElements; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/InclusionContext.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/InclusionContext.java index 0345cb3b0d7..bdca8db3b9b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/InclusionContext.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/InclusionContext.java @@ -11,16 +11,21 @@ package org.eclipse.cdt.internal.ui.refactoring.includes; import java.io.File; +import java.util.ArrayDeque; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.cdt.core.index.IIndex; +import org.eclipse.cdt.core.index.IIndexFile; +import org.eclipse.cdt.core.index.IIndexInclude; +import org.eclipse.cdt.core.index.IndexLocationFactory; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.parser.IScannerInfo; @@ -149,6 +154,43 @@ public class InclusionContext { return include; } + /** + * Removes headers that are exported by other headers that will be included + */ + public void removeExportedHeaders() throws CoreException { + // Index files keyed by their absolute paths. + Map filesByPath = new HashMap(); + for (IIndexFile file : fIndex.getAllFiles()) { + IPath path = getPath(file); + filesByPath.put(path, file); + } + + Set exportedHeaders = new HashSet(); + for (IPath path : fHeadersToInclude) { + if (!exportedHeaders.contains(path)) { + IIndexFile file = filesByPath.get(path); + ArrayDeque queue = new ArrayDeque(); + queue.add(file); + while ((file = queue.pollFirst()) != null) { + for (IIndexInclude include : file.getIncludes()) { + if (include.isIncludedFileExported()) { + file = fIndex.resolveInclude(include); + if (file != null) { + if (exportedHeaders.add(getPath(file))) + queue.add(file); + } + } + } + } + } + } + fHeadersToInclude.removeAll(exportedHeaders); + } + + private static IPath getPath(IIndexFile file) throws CoreException { + return IndexLocationFactory.getAbsolutePath(file.getLocation()); + } + private static boolean fileExists(String absolutePath) { return new File(absolutePath).exists(); }