Package com.google.dart.engine.internal.resolver

Source Code of com.google.dart.engine.internal.resolver.LibraryResolver2

/*
* 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.ast.Combinator;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.ast.Directive;
import com.google.dart.engine.ast.ExportDirective;
import com.google.dart.engine.ast.HideCombinator;
import com.google.dart.engine.ast.ImportDirective;
import com.google.dart.engine.ast.NamespaceDirective;
import com.google.dart.engine.ast.NodeList;
import com.google.dart.engine.ast.ShowCombinator;
import com.google.dart.engine.ast.SimpleIdentifier;
import com.google.dart.engine.ast.StringLiteral;
import com.google.dart.engine.context.AnalysisContext;
import com.google.dart.engine.context.AnalysisException;
import com.google.dart.engine.element.Element;
import com.google.dart.engine.element.ExportElement;
import com.google.dart.engine.element.FunctionElement;
import com.google.dart.engine.element.ImportElement;
import com.google.dart.engine.element.LibraryElement;
import com.google.dart.engine.element.NamespaceCombinator;
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.error.ErrorCode;
import com.google.dart.engine.error.StaticWarningCode;
import com.google.dart.engine.internal.builder.AngularCompilationUnitBuilder;
import com.google.dart.engine.internal.builder.EnumMemberBuilder;
import com.google.dart.engine.internal.builder.PolymerCompilationUnitBuilder;
import com.google.dart.engine.internal.constant.ConstantValueComputer;
import com.google.dart.engine.internal.context.InternalAnalysisContext;
import com.google.dart.engine.internal.context.PerformanceStatistics;
import com.google.dart.engine.internal.context.RecordingErrorListener;
import com.google.dart.engine.internal.context.ResolvableCompilationUnit;
import com.google.dart.engine.internal.element.ExportElementImpl;
import com.google.dart.engine.internal.element.HideElementCombinatorImpl;
import com.google.dart.engine.internal.element.ImportElementImpl;
import com.google.dart.engine.internal.element.LibraryElementImpl;
import com.google.dart.engine.internal.element.PrefixElementImpl;
import com.google.dart.engine.internal.element.ShowElementCombinatorImpl;
import com.google.dart.engine.internal.scope.Namespace;
import com.google.dart.engine.internal.scope.NamespaceBuilder;
import com.google.dart.engine.sdk.DartSdk;
import com.google.dart.engine.sdk.DirectoryBasedDartSdk;
import com.google.dart.engine.source.DartUriResolver;
import com.google.dart.engine.source.Source;
import com.google.dart.engine.source.SourceKind;
import com.google.dart.engine.utilities.general.TimeCounter.TimeCounterHandle;
import com.google.dart.engine.utilities.instrumentation.Instrumentation;
import com.google.dart.engine.utilities.instrumentation.InstrumentationBuilder;
import com.google.dart.engine.utilities.translation.DartBlockBody;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
* Instances of the class {@code LibraryResolver} are used to resolve one or more mutually dependent
* libraries within a single context.
*
* @coverage dart.engine.resolver
*/
public class LibraryResolver2 {
  /**
   * Report that the core library could not be resolved in the given analysis context and throw an
   * exception.
   *
   * @param analysisContext the analysis context in which the failure occurred
   * @param coreLibrarySource the source representing the core library
   * @throws AnalysisException always
   */
  @DartBlockBody({"throw new AnalysisException(\"Could not resolve dart:core\");"})
  public static void missingCoreLibrary(AnalysisContext analysisContext, Source coreLibrarySource)
      throws AnalysisException {
    InstrumentationBuilder instrumentation = Instrumentation.builder("ErrorNoCoreLibrary");
    try {
      DartSdk sdk = analysisContext.getSourceFactory().getDartSdk();
      if (sdk == null) {
        instrumentation.data("sdkPath", "--null--");
      } else if (sdk instanceof DirectoryBasedDartSdk) {
        File directory = ((DirectoryBasedDartSdk) sdk).getDirectory();
        if (directory == null) {
          instrumentation.data("sdkDirectoryIsNull", true);
        } else {
          instrumentation.data("sdkDirectoryIsNull", false);
          instrumentation.data("sdkPath", directory.getAbsolutePath());
          instrumentation.data("sdkDirectoryExists", directory.exists());
        }
      } else {
        instrumentation.data("sdkPath", "--unknown--");
      }
      instrumentation.data("coreLibraryPath", coreLibrarySource.getFullName());
    } finally {
      instrumentation.log();
    }
    throw new AnalysisException("Could not resolve dart:core");
  }

