blob: 4fb154504ec09d79c5df9718d2dd8d2d756d1f5f [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.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.royale.compiler.asdoc.IASDocBundleDelegate;
import org.apache.royale.compiler.common.IFileSpecificationGetter;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.internal.projects.SourcePathManager.QNameFile;
import org.apache.royale.compiler.internal.units.CompilationUnitBase;
import org.apache.royale.compiler.internal.units.InvisibleCompilationUnit;
import org.apache.royale.compiler.internal.units.SourceCompilationUnitFactory;
import org.apache.royale.compiler.internal.workspaces.Workspace;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.projects.IASProject;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.compiler.units.IInvisibleCompilationUnit;
import org.apache.royale.swc.ISWC;
import org.apache.royale.swc.ISWCFileEntry;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
/**
* Implementation base class to implement functionality common to all
* IASProject implementations. DefinitionPromises ( aka
* "provisional definitions" ) are added to the project scope in this class.
*/
public abstract class ASProject extends CompilerProject implements IASProject
{
/**
* Constructor
*
* @param workspace The Workspace in which this project lives.
* @param useAS3 Indicate whether or not the AS3 namespace should
* be opened in all compilation units in the project.
*/
public ASProject(Workspace workspace, boolean useAS3)
{
this(workspace, useAS3, IASDocBundleDelegate.NIL_DELEGATE);
}
public ASProject(Workspace workspace, boolean useAS3, IASDocBundleDelegate asDocBundleDelegate)
{
super(workspace, useAS3);
sourcePathManager = new SourcePathManager(this);
sourceListManager = new SourceListManager(this, sourcePathManager);
sourceCompilationUnitFactory = new SourceCompilationUnitFactory(this);
sourceCompilationUnitFactory.addHandler(ASSourceFileHandler.INSTANCE);
sourceCompilationUnitFactory.addHandler(FXGSourceFileHandler.INSTANCE);
libraryPathManager = new LibraryPathManager(this);
projectDependencies = new HashMap<IASProject, String>();
dependingProjects = new HashSet<IASProject>();
this.asDocBundleDelegate = asDocBundleDelegate;
}
private final SourceListManager sourceListManager;
private final SourcePathManager sourcePathManager;
private final SourceCompilationUnitFactory sourceCompilationUnitFactory;
private final LibraryPathManager libraryPathManager;
private final Map<IASProject, String> projectDependencies;
private final Set<IASProject> dependingProjects;
private final IASDocBundleDelegate asDocBundleDelegate;
private int compatibilityVersionMajor;
private int compatibilityVersionMinor;
private int compatibilityVersionRevision;
@Override
public List<ISWC> getLibraries()
{
final ImmutableList<ISWC> result = new ImmutableList.Builder<ISWC>()
.addAll(libraryPathManager.getLibrarySWCs())
.build();
return result;
}
@Override
public void attachInternalLibrarySourcePath(File library, File sourceDir)
{
libraryPathManager.setLibrarySourcePath(library, sourceDir);
}
@Override
public void attachExternalLibrarySourcePath(File library, File sourceDir)
{
// TODO: rename this and attachInternalLibraySourcePath to be
// just attachLibrarySourcePath.
libraryPathManager.setLibrarySourcePath(library, sourceDir);
}
@Override
public String getAttachedSourceDirectory(String libraryFilename)
{
String result = libraryPathManager.getAttachedSourceDirectory(libraryFilename);
return result;
}
@Override
public void setSourcePath(List<File> paths)
{
sourcePathManager.setSourcePath(paths.toArray(new File[paths.size()]));
}
@Override
public List<File> getSourcePath()
{
return sourcePathManager.getSourcePath();
}
/**
* Adds a file to the project if that file is on the project's
* source path.
* @param f The file to be added.
* @return true if any new {@link ICompilationUnit}'s were created
* as a result of this operation, false otherwise.
*/
public boolean addSourcePathFile(File f)
{
return sourcePathManager.addFile(f);
}
/**
* Test if a file is on the source path or not.
*
* @param f The file to test. May not be null.
* @return true if the file is on the source path, false otherwise.
*/
public boolean isFileOnSourcePath(File f)
{
return sourcePathManager.isFileOnSourcePath(f);
}
@Override
public void setIncludeSources(File files[]) throws InterruptedException
{
sourceListManager.setSourceList(files);
}
@Override
public void addIncludeSourceFile(File file) throws InterruptedException
{
addIncludeSourceFile(file, false);
}
@Override
public void addIncludeSourceFile(File file, boolean overrideSourcePath) throws InterruptedException
{
sourceListManager.addSource(file, overrideSourcePath);
}
@Override
public void removeIncludeSourceFile(File file) throws InterruptedException
{
sourceListManager.removeSource(file);
}
/**
* Removes a source file to the project, removing any references in the various
* managers - SourcePathManager, SourceListManager etc
*
* @see #addIncludeSourceFile(File)
* @param f File to remove.
*/
public void removeSourceFile(File f)
{
try
{
// TODO: this is mostly a place holder for now. Need
// to go through and cleanup the whole removal flow
// note that the assumption is that these functions
// will fail gracefully if the file is not included
// in the various managers
// remove any reference to this file in the
// source list manager
sourceListManager.removeSource(f);
// remove any reference to this file in the
// source path manager
sourcePathManager.removeFile(f);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public SourceCompilationUnitFactory getSourceCompilationUnitFactory()
{
return sourceCompilationUnitFactory;
}
/**
* Called by {@link SourcePathManager} or {@link LibraryPathManager} when the source
* or library path change.
* @param toRemove {@link ICompilationUnit}'s to remove from the project.
* @param toAdd {@link ICompilationUnit}'s to add to the project.
*/
void updateCompilationUnitsForPathChange(Collection<ICompilationUnit> toRemove, Collection<ICompilationUnit> toAdd)
{
assert toRemove != null;
assert toAdd != null;
removeCompilationUnits(toRemove);
addCompilationUnits(toAdd);
for (ICompilationUnit unit : toAdd)
{
for (IDefinition definitionPromise : unit.getDefinitionPromises())
{
getScope().addDefinition(definitionPromise);
}
}
}
@Override
public Set<IASProject> getDependingProjects()
{
return dependingProjects;
}
@Override
public void addProjectDependeny(IASProject project, String swcFilename)
{
assert (project instanceof ASProject) : "project dependency must be of type ASProject";
((ASProject)project).dependingProjects.add(this);
projectDependencies.put(project, swcFilename);
}
@Override
public void removeProjectDependeny(IASProject project)
{
assert (project instanceof ASProject) : "project dependency must be of type ASProject";
((ASProject)project).dependingProjects.remove(this);
projectDependencies.remove(project);
}
@Override
public void setDependencies(Map<IASProject, String> newIProjectsDependencies)
{
Set<IASProject> newProjectDependencies = ImmutableSet.<IASProject> copyOf(newIProjectsDependencies.keySet());
Set<IASProject> dependenciesToRemove = ImmutableSet.<IASProject> copyOf(Sets.difference(projectDependencies.keySet(), newProjectDependencies));
Set<IASProject> dependenciesToAdd = ImmutableSet.<IASProject> copyOf(Sets.difference(newProjectDependencies, projectDependencies.keySet()));
for (IASProject projectDependency : dependenciesToRemove)
{
removeProjectDependeny(projectDependency);
}
for (IASProject projectDependency : dependenciesToAdd)
{
String swcFilename = newIProjectsDependencies.get(projectDependency);
addProjectDependeny(projectDependency, swcFilename);
}
}
/**
* Called by {@link SourceListManager} when the include sources list is changed.
* @param toRemove {@link ICompilationUnit}'s to remove from the project.
* @param toAdd {@link ICompilationUnit}'s to add to the project.
*/
void sourceListChange(Collection<ICompilationUnit> toRemove, Collection<ICompilationUnit> toAdd) throws InterruptedException
{
// passing empty lists to removeCompilationUnits
// and addCompilationUnitsAndUpdateDefinitions *is* harmless
// but avoiding the call to sourcePathManager.sourceListChanged
// will prevent us from enumerating a bunch of directories on disk
if ((!toRemove.isEmpty()) || (!toAdd.isEmpty()))
{
removeCompilationUnits(toRemove);
addCompilationUnitsAndUpdateDefinitions(toAdd);
}
}
@Override
public void collectProblems(Collection<ICompilerProblem> problems)
{
sourcePathManager.collectProblems(problems);
sourceListManager.collectProblems(problems);
libraryPathManager.collectProblems(problems);
collectConfigProblems(problems);
}
/**
* Finds all the {@link ICompilationUnit}'s in this project whose root source file is the specified file.
*/
public void collectionCompilationUnitsForRootSourceFile(File rootSourceFile, Collection<ICompilationUnit> units)
{
sourcePathManager.collectionCompilationUnitsForRootSourceFile(rootSourceFile, units);
sourceListManager.collectionCompilationUnitsForRootSourceFile(rootSourceFile, units);
}
public boolean hasCompilationUnitForRootSourceFile(File rootSourceFile)
{
return sourcePathManager.hasCompilationUnitsForRootSourceFile(rootSourceFile) ||
sourceListManager.hasCompilationUnitsForRootSourceFile(rootSourceFile);
}
@Override
public boolean invalidateLibraries(Collection<File> swcFiles)
{
return libraryPathManager.invalidate(swcFiles);
}
@Override
public void invalidateLibrary(ISWC swc)
{
libraryPathManager.invalidate(swc);
}
@Override
public boolean handleAddedFile(File addedFile)
{
return addSourcePathFile(addedFile);
}
@Override
public String getSourceFileFromSourcePath(String file)
{
return sourcePathManager.getSourceFileFromSourcePath(file);
}
/**
* Iterate through the library path list looking for the specified file.
* @param file to look for
* @return ISWCFileEntry to the file, or null if file not found
*/
public ISWCFileEntry getSourceFileFromLibraryPath(String file)
{
return libraryPathManager.getFileEntryFromLibraryPath(file);
}
public IASDocBundleDelegate getASDocBundleDelegate()
{
return asDocBundleDelegate;
}
@Override
public void setLibraries(List<File> libraries)
{
assert libraries != null : "Libraries may not be null";
libraryPathManager.setLibraryPath(libraries.toArray(new File[libraries.size()]));
}
/**
* Sets the SDK compatibility version. For this release, the only valid value is 2.0.1.
*
* @param major The major version. For this release, this value must be 2.
* @param minor The minor version. For this release, this value must be 0.
* @param revision For this release, this value must be 1.
*/
public void setCompatibilityVersion(int major, int minor, int revision)
{
compatibilityVersionMajor = major;
compatibilityVersionMinor = minor;
compatibilityVersionRevision = revision;
clean();
}
@Override
public Integer getCompatibilityVersion()
{
int compatibilityVersion = (compatibilityVersionMajor << 24) + (compatibilityVersionMinor << 16) +
compatibilityVersionRevision;
return compatibilityVersion != 0 ? compatibilityVersion : null;
}
@Override
public String getCompatibilityVersionString()
{
int sum = compatibilityVersionMajor + compatibilityVersionMinor + compatibilityVersionRevision;
if (sum == 0)
return null;
return compatibilityVersionMajor + "." +
compatibilityVersionMinor + "." +
compatibilityVersionRevision;
}
@Override
public IInvisibleCompilationUnit createInvisibleCompilationUnit(String rootSourceFile, IFileSpecificationGetter fileSpecGetter)
{
QNameFile qNameFile = sourcePathManager.computeQNameForFilename(rootSourceFile);
if (qNameFile == null)
return null;
CompilationUnitBase invisibleCUDelegate = createInvisibleCompilationUnit(qNameFile);
if (invisibleCUDelegate == null)
return null;
return new InvisibleCompilationUnit(invisibleCUDelegate, fileSpecGetter);
}
@Override
public IInvisibleCompilationUnit createInvisibleCompilationUnit(String rootSourceFile, IFileSpecificationGetter fileSpecGetter, String qName)
{
QNameFile qNameFile = new QNameFile(qName, new File(rootSourceFile), null, 0);
CompilationUnitBase invisibleCUDelegate = createInvisibleCompilationUnit(qNameFile);
if (invisibleCUDelegate == null)
return null;
return new InvisibleCompilationUnit(invisibleCUDelegate, fileSpecGetter);
}
/**
* Create's a new {@link CompilationUnitBase} that is marked as being a
* delegate for an {@link InvisibleCompilationUnit}.
*
* @param qNameFile The qNameFile of the new {@link InvisibleCompilationUnit}.
* @return A new {@link CompilationUnitBase} that is marked as being a
* delegate for an {@link InvisibleCompilationUnit} or null if the specified
* file name is not on the source path.
*/
private CompilationUnitBase createInvisibleCompilationUnit(QNameFile qNameFile)
{
SourceCompilationUnitFactory compilationUnitFactory = getSourceCompilationUnitFactory();
if (!compilationUnitFactory.canCreateCompilationUnit(qNameFile.file))
return null;
CompilationUnitBase newCU = (CompilationUnitBase)getSourceCompilationUnitFactory().createCompilationUnit(
qNameFile.file, DefinitionPriority.BasePriority.SOURCE_PATH, 0, qNameFile.qName, qNameFile.locale);
assert newCU != null : "canCreateCompilationUnit should have returned false if createCompilationUnit returns null!";
addCompilationUnit(newCU);
return newCU;
}
@Override
public boolean isAssetEmbeddingSupported()
{
return true;
}
@Override
public boolean isSupportedSourceFileType(String fileExtension)
{
return sourceCompilationUnitFactory.canCreateCompilationUnitForFileType(fileExtension);
}
}