From 85d8e44eb169c83a56248bc3a8fce27c44f78472 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Thu, 13 Oct 2016 17:49:40 -0700 Subject: [PATCH] Bug 485422 - Organize includes: header substitution maps not always used With this change the heuristic header substitution tries to find a header that is better than the one computed using regular substitution rules, but defaults to that header if it can't find a better one. Change-Id: I811857b2ccf66e2db4161801f34db8464834ce12 --- .../includes/HeaderSubstitutor.java | 84 ++++++++++--------- .../refactoring/includes/IncludeCreator.java | 2 +- .../includes/IncludeOrganizer.java | 2 +- 3 files changed, 46 insertions(+), 42 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 8285ff2455d..105f2be7c23 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 @@ -33,6 +33,10 @@ import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.cdt.internal.corext.codemanipulation.IncludeInfo; public class HeaderSubstitutor { + private static int HEURISTIC_SCORE_NAME_MATCH = 1; + private static int HEURISTIC_SCORE_NO_EXTENSION = 2; + private static int HEURISTIC_SCORE_MAX = HEURISTIC_SCORE_NAME_MATCH + HEURISTIC_SCORE_NO_EXTENSION; + private final IncludeCreationContext fContext; private IncludeMap[] fIncludeMaps; private SymbolExportMap fSymbolExportMap; @@ -192,65 +196,65 @@ public class HeaderSubstitutor { /** * Performs heuristic header substitution. + * + * @param request the inclusion request + * @param preferredHeader the header selected using regular header substitution rules */ - public IPath getPreferredRepresentativeHeaderByHeuristic(InclusionRequest request) { - Set indexFiles = request.getDeclaringFiles().keySet(); + public IPath getPreferredRepresentativeHeaderByHeuristic(InclusionRequest request, IPath preferredHeader) { + if (!fContext.isCXXLanguage()) + return preferredHeader; + String symbolName = request.getBinding().getName(); + int bestScore = getScore(preferredHeader.toString(), symbolName); + if (bestScore == HEURISTIC_SCORE_MAX) + return preferredHeader; // Nothing can be better than preferredHeader. + + IIndexFile bestCandidate = null; + Set indexFiles = request.getDeclaringFiles().keySet(); ArrayDeque front = new ArrayDeque<>(); HashSet processed = new HashSet<>(); - IIndexFile bestCandidate = null; - IIndexFile candidateWithoutExtension = null; - IIndexFile candidateWithMatchingName = null; + front.addAll(indexFiles); + processed.addAll(indexFiles); try { // Look for headers matching by name and headers without an extension. - if (fContext.isCXXLanguage()) { - front.addAll(indexFiles); - processed.addAll(indexFiles); + while (!front.isEmpty()) { + IIndexFile file = front.remove(); + String path = IncludeUtil.getPath(file); - while (!front.isEmpty()) { - IIndexFile file = front.remove(); - String path = IncludeUtil.getPath(file); + int score = getScore(path, symbolName); + if (score > bestScore) { + bestScore = score; + bestCandidate = file; + } - 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. - IIndexInclude[] includes = fContext.getIndex().findIncludedBy(file, 0); - for (IIndexInclude include : includes) { - IIndexFile includer = include.getIncludedBy(); - if (!processed.contains(includer)) { - front.add(includer); - processed.add(includer); - } + // 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)) { + front.add(includer); + processed.add(includer); } } } - if (bestCandidate == null) - bestCandidate = candidateWithoutExtension; - - if (bestCandidate == null) - bestCandidate = candidateWithMatchingName; - if (bestCandidate != null) return IndexLocationFactory.getAbsolutePath(bestCandidate.getLocation()); } catch (CoreException e) { CUIPlugin.log(e); } - return request.getCandidatePaths().iterator().next(); + return preferredHeader; + } + + private static int getScore(String path, String symbolName) { + int score = 0; + if (getFilename(path).equalsIgnoreCase(symbolName)) + score += HEURISTIC_SCORE_NAME_MATCH; + if (!hasExtension(path)) + score += HEURISTIC_SCORE_NO_EXTENSION; + return score; } /** 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 560d5cb499c..0c405abe6c2 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 @@ -488,7 +488,7 @@ public class IncludeCreator { boolean reachable = ast.getIndexFileSet().contains(file); InclusionRequest request = new InclusionRequest(binding, Collections.singletonMap(file, header), reachable); - header = headerSubstitutor.getPreferredRepresentativeHeaderByHeuristic(request); + header = headerSubstitutor.getPreferredRepresentativeHeaderByHeuristic(request, header); } IncludeGroupStyle style = fContext.getIncludeStyle(header); include = fContext.createIncludeInfo(header, style); 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 92cba70ee2c..86a9b417275 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 @@ -696,7 +696,7 @@ public class IncludeOrganizer { } else { IPath header = headerSubstitutor.getPreferredRepresentativeHeader(path); if (header.equals(path) && fContext.getPreferences().heuristicHeaderSubstitution) { - header = headerSubstitutor.getPreferredRepresentativeHeaderByHeuristic(request); + header = headerSubstitutor.getPreferredRepresentativeHeaderByHeuristic(request, header); } request.resolve(header); if (DEBUG_HEADER_SUBSTITUTION) {