  /**
   * The analysis context in which the libraries are being analyzed.
   */
  private InternalAnalysisContext analysisContext;

  /**
   * The listener to which analysis errors will be reported, this error listener is either
   * references {@link #recordingErrorListener}, or it unions the passed
   * {@link AnalysisErrorListener} with the {@link #recordingErrorListener}.
   */
  private RecordingErrorListener errorListener;

  /**
   * A source object representing the core library (dart:core).
   */
  private Source coreLibrarySource;

  /**
   * The object representing the core library.
   */
  private ResolvableLibrary coreLibrary;

  /**
   * The object used to access the types from the core library.
   */
  private TypeProvider typeProvider;

  /**
   * A table mapping library sources to the information being maintained for those libraries.
   */
  private HashMap<Source, ResolvableLibrary> libraryMap = new HashMap<Source, ResolvableLibrary>();

  /**
   * A collection containing the libraries that are being resolved together.
   */
  private List<ResolvableLibrary> librariesInCycle;

  /**
   * Initialize a newly created library resolver to resolve libraries within the given context.
   *
   * @param analysisContext the analysis context in which the library is being analyzed
   */
  public LibraryResolver2(InternalAnalysisContext analysisContext) {
    this.analysisContext = analysisContext;
    this.errorListener = new RecordingErrorListener();
    coreLibrarySource = analysisContext.getSourceFactory().forUri(DartSdk.DART_CORE);
  }

  /**
   * Return the analysis context in which the libraries are being analyzed.
   *
   * @return the analysis context in which the libraries are being analyzed
   */
  public InternalAnalysisContext getAnalysisContext() {
    return analysisContext;
  }

  /**
   * Return the listener to which analysis errors will be reported.
   *
   * @return the listener to which analysis errors will be reported
   */
  public RecordingErrorListener getErrorListener() {
    return errorListener;
  }

  /**
   * Return an array containing information about all of the libraries that were resolved.
   *
   * @return an array containing the libraries that were resolved
   */
  public List<ResolvableLibrary> getResolvedLibraries() {
    return librariesInCycle;
  }

