From 290c8dfe230a8524ada6a456745eb613a4695678 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Wed, 25 May 2016 17:20:47 -0700 Subject: [PATCH] Improved heuristic header substitution algorithm and unified it between Add Include and Organize Includes commands. Change-Id: I0d4a1110a8b89ca49d55eb82eddb29e7d8bcd548 --- .../includes/HeaderSubstitutor.java | 76 ++++--- .../includes/IncludeCreationContext.java | 13 +- .../refactoring/includes/IncludeCreator.java | 214 +++--------------- .../includes/IncludeOrganizer.java | 34 ++- 4 files changed, 106 insertions(+), 231 deletions(-) diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/HeaderSubstitutor.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/HeaderSubstitutor.java index cb7f0fab22c..18e8541a583 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/HeaderSubstitutor.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/HeaderSubstitutor.java @@ -79,7 +79,7 @@ public class HeaderSubstitutor { IPath path = IndexLocationFactory.getAbsolutePath(file.getLocation()); if (fContext.getCurrentDirectory().isPrefixOf(path)) { // "IWYU pragma: private" does not affect inclusion from files under - // the directory where the header is located. + // the directory where the header is located. continue; } @@ -201,9 +201,12 @@ public class HeaderSubstitutor { String symbolName = request.getBinding().getName(); ArrayDeque front = new ArrayDeque<>(); HashSet processed = new HashSet<>(); + IIndexFile bestCandidate = null; + IIndexFile candidateWithoutExtension = null; + IIndexFile candidateWithMatchingName = null; try { - // Look for headers without an extension and a matching name. + // Look for headers matching by name and headers without an extension. if (fContext.isCXXLanguage()) { front.addAll(indexFiles); processed.addAll(indexFiles); @@ -213,10 +216,18 @@ public class HeaderSubstitutor { String path = IncludeUtil.getPath(file); - if (!hasExtension(path) && getFilename(path).equalsIgnoreCase(symbolName)) { - // A C++ header without an extension and with a name which matches the name - // of the symbol which should be declared is a perfect candidate for inclusion. - return IndexLocationFactory.getAbsolutePath(file.getLocation()); + if (getFilename(path).equalsIgnoreCase(symbolName)) { + if (!hasExtension(path)) { + // A C++ header without an extension and with a name which matches the name + // of the symbol that should be declared is a perfect candidate for inclusion. + bestCandidate = file; + break; + } + if (candidateWithMatchingName == null) + candidateWithMatchingName = file; + } else if (!hasExtension(path)) { + if (candidateWithoutExtension == null) + candidateWithoutExtension = file; } // Process the next level of the include hierarchy. @@ -231,36 +242,41 @@ public class HeaderSubstitutor { } } - // Repeat the process, this time only looking for headers without an extension. - front.clear(); - front.addAll(indexFiles); - processed.clear(); - processed.addAll(indexFiles); + if (bestCandidate == null) { + bestCandidate = candidateWithoutExtension; + } + if (bestCandidate == null) { + bestCandidate = candidateWithMatchingName; + } - while (!front.isEmpty()) { - IIndexFile file = front.remove(); + if (bestCandidate == null) { + // Repeat inclusion tree search, this time looking for any header included by a source file. + front.clear(); + front.addAll(indexFiles); + processed.clear(); + processed.addAll(indexFiles); - String path = IncludeUtil.getPath(file); + while (!front.isEmpty()) { + IIndexFile file = front.remove(); - if (fContext.isCXXLanguage() && !hasExtension(path)) { - // A C++ header without an extension is still a very good candidate for inclusion. - return IndexLocationFactory.getAbsolutePath(file.getLocation()); - } - - // Process the next level of the include hierarchy. - IIndexInclude[] includes = fContext.getIndex().findIncludedBy(file, 0); - for (IIndexInclude include : includes) { - IIndexFile includer = include.getIncludedBy(); - if (!processed.contains(includer)) { - URI uri = includer.getLocation().getURI(); - if (IncludeUtil.isSource(includer, fContext.getProject()) || isWorkspaceFile(uri)) { - return IndexLocationFactory.getAbsolutePath(file.getLocation()); + // Process the next level of the include hierarchy. + IIndexInclude[] includes = fContext.getIndex().findIncludedBy(file, 0); + for (IIndexInclude include : includes) { + IIndexFile includer = include.getIncludedBy(); + if (!processed.contains(includer)) { + URI uri = includer.getLocation().getURI(); + if (IncludeUtil.isSource(includer, fContext.getProject()) || isWorkspaceFile(uri)) { + bestCandidate = file; + break; + } + front.add(includer); + processed.add(includer); } - front.add(includer); - processed.add(includer); } } } + if (bestCandidate != null) + return IndexLocationFactory.getAbsolutePath(bestCandidate.getLocation()); } catch (CoreException e) { CUIPlugin.log(e); } @@ -269,7 +285,7 @@ public class HeaderSubstitutor { } /** - * Returns the set of headers exporting the given symbol. + * Returns the set of headers exporting the given symbol. */ public Set getExportingHeaders(String symbol) { Set headers = fSymbolExportMap.getMapping(symbol); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeCreationContext.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeCreationContext.java index e3eef3b1948..91c9f20b524 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeCreationContext.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeCreationContext.java @@ -33,7 +33,7 @@ import org.eclipse.cdt.internal.corext.codemanipulation.InclusionContext; /** * Context for managing include statements. */ -public class IncludeCreationContext extends InclusionContext { +public final class IncludeCreationContext extends InclusionContext { private final IIndex fIndex; private final Set fHeadersToInclude; private final Set fHeadersAlreadyIncluded; @@ -108,7 +108,7 @@ public class IncludeCreationContext extends InclusionContext { private static IPath getPath(IIndexFile file) throws CoreException { return IndexLocationFactory.getAbsolutePath(file.getLocation()); } - + public Set getHeadersToInclude() { return fHeadersToInclude; } @@ -164,4 +164,13 @@ public class IncludeCreationContext extends InclusionContext { } return null; } + + /** + * Checks if the given file is suitable for inclusion. A file is suitable for inclusion if it is a header + * file, or if it is already included by some other file. + */ + public final boolean canBeIncluded(IIndexFile indexFile) throws CoreException { + return !IncludeUtil.isSource(indexFile, getProject()) || + fIndex.findIncludedBy(indexFile, 0).length != 0; + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeCreator.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeCreator.java index ba1af526339..560d5cb499c 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeCreator.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/IncludeCreator.java @@ -15,23 +15,18 @@ package org.eclipse.cdt.internal.ui.refactoring.includes; import static org.eclipse.cdt.core.index.IndexLocationFactory.getAbsolutePath; -import java.net.URI; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.content.IContentType; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.text.edits.InsertEdit; @@ -39,7 +34,6 @@ import org.eclipse.text.edits.MultiTextEdit; import com.ibm.icu.text.Collator; -import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IName; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; @@ -72,7 +66,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFile; -import org.eclipse.cdt.core.index.IIndexInclude; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.index.IndexFilter; @@ -90,7 +83,6 @@ import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.ASTCommenter; import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap; import org.eclipse.cdt.internal.core.dom.rewrite.util.ASTNodes; import org.eclipse.cdt.internal.core.model.ASTStringUtil; -import org.eclipse.cdt.internal.core.resources.ResourceLookup; import org.eclipse.cdt.internal.core.util.TextUtil; import org.eclipse.cdt.internal.corext.codemanipulation.IncludeInfo; import org.eclipse.cdt.internal.corext.codemanipulation.StyledInclude; @@ -139,7 +131,7 @@ public class IncludeCreator { final Map candidatesMap= new HashMap<>(); final IndexFilter filter = IndexFilter.getDeclaredBindingFilter(ast.getLinkage().getLinkageID(), false); - + final List requiredIncludes = new ArrayList<>(); final List usingDeclarations = new ArrayList<>(); @@ -158,7 +150,7 @@ public class IncludeCreator { } } } - + HeaderSubstitutor headerSubstitutor = new HeaderSubstitutor(fContext); for (IIndexBinding indexBinding : bindings) { @@ -168,26 +160,27 @@ public class IncludeCreator { } IIndexName[] definitions= null; // class, struct, union, enum-type, enum-item - if (indexBinding instanceof ICompositeType || indexBinding instanceof IEnumeration || indexBinding instanceof IEnumerator) { + if (indexBinding instanceof ICompositeType || indexBinding instanceof IEnumeration + || indexBinding instanceof IEnumerator) { definitions= index.findDefinitions(indexBinding); - } else if (indexBinding instanceof ITypedef || (indexBinding instanceof IFunction)) { + } else if (indexBinding instanceof ITypedef || indexBinding instanceof IFunction) { definitions = index.findDeclarations(indexBinding); } if (definitions != null) { for (IIndexName definition : definitions) { - considerForInclusion(definition, indexBinding, index, headerSubstitutor, + considerForInclusion(ast, definition, indexBinding, index, headerSubstitutor, candidatesMap); } - if (definitions.length > 0 && adaptedBinding != null) + if (definitions.length > 0 && adaptedBinding != null) break; } } IIndexMacro[] macros = index.findMacros(nameChars, filter, new NullProgressMonitor()); for (IIndexMacro macro : macros) { IIndexName definition = macro.getDefinition(); - considerForInclusion(definition, macro, index, headerSubstitutor, candidatesMap); + considerForInclusion(ast, definition, macro, index, headerSubstitutor, candidatesMap); } - + final ArrayList candidates = new ArrayList<>(candidatesMap.values()); if (candidates.size() > 1) { // First, try to resolve the ambiguity by comparing the namespaces of the @@ -202,12 +195,12 @@ public class IncludeCreator { candidates.clear(); candidates.add(candidate); } - + if (candidates.size() == 1) { IncludeCandidate candidate = candidates.get(0); requiredIncludes.add(candidate.include); IIndexBinding indexBinding = candidate.binding; - + if (indexBinding instanceof ICPPBinding && !(indexBinding instanceof IIndexMacro)) { // Decide what 'using' declaration, if any, should be added along with the include. UsingDeclaration usingDeclaration = deduceUsingDeclaration(binding, indexBinding, ast); @@ -254,7 +247,7 @@ public class IncludeCreator { } return null; } - + private ICPPNamespace getContainingNamespace(IASTName name) { ICPPNamespaceScope scope = getContainingNamespaceScope(name); // TODO(nathanridge): Move this ICPPNamespaceScope -> ICPPNamespace @@ -273,7 +266,7 @@ public class IncludeCreator { } return null; } - + private ICPPNamespace getContainingNamespace(IBinding binding) { while (binding != null) { if (binding instanceof ICPPNamespace) { @@ -283,7 +276,7 @@ public class IncludeCreator { } return null; } - + private IncludeCandidate selectCandidateByNamespace(IASTName sourceName, ArrayList candidates) { // If one of the candidates is in the same namespace as the source name, // and the others aren't, prefer that candidate. @@ -310,7 +303,7 @@ public class IncludeCreator { String contents = fContext.getSourceContents(); IRegion includeRegion = IncludeUtil.getSafeIncludeReplacementRegion(contents, ast, commentedNodeMap); - + IncludePreferences preferences = fContext.getPreferences(); MultiTextEdit rootEdit = new MultiTextEdit(); @@ -336,7 +329,7 @@ public class IncludeCreator { if (preferences.allowReordering) { // Since the order of existing include statements may not match the include order // preferences, we find positions for the new include statements by pushing them up - // from the bottom of the include insertion region. + // from the bottom of the include insertion region. for (StyledInclude include : styledIncludes) { int i = mergedIncludes.size(); while (--i >= 0 && preferences.compare(include, mergedIncludes.get(i)) < 0) {} @@ -425,7 +418,7 @@ public class IncludeCreator { // Since the order of existing using declarations may not be alphabetical, we find positions // for the new using declarations by pushing them from them up from the bottom of - // the using declaration list. + // the using declaration list. for (UsingDeclaration using : usingDeclarations) { int i = mergedUsingDeclarations.size(); while (--i >= 0 && using.compareTo(mergedUsingDeclarations.get(i)) < 0) {} @@ -475,27 +468,30 @@ public class IncludeCreator { } /** - * Adds an include candidate to the candidates map if the file containing - * the definition is suitable for inclusion. + * Adds an include candidate to the {@code candidates} map if the file containing the definition + * is suitable for inclusion. */ - private void considerForInclusion(IIndexName definition, IIndexBinding binding, IIndex index, - HeaderSubstitutor headerSubstitutor, Map candidates) throws CoreException { + private void considerForInclusion(IASTTranslationUnit ast, IIndexName definition, IIndexBinding binding, + IIndex index, HeaderSubstitutor headerSubstitutor, Map candidates) + throws CoreException { if (definition == null) { return; } IIndexFile file = definition.getFile(); // Consider the file for inclusion only if it is not a source file, - // or a source file that was already included by some other file. - if (!isSource(getPath(file)) || index.findIncludedBy(file, 0).length > 0) { + // or a source file that was already included by some other file. + if (fContext.canBeIncluded(file)) { IncludeInfo include; + IPath header = getAbsolutePath(file.getLocation()); + header = headerSubstitutor.getPreferredRepresentativeHeader(header); if (fContext.getPreferences().heuristicHeaderSubstitution) { - include = getIncludeByHeuristic(file, index); - } else { - IPath header = getAbsolutePath(file.getLocation()); - header = headerSubstitutor.getPreferredRepresentativeHeader(header); - IncludeGroupStyle style = fContext.getIncludeStyle(header); - include = fContext.createIncludeInfo(header, style); + boolean reachable = ast.getIndexFileSet().contains(file); + InclusionRequest request = + new InclusionRequest(binding, Collections.singletonMap(file, header), reachable); + header = headerSubstitutor.getPreferredRepresentativeHeaderByHeuristic(request); } + IncludeGroupStyle style = fContext.getIncludeStyle(header); + include = fContext.createIncludeInfo(header, style); if (include != null) { IncludeCandidate candidate = new IncludeCandidate(binding, include); @@ -611,7 +607,6 @@ public class IncludeCreator { } else { break; } - } catch (DOMException e) { break; } @@ -619,7 +614,7 @@ public class IncludeCreator { } return chain; } - + /** * Returns components of the qualified name in reverse order. * For ns1::ns2::Name, e.g., it returns [Name, ns2, ns1]. @@ -646,60 +641,6 @@ public class IncludeCreator { return chain; } - /** - * Given a header file, decides if this header file should be included directly or - * through another header file. For example, bits/stl_map.h is not supposed - * to be included directly, but should be represented by map. - * @return the header file to include. - */ - private IIndexFile getRepresentativeFile(IIndexFile headerFile, IIndex index) { - try { - if (isWorkspaceFile(headerFile.getLocation().getURI())) { - return headerFile; - } - ArrayDeque front = new ArrayDeque<>(); - front.add(headerFile); - HashSet processed = new HashSet<>(); - processed.add(headerFile); - while (!front.isEmpty()) { - IIndexFile file = front.remove(); - // A header without an extension is a good candidate for inclusion into a C++ source - // file. - if (fContext.isCXXLanguage() && !hasExtension(getPath(file))) { - return file; - } - IIndexInclude[] includes = index.findIncludedBy(file, 0); - for (IIndexInclude include : includes) { - IIndexFile includer = include.getIncludedBy(); - if (!processed.contains(includer)) { - URI uri = includer.getLocation().getURI(); - if (isSource(uri.getPath()) || isWorkspaceFile(uri)) { - return file; - } - front.add(includer); - processed.add(includer); - } - } - } - } catch (CoreException e) { - CUIPlugin.log(e); - } - return headerFile; - } - - private boolean isWorkspaceFile(URI uri) { - for (IFile file : ResourceLookup.findFilesForLocationURI(uri)) { - if (file.exists()) { - return true; - } - } - return false; - } - - private boolean hasExtension(String path) { - return path.indexOf('.', path.lastIndexOf('/') + 1) >= 0; - } - private IFunctionSummary findContribution(final String name) throws CoreException { ICHelpInvocationContext context = new ICHelpInvocationContext() { @Override @@ -716,91 +657,6 @@ public class IncludeCreator { return CHelpProviderManager.getDefault().getFunctionInfo(context, name); } - /** - * Checks if a file is a source file (.c, .cpp, .cc, etc). Header files are not considered - * source files. - * - * @return Returns {@code true} if the the file is a source file. - */ - private boolean isSource(String filename) { - IContentType ct= CCorePlugin.getContentType(fContext.getProject(), filename); - if (ct != null) { - String id = ct.getId(); - if (CCorePlugin.CONTENT_TYPE_CSOURCE.equals(id) || CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(id)) { - return true; - } - } - return false; - } - - private static String getPath(IIndexFile file) throws CoreException { - return file.getLocation().getURI().getPath(); - } - - /** - * Returns the {@link IncludeInfo} object to be added to the include list - * - * @param path - the full path of the file to include - * @return the {@link IncludeInfo} object - * @throws CoreException - */ - private IncludeInfo getIncludeByHeuristic(IIndexFile file, IIndex index) throws CoreException { - file = getRepresentativeFile(file, index); - IIndexInclude[] includes = index.findIncludedBy(file); - if (includes.length > 0) { - // Let the existing includes vote. To be eligible to vote, an include - // has to be resolvable in the context of the current translation unit. - int systemIncludeVotes = 0; - String[] ballotBox = new String[includes.length]; - int k = 0; - for (IIndexInclude include : includes) { - if (isResolvableInCurrentContext(include)) { - ballotBox[k++] = include.getFullName(); - if (include.isSystemInclude()) { - systemIncludeVotes++; - } - } - } - if (k != 0) { - Arrays.sort(ballotBox, 0, k); - String contender = ballotBox[0]; - int votes = 1; - String winner = contender; - int winnerVotes = votes; - for (int i = 1; i < k; i++) { - if (!ballotBox[i].equals(contender)) { - contender = ballotBox[i]; - votes = 1; - } - votes++; - if (votes > winnerVotes) { - winner = contender; - winnerVotes = votes; - } - } - return new IncludeInfo(winner, systemIncludeVotes * 2 >= k); - } - } - - // The file has never been included before. - IPath targetLocation = getAbsolutePath(file.getLocation()); - return fContext.getIncludeForHeaderFile(targetLocation); - } - - /** - * Returns {@code true} if the given include can be resolved in the context of - * the current translation unit. - */ - private boolean isResolvableInCurrentContext(IIndexInclude include) { - try { - IncludeInfo includeInfo = new IncludeInfo(include.getFullName(), include.isSystemInclude()); - return fContext.resolveInclude(includeInfo) != null; - } catch (CoreException e) { - CUIPlugin.log(e); - return false; - } - } - /** * Returns the fully qualified name for a given index binding. * @@ -815,7 +671,7 @@ public class IncludeCreator { for (String element : qname) { if (needSep) result.append(Keywords.cpCOLONCOLON); - result.append(element); + result.append(element); needSep= true; } return result.toString(); @@ -823,7 +679,7 @@ public class IncludeCreator { /** * To be used by ElementListSelectionDialog for user to choose which declarations/ - * definitions for "add include" when there are more than one to choose from. + * definitions for "add include" when there are more than one to choose from. */ private static class IncludeCandidate { final IIndexBinding binding; 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 c26426b9e46..92cba70ee2c 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 @@ -175,8 +175,8 @@ public class IncludeOrganizer { /** * Organizes the includes for a given translation unit. + * * @param ast The AST translation unit to process. - * @throws CoreException */ public MultiTextEdit organizeIncludes(IASTTranslationUnit ast) throws CoreException { // Process the given translation unit with the inclusion resolver. @@ -333,7 +333,6 @@ public class IncludeOrganizer { /** * Creates forward declarations by examining the list of bindings which have to be declared. - * @param pendingBlankLine */ private void createForwardDeclarations(IASTTranslationUnit ast, BindingClassifier classifier, int offset, boolean pendingBlankLine, MultiTextEdit rootEdit) throws CoreException { @@ -831,17 +830,17 @@ public class IncludeOrganizer { IIndexName[] indexNames; if (binding instanceof IMacroBinding) { indexNames = IIndexName.EMPTY_ARRAY; - ILocationResolver resolver = ast.getAdapter(ILocationResolver.class); - IASTName[] declarations = resolver.getDeclarations((IMacroBinding) binding); - for (IASTName name : declarations) { - if (name instanceof IAdaptable) { - IIndexName indexName = ((IAdaptable) name).getAdapter(IIndexName.class); - if (indexName != null) { - indexNames = Arrays.copyOf(indexNames, indexNames.length + 1); - indexNames[indexNames.length - 1] = indexName; - } - } - } + ILocationResolver resolver = ast.getAdapter(ILocationResolver.class); + IASTName[] declarations = resolver.getDeclarations((IMacroBinding) binding); + for (IASTName name : declarations) { + if (name instanceof IAdaptable) { + IIndexName indexName = ((IAdaptable) name).getAdapter(IIndexName.class); + if (indexName != null) { + indexNames = Arrays.copyOf(indexNames, indexNames.length + 1); + indexNames[indexNames.length - 1] = indexName; + } + } + } } else if (allowDeclarations || binding instanceof IVariable) { // For a variable we need to include a declaration. indexNames = index.findDeclarations(binding); @@ -888,7 +887,7 @@ public class IncludeOrganizer { Map reachableDeclaringHeaders = new HashMap<>(); for (IIndexName indexName : indexNames) { IIndexFile indexFile = indexName.getFile(); - if (!canBeIncluded(indexFile)) { + if (!fContext.canBeIncluded(indexFile)) { // The target is a source file which isn't included by any other files. // Don't include it. continue; @@ -918,17 +917,12 @@ public class IncludeOrganizer { int pos = 0; for (IIndexName name : names) { IIndexFile file = name.getFile(); - if (file != null && !blacklist.contains(file) && canBeIncluded(file)) + if (file != null && !blacklist.contains(file) && fContext.canBeIncluded(file)) includable = ArrayUtil.appendAt(includable, pos++, name); } return ArrayUtil.trim(includable, pos); } - private boolean canBeIncluded(IIndexFile indexFile) throws CoreException { - return !IncludeUtil.isSource(indexFile, fContext.getProject()) || - fContext.getIndex().findIncludedBy(indexFile, 0).length != 0; - } - private String createIncludeDirective(IncludePrototype include, String lineComment) { StringBuilder buf = new StringBuilder(); // Unresolved includes are preserved out of caution. Partner include is always preserved.