blob: f4a857eff3525f2644d28783e3f3a8a3dfeca9b7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2015 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:
* John Glassmyer <jogl@google.com> - import group sorting is broken - https://bugs.eclipse.org/430303
* Lars Vogel <Lars.Vogel@vogella.com> - Contributions for
* Bug 473178
*******************************************************************************/
package org.eclipse.jdt.internal.core.dom.rewrite.imports;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.JavaModelException;
public class ConflictIdentifier {
/**
* Encapsulates those simple names (of type imports and of static imports) which would be
* imported from multiple on-demand or implicit import containers.
*/
static final class Conflicts {
final Set<String> typeConflicts;
final Set<String> staticConflicts;
Conflicts(Set<String> typeConflicts, Set<String> staticConflicts) {
this.typeConflicts = Collections.unmodifiableSet(new HashSet<>(typeConflicts));
this.staticConflicts = Collections.unmodifiableSet(new HashSet<>(staticConflicts));
}
@Override
public String toString() {
return String.format(
"Conflicts(type: %s; static: %s)", this.typeConflicts, this.staticConflicts); //$NON-NLS-1$
}
}
private final OnDemandComputer onDemandComputer;
private final TypeConflictingSimpleNameFinder typeConflictFinder;
private final StaticConflictingSimpleNameFinder staticConflictFinder;
private final Set<String> implicitImportContainers;
ConflictIdentifier(
OnDemandComputer onDemandComputer,
TypeConflictingSimpleNameFinder typeConflictFinder,
StaticConflictingSimpleNameFinder staticConflictFinder,
Set<String> implicitImportContainers) {
this.onDemandComputer = onDemandComputer;
this.typeConflictFinder = typeConflictFinder;
this.staticConflictFinder = staticConflictFinder;
this.implicitImportContainers = implicitImportContainers;
}
/**
* Identifies the simple names (of the elements of {@code imports}) which would be imported from
* multiple on-demand or implicit import containers.
*
* @param imports
* imports whose simple names are to be considered for conflicts
* @param addedImports
* imports which have been added as part of the rewrite (and could therefore trigger
* on-demand reductions; a subset of {@code imports}
* @param typeExplicitSimpleNames
* simple names of types which are already known to require explicit imports
* @param staticExplicitSimpleNames
* simple names of statics which are already known to require explicit imports
* @param progressMonitor
* a progress monitor used to track time spent searching for conflicts
* @return a {@link Conflicts} object encapsulating the found conflicting type and static names
* @throws JavaModelException if an error occurs while searching for declarations
*/
Conflicts identifyConflicts(
Set<ImportName> imports,
Set<ImportName> addedImports,
Set<String> typeExplicitSimpleNames,
Set<String> staticExplicitSimpleNames,
IProgressMonitor progressMonitor) throws JavaModelException {
Collection<OnDemandReduction> onDemandCandidates = this.onDemandComputer.identifyPossibleReductions(
imports, addedImports, typeExplicitSimpleNames, staticExplicitSimpleNames);
Set<String> typeOnDemandContainers = new HashSet<>(extractContainerNames(onDemandCandidates, false));
Set<String> staticOnDemandContainers = new HashSet<>(extractContainerNames(onDemandCandidates, true));
if (!typeOnDemandContainers.isEmpty()) {
// Existing on-demands might conflict with new or existing on-demands.
typeOnDemandContainers.addAll(extractOnDemandContainerNames(imports, false));
// Implicitly imported types might conflict with type on-demands.
typeOnDemandContainers.addAll(this.implicitImportContainers);
// Member types imported by static on-demands might conflict with type on-demands.
typeOnDemandContainers.addAll(staticOnDemandContainers);
}
if (!staticOnDemandContainers.isEmpty()) {
// Existing on-demands might conflict with new or existing on-demands.
staticOnDemandContainers.addAll(extractOnDemandContainerNames(imports, true));
}
Set<String> typeConflicts = findConflictingSimpleNames(
this.typeConflictFinder, imports, false, typeOnDemandContainers, progressMonitor);
Set<String> staticConflicts = findConflictingSimpleNames(
this.staticConflictFinder, imports, true, staticOnDemandContainers, progressMonitor);
return new Conflicts(typeConflicts, staticConflicts);
}
private Collection<String> extractContainerNames(
Collection<OnDemandReduction> onDemandCandidates, boolean isStatic) {
Collection<String> containerNames = new ArrayList<>(onDemandCandidates.size());
for (OnDemandReduction onDemandCandidate : onDemandCandidates) {
ImportName containerOnDemand = onDemandCandidate.containerOnDemand;
if (containerOnDemand.isStatic == isStatic) {
containerNames.add(containerOnDemand.containerName);
}
}
return containerNames;
}
private Collection<String> extractOnDemandContainerNames(
Collection<ImportName> imports, boolean isStatic) {
Collection<String> onDemandContainerNames = new ArrayList<>(imports.size());
for (ImportName importName : imports) {
if (importName.isOnDemand() && importName.isStatic == isStatic) {
onDemandContainerNames.add(importName.containerName);
}
}
return onDemandContainerNames;
}
private Set<String> findConflictingSimpleNames(
ConflictingSimpleNameFinder conflictFinder,
Set<ImportName> imports,
boolean isStatic,
Set<String> onDemandImportedContainers,
IProgressMonitor monitor) throws JavaModelException {
if (onDemandImportedContainers.isEmpty() || imports.isEmpty()) {
return Collections.emptySet();
}
Set<String> simpleNames = new HashSet<>();
for (ImportName currentImport : imports) {
if (currentImport.isStatic == isStatic) {
simpleNames.add(currentImport.simpleName);
}
}
return conflictFinder.findConflictingSimpleNames(simpleNames, onDemandImportedContainers, monitor);
}
}