  /**
   * Resolve the library specified by the given source in the given context.
   * <p>
   * Note that because Dart allows circular imports between libraries, it is possible that more than
   * one library will need to be resolved. In such cases the error listener can receive errors from
   * multiple libraries.
   *
   * @param librarySource the source specifying the defining compilation unit of the library to be
   *          resolved
   * @param fullAnalysis {@code true} if a full analysis should be performed
   * @return the element representing the resolved library
   * @throws AnalysisException if the library could not be resolved for some reason
   */
  public LibraryElement resolveLibrary(Source librarySource,
      List<ResolvableLibrary> librariesInCycle) throws AnalysisException {
    InstrumentationBuilder instrumentation = Instrumentation.builder("dart.engine.LibraryResolver.resolveLibrary");
    try {
      instrumentation.data("fullName", librarySource.getFullName());
      //
      // Build the map of libraries that are known.
      //
      this.librariesInCycle = librariesInCycle;
      libraryMap = buildLibraryMap();
      ResolvableLibrary targetLibrary = libraryMap.get(librarySource);
      coreLibrary = libraryMap.get(coreLibrarySource);
      instrumentation.metric("buildLibraryMap", "complete");
      //
      // Build the element models representing the libraries being resolved. This is done in three
      // steps:
      //
      // 1. Build the basic element models without making any connections between elements other
      //    than the basic parent/child relationships. This includes building the elements
      //    representing the libraries, but excludes members defined in enums.
      // 2. Build the elements for the import and export directives. This requires that we have the
      //    elements built for the referenced libraries, but because of the possibility of circular
      //    references needs to happen after all of the library elements have been created.
      // 3. Build the members in enum declarations.
      // 4. Build the rest of the type model by connecting superclasses, mixins, and interfaces. This
      //    requires that we be able to compute the names visible in the libraries being resolved,
      //    which in turn requires that we have resolved the import directives.
      //
      buildElementModels();
      instrumentation.metric("buildElementModels", "complete");
      LibraryElement coreElement = coreLibrary.getLibraryElement();
      if (coreElement == null) {
        missingCoreLibrary(analysisContext, coreLibrarySource);
      }
      buildDirectiveModels();
      instrumentation.metric("buildDirectiveModels", "complete");
      typeProvider = new TypeProviderImpl(coreElement);
      buildEnumMembers();
      buildTypeHierarchies();
      instrumentation.metric("buildTypeHierarchies", "complete");
      //
      // Perform resolution and type analysis.
      //
      // TODO(brianwilkerson) Decide whether we want to resolve all of the libraries or whether we
      // want to only resolve the target library. The advantage to resolving everything is that we
      // have already done part of the work so we'll avoid duplicated effort. The disadvantage of
      // resolving everything is that we might do extra work that we don't really care about. Another
      // possibility is to add a parameter to this method and punt the decision to the clients.
      //
      //if (analyzeAll) {
      resolveReferencesAndTypes();
      instrumentation.metric("resolveReferencesAndTypes", "complete");
      //} else {
      //  resolveReferencesAndTypes(targetLibrary);
      //}
      performConstantEvaluation();
      instrumentation.metric("performConstantEvaluation", "complete");
      instrumentation.metric("librariesInCycles", librariesInCycle.size());
      for (ResolvableLibrary lib : librariesInCycle) {
        instrumentation.metric(
            "librariesInCycles-CompilationUnitSources-Size",
            lib.getCompilationUnitSources().length);
      }

      return targetLibrary.getLibraryElement();
    } finally {
      instrumentation.log();
    }
  }

  /**
   * Build the element model representing the combinators declared by the given directive.
   *
   * @param directive the directive that declares the combinators
   * @return an array containing the import combinators that were built
   */
  // TODO(brianwilkerson) Move with buildDirectiveModels().
  private NamespaceCombinator[] buildCombinators(NamespaceDirective directive) {
    ArrayList<NamespaceCombinator> combinators = new ArrayList<NamespaceCombinator>();
    for (Combinator combinator : directive.getCombinators()) {
      if (combinator instanceof HideCombinator) {
        HideElementCombinatorImpl hide = new HideElementCombinatorImpl();
        hide.setHiddenNames(getIdentifiers(((HideCombinator) combinator).getHiddenNames()));
        combinators.add(hide);
      } else {
        ShowElementCombinatorImpl show = new ShowElementCombinatorImpl();
        show.setOffset(combinator.getOffset());
        show.setEnd(combinator.getEnd());
        show.setShownNames(getIdentifiers(((ShowCombinator) combinator).getShownNames()));
        combinators.add(show);
      }
    }
    return combinators.toArray(new NamespaceCombinator[combinators.size()]);
  }

