blob: cf881ea0a65b725df9d420b53f14f1b008a6b895 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.royale.compiler.internal.projects;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.royale.compiler.problems.DuplicateSourceFileProblem;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.UnsupportedSourceFileProblem;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.utils.FilenameNormalization;
/**
* Manages the include sources list of a {@link ASProject}.
*
* TODO Revisit this class, it is trying to be too atomic.
*/
final class SourceListManager
{
SourceListManager(ASProject project, SourcePathManager sourcePathManager)
{
this.project = project;
this.sourcePathManager = sourcePathManager;
sources = new LinkedHashSet<File>();
problems = Collections.emptyList();
}
private final ASProject project;
private final SourcePathManager sourcePathManager;
private Set<File> sources;
private Collection<ICompilerProblem> problems;
void setSourceList(File[] newSources) throws InterruptedException
{
setSourceList(newSources, false);
}
/**
* Sets the source list. This method will remove the existing source list
* {@link ICompilationUnit}'s from the project and add new
* {@link ICompilationUnit}'s to the project.
*
* @param newSources New source list.
* @param overrideSourcePath Set to true to add the file to the source list
* @throws InterruptedException
*/
void setSourceList(File[] newSources, boolean overrideSourcePath) throws InterruptedException
{
newSources = FilenameNormalization.normalize(newSources);
if (newSources.equals(sources))
return;
Collection<ICompilerProblem> problems = new ArrayList<ICompilerProblem>();
Set<File> newSourcesSet = new LinkedHashSet<File>();
List<File> newSourcesToCreate = new ArrayList<File>();
for (File file : newSources)
{
assert !file.isDirectory();
if (project.getSourceCompilationUnitFactory().canCreateCompilationUnit(file))
{
if (!overrideSourcePath && sourcePathManager.isFileOnSourcePath(file))
continue;
if (newSourcesSet.contains(file))
{
problems.add(new DuplicateSourceFileProblem(file));
}
else
{
newSourcesSet.add(file);
// if a file doesn't exist in the sources, then it needs
// creating, otherwise don't re-create same source
if (!sources.contains(file))
{
newSourcesToCreate.add(file);
}
}
}
else
{
problems.add(new UnsupportedSourceFileProblem(file));
}
}
// if an existing source is not in the newSources, it needs to be removed.
Set<ICompilationUnit> unitsToRemove = new HashSet<ICompilationUnit>();
for (File existingSource : sources)
{
if (!newSourcesSet.contains(existingSource))
{
unitsToRemove.addAll(project.getCompilationUnits(existingSource.getAbsolutePath()));
}
}
// set the new sources
sources = newSourcesSet;
List<ICompilationUnit> unitsToAdd = Collections.emptyList();
if (!newSourcesToCreate.isEmpty())
{
unitsToAdd = new ArrayList<ICompilationUnit>(newSourcesToCreate.size());
for (File file : newSourcesToCreate)
{
File sourcePath = sourcePathManager.getSourcePath(file);
String qname = null;
if (sourcePath != null)
qname = SourcePathManager.computeQName(sourcePath, file);
ICompilationUnit unit = project.getSourceCompilationUnitFactory().createCompilationUnit(
file, DefinitionPriority.BasePriority.SOURCE_LIST, 0, qname, null);
//It can be null in some cases, see #ResourceBundleSourceFileHandler
if(unit != null)
unitsToAdd.add(unit);
}
}
List<ICompilerProblem> emptyList = Collections.emptyList();
this.problems = problems.size() == 0 ? emptyList : problems;
project.sourceListChange(unitsToRemove, unitsToAdd);
}
/**
* Returns true if the source is already contained within the SourceListManager
*
* @param source A source file.
*/
public boolean containsSource(File source)
{
assert source.equals(FilenameNormalization.normalize(source));
return sources.contains(source);
}
/**
* Adds a file to the source list unless it is on the source path.
* <p>
* Adding the same file multiple times or adding files that don't exist will
* generate ICompilerProblems that can be retrieved via
* {@code collectProblems(Collection)}.
* <p>
* If the same file is added multiple times, the file may be removed multiple times
* with {@code removeSource(File)}.
*
* @param newSource File to add to the source list.
*/
public void addSource(File newSource) throws InterruptedException
{
addSource(newSource, false);
}
/**
* Adds a file to the source list unless it is on the source path.
* <p>
* Adding the same file multiple times or adding files that don't exist will
* generate ICompilerProblems that can be retrieved via
* {@code collectProblems(Collection)}.
* <p>
* If the same file is added multiple times, the file may be removed
* multiple times with {@code removeSource(File)}.
*
* @param newSource File to add to the source list.
* @param overrideSourcePath Set to true to add the file to the source list
* even if it exists on the source path.
*/
public void addSource(File newSource, boolean overrideSourcePath) throws InterruptedException
{
File[] newSources = sources.toArray(new File[sources.size() + 1]);
newSources[sources.size()] = newSource;
setSourceList(newSources, overrideSourcePath);
}
/**
* Removes a file from the source list.
* <p>
* If the specified file occurs more than once in the source list, the last
* entry is removed.
*
* @param sourceToRemove File to remove from the source list.
*/
public void removeSource(File sourceToRemove) throws InterruptedException
{
if (sources.isEmpty())
return;
sourceToRemove = FilenameNormalization.normalize(sourceToRemove);
if (!sources.contains(sourceToRemove))
return;
Set<File> newSources = new LinkedHashSet<File>(sources);
newSources.remove(sourceToRemove);
setSourceList(newSources.toArray(new File[newSources.size()]));
}
/**
* Adds {@link ICompilerProblem}'s found in the current
* source list to the specified collection.
* <p>
* These problems are with the source list itself, not with sources
* discovered in the source list. For example the returned collection would
* not contain syntax error problems, put will contain
* {@link DuplicateSourceFileProblem} problems.
*/
void collectProblems(Collection<ICompilerProblem> problems)
{
problems.addAll(this.problems);
}
/**
* Adds all the {@link ICompilationUnit}'s whose root source file is the
* specified File to the specified collection.
*
* @param rootSourceFile File to search for.
* @param units Collection to add to.
*/
public void collectionCompilationUnitsForRootSourceFile(File rootSourceFile, Collection<ICompilationUnit> units)
{
Collection<ICompilationUnit> compilationUnits = project.getCompilationUnits(rootSourceFile.getAbsolutePath());
units.addAll(compilationUnits);
}
/**
* Determines of the specified file is the root source file of any
* {@link ICompilationUnit} created by this {@code SourceListManager}.
*
* @param rootSourceFile File to search for.
* @return true if the specified file is the root source file of any
* {@link ICompilationUnit}'s created by this {@code SourceListManager}.
*/
public boolean hasCompilationUnitsForRootSourceFile(File rootSourceFile)
{
Collection<ICompilationUnit> compilationUnits = project.getCompilationUnits(rootSourceFile.getAbsolutePath());
return compilationUnits.size() > 0;
}
}