| /* |
| * Copyright (c) 2013, the Dart project authors. |
| * |
| * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html |
| * |
| * 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 com.google.dart.engine.internal.resolver; |
| |
| import com.google.dart.engine.AnalysisEngine; |
| import com.google.dart.engine.ast.CompilationUnit; |
| import com.google.dart.engine.ast.ImportDirective; |
| import com.google.dart.engine.ast.StringInterpolation; |
| import com.google.dart.engine.ast.StringLiteral; |
| import com.google.dart.engine.ast.UriBasedDirective; |
| import com.google.dart.engine.context.AnalysisException; |
| import com.google.dart.engine.error.AnalysisError; |
| import com.google.dart.engine.error.AnalysisErrorListener; |
| import com.google.dart.engine.error.CompileTimeErrorCode; |
| import com.google.dart.engine.internal.context.InternalAnalysisContext; |
| import com.google.dart.engine.internal.context.ResolvableCompilationUnit; |
| import com.google.dart.engine.internal.element.LibraryElementImpl; |
| import com.google.dart.engine.internal.scope.LibraryScope; |
| import com.google.dart.engine.source.Source; |
| import com.google.dart.engine.utilities.io.UriUtilities; |
| |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| /** |
| * Instances of the class {@code Library} represent the data about a single library during the |
| * resolution of some (possibly different) library. They are not intended to be used except during |
| * the resolution process. |
| * |
| * @coverage dart.engine.resolver |
| */ |
| public class Library { |
| /** |
| * The analysis context in which this library is being analyzed. |
| */ |
| private InternalAnalysisContext analysisContext; |
| |
| /** |
| * The inheritance manager which is used for this member lookups in this library. |
| */ |
| private InheritanceManager inheritanceManager; |
| |
| /** |
| * The listener to which analysis errors will be reported. |
| */ |
| private AnalysisErrorListener errorListener; |
| |
| /** |
| * The source specifying the defining compilation unit of this library. |
| */ |
| private Source librarySource; |
| |
| /** |
| * The library element representing this library. |
| */ |
| private LibraryElementImpl libraryElement; |
| |
| /** |
| * A list containing all of the libraries that are imported into this library. |
| */ |
| private Library[] importedLibraries = EMPTY_ARRAY; |
| |
| /** |
| * A table mapping URI-based directive to the actual URI value. |
| */ |
| private HashMap<UriBasedDirective, String> directiveUris = new HashMap<UriBasedDirective, String>(); |
| |
| /** |
| * A flag indicating whether this library explicitly imports core. |
| */ |
| private boolean explicitlyImportsCore = false; |
| |
| /** |
| * A list containing all of the libraries that are exported from this library. |
| */ |
| private Library[] exportedLibraries = EMPTY_ARRAY; |
| |
| /** |
| * A table mapping the sources for the compilation units in this library to their corresponding |
| * AST structures. |
| */ |
| private HashMap<Source, ResolvableCompilationUnit> astMap = new HashMap<Source, ResolvableCompilationUnit>(); |
| |
| /** |
| * The library scope used when resolving elements within this library's compilation units. |
| */ |
| private LibraryScope libraryScope; |
| |
| /** |
| * An empty array that can be used to initialize lists of libraries. |
| */ |
| private static final Library[] EMPTY_ARRAY = new Library[0]; |
| |
| /** |
| * The prefix of a URI using the dart-ext scheme to reference a native code library. |
| */ |
| private static final String DART_EXT_SCHEME = "dart-ext:"; |
| |
| /** |
| * Initialize a newly created data holder that can maintain the data associated with a library. |
| * |
| * @param analysisContext the analysis context in which this library is being analyzed |
| * @param errorListener the listener to which analysis errors will be reported |
| * @param librarySource the source specifying the defining compilation unit of this library |
| */ |
| public Library(InternalAnalysisContext analysisContext, AnalysisErrorListener errorListener, |
| Source librarySource) { |
| this.analysisContext = analysisContext; |
| this.errorListener = errorListener; |
| this.librarySource = librarySource; |
| this.libraryElement = (LibraryElementImpl) analysisContext.getLibraryElement(librarySource); |
| } |
| |
| /** |
| * Return the AST structure associated with the given source. |
| * |
| * @param source the source representing the compilation unit whose AST is to be returned |
| * @return the AST structure associated with the given source |
| * @throws AnalysisException if an AST structure could not be created for the compilation unit |
| */ |
| public CompilationUnit getAST(Source source) throws AnalysisException { |
| ResolvableCompilationUnit holder = astMap.get(source); |
| if (holder == null) { |
| holder = analysisContext.computeResolvableCompilationUnit(source); |
| astMap.put(source, holder); |
| } |
| return holder.getCompilationUnit(); |
| } |
| |
| /** |
| * Return an array of the {@link CompilationUnit}s that make up the library. The first unit is |
| * always the defining unit. |
| * |
| * @return an array of the {@link CompilationUnit}s that make up the library. The first unit is |
| * always the defining unit |
| */ |
| public CompilationUnit[] getCompilationUnits() throws AnalysisException { |
| ArrayList<CompilationUnit> unitArrayList = new ArrayList<CompilationUnit>(astMap.size()); |
| unitArrayList.add(getDefiningCompilationUnit()); |
| for (Source source : astMap.keySet()) { |
| if (!librarySource.equals(source)) { |
| unitArrayList.add(getAST(source)); |
| } |
| } |
| return unitArrayList.toArray(new CompilationUnit[unitArrayList.size()]); |
| } |
| |
| /** |
| * Return a collection containing the sources for the compilation units in this library, including |
| * the defining compilation unit. |
| * |
| * @return the sources for the compilation units in this library |
| */ |
| public Set<Source> getCompilationUnitSources() { |
| return astMap.keySet(); |
| } |
| |
| /** |
| * Return the AST structure associated with the defining compilation unit for this library. |
| * |
| * @return the AST structure associated with the defining compilation unit for this library |
| * @throws AnalysisException if an AST structure could not be created for the defining compilation |
| * unit |
| */ |
| public CompilationUnit getDefiningCompilationUnit() throws AnalysisException { |
| return getAST(librarySource); |
| } |
| |
| /** |
| * Return {@code true} if this library explicitly imports core. |
| * |
| * @return {@code true} if this library explicitly imports core |
| */ |
| public boolean getExplicitlyImportsCore() { |
| return explicitlyImportsCore; |
| } |
| |
| /** |
| * Return an array containing the libraries that are exported from this library. |
| * |
| * @return an array containing the libraries that are exported from this library |
| */ |
| public Library[] getExports() { |
| return exportedLibraries; |
| } |
| |
| /** |
| * Return an array containing the libraries that are imported into this library. |
| * |
| * @return an array containing the libraries that are imported into this library |
| */ |
| public Library[] getImports() { |
| return importedLibraries; |
| } |
| |
| /** |
| * Return an array containing the libraries that are either imported or exported from this |
| * library. |
| * |
| * @return the libraries that are either imported or exported from this library |
| */ |
| public Library[] getImportsAndExports() { |
| HashSet<Library> libraries = new HashSet<Library>(importedLibraries.length |
| + exportedLibraries.length); |
| for (Library library : importedLibraries) { |
| libraries.add(library); |
| } |
| for (Library library : exportedLibraries) { |
| libraries.add(library); |
| } |
| return libraries.toArray(new Library[libraries.size()]); |
| } |
| |
| /** |
| * Return the inheritance manager for this library. |
| * |
| * @return the inheritance manager for this library |
| */ |
| public InheritanceManager getInheritanceManager() { |
| if (inheritanceManager == null) { |
| return inheritanceManager = new InheritanceManager(libraryElement); |
| } |
| return inheritanceManager; |
| } |
| |
| /** |
| * Return the library element representing this library, creating it if necessary. |
| * |
| * @return the library element representing this library |
| */ |
| public LibraryElementImpl getLibraryElement() { |
| if (libraryElement == null) { |
| try { |
| libraryElement = (LibraryElementImpl) analysisContext.computeLibraryElement(librarySource); |
| } catch (AnalysisException exception) { |
| AnalysisEngine.getInstance().getLogger().logError( |
| "Could not compute library element for " + librarySource.getFullName(), |
| exception); |
| } |
| } |
| return libraryElement; |
| } |
| |
| /** |
| * Return the library scope used when resolving elements within this library's compilation units. |
| * |
| * @return the library scope used when resolving elements within this library's compilation units |
| */ |
| public LibraryScope getLibraryScope() { |
| if (libraryScope == null) { |
| libraryScope = new LibraryScope(libraryElement, errorListener); |
| } |
| return libraryScope; |
| } |
| |
| /** |
| * Return the source specifying the defining compilation unit of this library. |
| * |
| * @return the source specifying the defining compilation unit of this library |
| */ |
| public Source getLibrarySource() { |
| return librarySource; |
| } |
| |
| /** |
| * Return the modification time associated with the given source. |
| * |
| * @param source the source representing the compilation unit whose modification time is to be |
| * returned |
| * @return the modification time associated with the given source |
| * @throws AnalysisException if an AST structure could not be created for the compilation unit |
| */ |
| public long getModificationTime(Source source) throws AnalysisException { |
| ResolvableCompilationUnit holder = astMap.get(source); |
| if (holder == null) { |
| holder = analysisContext.computeResolvableCompilationUnit(source); |
| astMap.put(source, holder); |
| } |
| return holder.getModificationTime(); |
| } |
| |
| /** |
| * Return the result of resolving the URI of the given URI-based directive against the URI of the |
| * library, or {@code null} if the URI is not valid. If the URI is not valid, report the error. |
| * |
| * @param directive the directive which URI should be resolved |
| * @return the result of resolving the URI against the URI of the library |
| */ |
| public Source getSource(UriBasedDirective directive) { |
| StringLiteral uriLiteral = directive.getUri(); |
| if (uriLiteral instanceof StringInterpolation) { |
| errorListener.onError(new AnalysisError( |
| librarySource, |
| uriLiteral.getOffset(), |
| uriLiteral.getLength(), |
| CompileTimeErrorCode.URI_WITH_INTERPOLATION)); |
| return null; |
| } |
| String uriContent = uriLiteral.getStringValue().trim(); |
| directiveUris.put(directive, uriContent); |
| uriContent = UriUtilities.encode(uriContent); |
| if (directive instanceof ImportDirective && uriContent.startsWith(DART_EXT_SCHEME)) { |
| libraryElement.setHasExtUri(true); |
| return null; |
| } |
| try { |
| new URI(uriContent); |
| Source source = analysisContext.getSourceFactory().resolveUri(librarySource, uriContent); |
| if (!analysisContext.exists(source)) { |
| errorListener.onError(new AnalysisError( |
| librarySource, |
| uriLiteral.getOffset(), |
| uriLiteral.getLength(), |
| CompileTimeErrorCode.URI_DOES_NOT_EXIST, |
| uriContent)); |
| } |
| return source; |
| } catch (URISyntaxException exception) { |
| errorListener.onError(new AnalysisError( |
| librarySource, |
| uriLiteral.getOffset(), |
| uriLiteral.getLength(), |
| CompileTimeErrorCode.INVALID_URI, |
| uriContent)); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the URI value of the given directive. |
| */ |
| public String getUri(UriBasedDirective directive) { |
| return directiveUris.get(directive); |
| } |
| |
| /** |
| * Set the AST structure associated with the defining compilation unit for this library to the |
| * given AST structure. |
| * |
| * @param modificationStamp the modification time of the source from which the compilation unit |
| * was created |
| * @param unit the AST structure associated with the defining compilation unit for this library |
| */ |
| public void setDefiningCompilationUnit(long modificationStamp, CompilationUnit unit) { |
| astMap.put(librarySource, new ResolvableCompilationUnit(modificationStamp, unit)); |
| } |
| |
| /** |
| * Set whether this library explicitly imports core to match the given value. |
| * |
| * @param explicitlyImportsCore {@code true} if this library explicitly imports core |
| */ |
| public void setExplicitlyImportsCore(boolean explicitlyImportsCore) { |
| this.explicitlyImportsCore = explicitlyImportsCore; |
| } |
| |
| /** |
| * Set the libraries that are exported by this library to be those in the given array. |
| * |
| * @param exportedLibraries the libraries that are exported by this library |
| */ |
| public void setExportedLibraries(Library[] exportedLibraries) { |
| this.exportedLibraries = exportedLibraries; |
| } |
| |
| /** |
| * Set the libraries that are imported into this library to be those in the given array. |
| * |
| * @param importedLibraries the libraries that are imported into this library |
| */ |
| public void setImportedLibraries(Library[] importedLibraries) { |
| this.importedLibraries = importedLibraries; |
| } |
| |
| /** |
| * Set the library element representing this library to the given library element. |
| * |
| * @param libraryElement the library element representing this library |
| */ |
| public void setLibraryElement(LibraryElementImpl libraryElement) { |
| this.libraryElement = libraryElement; |
| if (inheritanceManager != null) { |
| inheritanceManager.setLibraryElement(libraryElement); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return librarySource.getShortName(); |
| } |
| } |