  /**
   * Every library now has a corresponding {@link LibraryElement}, so it is now possible to resolve
   * the import and export directives.
   *
   * @throws AnalysisException if the defining compilation unit for any of the libraries could not
   *           be accessed
   */
  // TODO(brianwilkerson) The body of this method probably wants to be moved into a separate class.
  private void buildDirectiveModels() throws AnalysisException {
    for (ResolvableLibrary library : librariesInCycle) {
      HashMap<String, PrefixElementImpl> nameToPrefixMap = new HashMap<String, PrefixElementImpl>();
      ArrayList<ImportElement> imports = new ArrayList<ImportElement>();
      ArrayList<ExportElement> exports = new ArrayList<ExportElement>();
      for (Directive directive : library.getDefiningCompilationUnit().getDirectives()) {
        if (directive instanceof ImportDirective) {
          ImportDirective importDirective = (ImportDirective) directive;
          String uriContent = importDirective.getUriContent();
          if (DartUriResolver.isDartExtUri(uriContent)) {
            library.getLibraryElement().setHasExtUri(true);
          }
          Source importedSource = importDirective.getSource();
          if (importedSource != null && analysisContext.exists(importedSource)) {
            // The imported source will be null if the URI in the import directive was invalid.
            ResolvableLibrary importedLibrary = libraryMap.get(importedSource);
            if (importedLibrary != null) {
              ImportElementImpl importElement = new ImportElementImpl(directive.getOffset());
              StringLiteral uriLiteral = importDirective.getUri();
              if (uriLiteral != null) {
                importElement.setUriOffset(uriLiteral.getOffset());
                importElement.setUriEnd(uriLiteral.getEnd());
              }
              importElement.setUri(uriContent);
              importElement.setDeferred(importDirective.getDeferredToken() != null);
              importElement.setCombinators(buildCombinators(importDirective));
              LibraryElement importedLibraryElement = importedLibrary.getLibraryElement();
              if (importedLibraryElement != null) {
                importElement.setImportedLibrary(importedLibraryElement);
              }
              SimpleIdentifier prefixNode = ((ImportDirective) directive).getPrefix();
              if (prefixNode != null) {
                importElement.setPrefixOffset(prefixNode.getOffset());
                String prefixName = prefixNode.getName();
                PrefixElementImpl prefix = nameToPrefixMap.get(prefixName);
                if (prefix == null) {
                  prefix = new PrefixElementImpl(prefixNode);
                  nameToPrefixMap.put(prefixName, prefix);
                }
                importElement.setPrefix(prefix);
                prefixNode.setStaticElement(prefix);
              }
              directive.setElement(importElement);
              imports.add(importElement);

              if (analysisContext.computeKindOf(importedSource) != SourceKind.LIBRARY) {
                ErrorCode errorCode = importElement.isDeferred()
                    ? StaticWarningCode.IMPORT_OF_NON_LIBRARY
                    : CompileTimeErrorCode.IMPORT_OF_NON_LIBRARY;
                errorListener.onError(new AnalysisError(
                    library.getLibrarySource(),
                    uriLiteral.getOffset(),
                    uriLiteral.getLength(),
                    errorCode,
                    uriLiteral.toSource()));
              }
            }
          }
        } else if (directive instanceof ExportDirective) {
          ExportDirective exportDirective = (ExportDirective) directive;
          Source exportedSource = exportDirective.getSource();
          if (exportedSource != null && analysisContext.exists(exportedSource)) {
            // The exported source will be null if the URI in the export directive was invalid.
            ResolvableLibrary exportedLibrary = libraryMap.get(exportedSource);
            if (exportedLibrary != null) {
              ExportElementImpl exportElement = new ExportElementImpl();
              StringLiteral uriLiteral = exportDirective.getUri();
              if (uriLiteral != null) {
                exportElement.setUriOffset(uriLiteral.getOffset());
                exportElement.setUriEnd(uriLiteral.getEnd());
              }
              exportElement.setUri(exportDirective.getUriContent());
              exportElement.setCombinators(buildCombinators(exportDirective));
              LibraryElement exportedLibraryElement = exportedLibrary.getLibraryElement();
              if (exportedLibraryElement != null) {
                exportElement.setExportedLibrary(exportedLibraryElement);
              }
              directive.setElement(exportElement);
              exports.add(exportElement);

              if (analysisContext.computeKindOf(exportedSource) != SourceKind.LIBRARY) {
                errorListener.onError(new AnalysisError(
                    library.getLibrarySource(),
                    uriLiteral.getOffset(),
                    uriLiteral.getLength(),
                    CompileTimeErrorCode.EXPORT_OF_NON_LIBRARY,
                    uriLiteral.toSource()));
              }
            }
          }
        }
      }
      Source librarySource = library.getLibrarySource();
      if (!library.getExplicitlyImportsCore() && !coreLibrarySource.equals(librarySource)) {
        ImportElementImpl importElement = new ImportElementImpl(-1);
        importElement.setImportedLibrary(coreLibrary.getLibraryElement());
        importElement.setSynthetic(true);
        imports.add(importElement);
      }
      LibraryElementImpl libraryElement = library.getLibraryElement();
      libraryElement.setImports(imports.toArray(new ImportElement[imports.size()]));
      libraryElement.setExports(exports.toArray(new ExportElement[exports.size()]));
      if (libraryElement.getEntryPoint() == null) {
        Namespace namespace = new NamespaceBuilder().createExportNamespaceForLibrary(libraryElement);
        Element element = namespace.get(LibraryElementBuilder.ENTRY_POINT_NAME);
        if (element instanceof FunctionElement) {
          libraryElement.setEntryPoint((FunctionElement) element);
        }
      }
    }
  }

  /**
   * Build element models for all of the libraries in the current cycle.
   *
   * @throws AnalysisException if any of the element models cannot be built
   */
  private void buildElementModels() throws AnalysisException {
    for (ResolvableLibrary library : librariesInCycle) {
      LibraryElementBuilder builder = new LibraryElementBuilder(
          getAnalysisContext(),
          getErrorListener());
      LibraryElementImpl libraryElement = builder.buildLibrary(library);
      library.setLibraryElement(libraryElement);
    }
  }

  /**
   * Build the members in enum declarations. This cannot be done while building the rest of the
   * element model because it depends on being able to access core types, which cannot happen until
   * the rest of the element model has been built (when resolving the core library).
   *
   * @throws AnalysisException if any of the enum members could not be built
   */
  private void buildEnumMembers() throws AnalysisException {
    TimeCounterHandle timeCounter = PerformanceStatistics.resolve.start();
    try {
      for (ResolvableLibrary library : librariesInCycle) {
        for (Source source : library.getCompilationUnitSources()) {
          EnumMemberBuilder builder = new EnumMemberBuilder(typeProvider);
          library.getAST(source).accept(builder);
        }
      }
    } finally {
      timeCounter.stop();
    }
  }

  private HashMap<Source, ResolvableLibrary> buildLibraryMap() {
    HashMap<Source, ResolvableLibrary> libraryMap = new HashMap<Source, ResolvableLibrary>();
    int libraryCount = librariesInCycle.size();
    for (int i = 0; i < libraryCount; i++) {
      ResolvableLibrary library = librariesInCycle.get(i);
      library.setErrorListener(errorListener);
      libraryMap.put(library.getLibrarySource(), library);
      ResolvableLibrary[] dependencies = library.getImportsAndExports();
      int dependencyCount = dependencies.length;
      for (int j = 0; j < dependencyCount; j++) {
        ResolvableLibrary dependency = dependencies[j];
        //dependency.setErrorListener(errorListener);
        libraryMap.put(dependency.getLibrarySource(), dependency);
      }
    }
    return libraryMap;
  }

  /**
   * Resolve the type hierarchy across all of the types declared in the libraries in the current
   * cycle.
   *
   * @throws AnalysisException if any of the type hierarchies could not be resolved
   */
  private void buildTypeHierarchies() throws AnalysisException {
    TimeCounterHandle timeCounter = PerformanceStatistics.resolve.start();
    try {
      for (ResolvableLibrary library : librariesInCycle) {
        for (ResolvableCompilationUnit unit : library.getResolvableCompilationUnits()) {
          Source source = unit.getSource();
          CompilationUnit ast = unit.getCompilationUnit();
          TypeResolverVisitor visitor = new TypeResolverVisitor(library, source, typeProvider);
          ast.accept(visitor);
        }
      }
    } finally {
      timeCounter.stop();
    }
  }

  /**
   * Return an array containing the lexical identifiers associated with the nodes in the given list.
   *
   * @param names the AST nodes representing the identifiers
   * @return the lexical identifiers associated with the nodes in the list
   */
  // TODO(brianwilkerson) Move with buildDirectiveModels().
  private String[] getIdentifiers(NodeList<SimpleIdentifier> names) {
    int count = names.size();
    String[] identifiers = new String[count];
    for (int i = 0; i < count; i++) {
      identifiers[i] = names.get(i).getName();
    }
    return identifiers;
  }

  /**
   * Compute a value for all of the constants in the libraries being analyzed.
   */
  private void performConstantEvaluation() {
    TimeCounterHandle timeCounter = PerformanceStatistics.resolve.start();
    try {
      ConstantValueComputer computer = new ConstantValueComputer(
          typeProvider,
          analysisContext.getDeclaredVariables());
      for (ResolvableLibrary library : librariesInCycle) {
        for (ResolvableCompilationUnit unit : library.getResolvableCompilationUnits()) {
          CompilationUnit ast = unit.getCompilationUnit();
          if (ast != null) {
            computer.add(ast);
          }
        }
      }
      computer.computeValues();
    } finally {
      timeCounter.stop();
    }
  }

  /**
   * Resolve the identifiers and perform type analysis in the libraries in the current cycle.
   *
   * @throws AnalysisException if any of the identifiers could not be resolved or if any of the
   *           libraries could not have their types analyzed
   */
  private void resolveReferencesAndTypes() throws AnalysisException {
    for (ResolvableLibrary library : librariesInCycle) {
      resolveReferencesAndTypesInLibrary(library);
    }
  }

  /**
   * Resolve the identifiers and perform type analysis in the given library.
   *
   * @param library the library to be resolved
   * @throws AnalysisException if any of the identifiers could not be resolved or if the types in
   *           the library cannot be analyzed
   */
  private void resolveReferencesAndTypesInLibrary(ResolvableLibrary library)
      throws AnalysisException {
    TimeCounterHandle timeCounter = PerformanceStatistics.resolve.start();
    try {
      for (ResolvableCompilationUnit unit : library.getResolvableCompilationUnits()) {
        Source source = unit.getSource();
        CompilationUnit ast = unit.getCompilationUnit();
        ast.accept(new VariableResolverVisitor(library, source, typeProvider));
        ResolverVisitor visitor = new ResolverVisitor(library, source, typeProvider);
        ast.accept(visitor);
      }
    } finally {
      timeCounter.stop();
    }
    // Angular
    timeCounter = PerformanceStatistics.angular.start();
    try {
      for (ResolvableCompilationUnit unit : library.getResolvableCompilationUnits()) {
        Source source = unit.getSource();
        CompilationUnit ast = unit.getCompilationUnit();
        new AngularCompilationUnitBuilder(errorListener, source, ast).build();
      }
    } finally {
      timeCounter.stop();
    }
    // Polymer
    timeCounter = PerformanceStatistics.polymer.start();
    try {
      for (Source source : library.getCompilationUnitSources()) {
        CompilationUnit ast = library.getAST(source);
        new PolymerCompilationUnitBuilder(ast).build();
      }
    } finally {
      timeCounter.stop();
    }
  }
}
TOP

Related Classes of com.google.dart.engine.internal.resolver.LibraryResolver2

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.