Package com.google.dart.engine.internal.scope

Source Code of com.google.dart.engine.internal.scope.LibraryImportScope

/*
* Copyright (c) 2012, 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.scope;

import com.google.dart.engine.AnalysisEngine;
import com.google.dart.engine.ast.Identifier;
import com.google.dart.engine.element.Element;
import com.google.dart.engine.element.ImportElement;
import com.google.dart.engine.element.LibraryElement;
import com.google.dart.engine.error.AnalysisError;
import com.google.dart.engine.error.AnalysisErrorListener;
import com.google.dart.engine.error.StaticWarningCode;
import com.google.dart.engine.internal.element.MultiplyDefinedElementImpl;
import com.google.dart.engine.utilities.general.StringUtilities;

import java.util.ArrayList;
import java.util.Arrays;

/**
* Instances of the class {@code LibraryImportScope} represent the scope containing all of the names
* available from imported libraries.
*
* @coverage dart.engine.resolver
*/
public class LibraryImportScope extends Scope {
  /**
   * The element representing the library in which this scope is enclosed.
   */
  private LibraryElement definingLibrary;

  /**
   * The listener that is to be informed when an error is encountered.
   */
  private AnalysisErrorListener errorListener;

  /**
   * A list of the namespaces representing the names that are available in this scope from imported
   * libraries.
   */
  private Namespace[] importedNamespaces;

  /**
   * Initialize a newly created scope representing the names imported into the given library.
   *
   * @param definingLibrary the element representing the library that imports the names defined in
   *          this scope
   * @param errorListener the listener that is to be informed when an error is encountered
   */
  public LibraryImportScope(LibraryElement definingLibrary, AnalysisErrorListener errorListener) {
    this.definingLibrary = definingLibrary;
    this.errorListener = errorListener;
    createImportedNamespaces();
  }

  @Override
  public void define(Element element) {
    if (!isPrivateName(element.getDisplayName())) {
      super.define(element);
    }
  }

  @Override
  public AnalysisErrorListener getErrorListener() {
    return errorListener;
  }

  @Override
  protected Element internalLookup(Identifier identifier, String name,
      LibraryElement referencingLibrary) {
    Element foundElement = localLookup(name, referencingLibrary);
    if (foundElement != null) {
      return foundElement;
    }
    for (int i = 0; i < importedNamespaces.length; i++) {
      Namespace nameSpace = importedNamespaces[i];
      Element element = nameSpace.get(name);
      if (element != null) {
        if (foundElement == null) {
          foundElement = element;
        } else if (foundElement != element) {
          foundElement = MultiplyDefinedElementImpl.fromElements(
              definingLibrary.getContext(),
              foundElement,
              element);
        }
      }
    }
    if (foundElement instanceof MultiplyDefinedElementImpl) {
      foundElement = removeSdkElements(identifier, name, (MultiplyDefinedElementImpl) foundElement);
    }
    if (foundElement instanceof MultiplyDefinedElementImpl) {
      String foundEltName = foundElement.getDisplayName();
      Element[] conflictingMembers = ((MultiplyDefinedElementImpl) foundElement).getConflictingElements();
      int count = conflictingMembers.length;
      String[] libraryNames = new String[count];
      for (int i = 0; i < count; i++) {
        libraryNames[i] = getLibraryName(conflictingMembers[i]);
      }
      Arrays.sort(libraryNames);
      errorListener.onError(new AnalysisError(
          getSource(identifier),
          identifier.getOffset(),
          identifier.getLength(),
          StaticWarningCode.AMBIGUOUS_IMPORT,
          foundEltName,
          StringUtilities.printListOfQuotedNames(libraryNames)));
      return foundElement;
    }
    if (foundElement != null) {
      defineNameWithoutChecking(name, foundElement);
    }
    return foundElement;
  }

  /**
   * Create all of the namespaces associated with the libraries imported into this library. The
   * names are not added to this scope, but are stored for later reference.
   *
   * @param definingLibrary the element representing the library that imports the libraries for
   *          which namespaces will be created
   */
  private final void createImportedNamespaces() {
    NamespaceBuilder builder = new NamespaceBuilder();
    ImportElement[] imports = definingLibrary.getImports();
    int count = imports.length;
    importedNamespaces = new Namespace[count];
    for (int i = 0; i < count; i++) {
      importedNamespaces[i] = builder.createImportNamespaceForDirective(imports[i]);
    }
  }

  /**
   * Returns the name of the library that defines given element.
   *
   * @param element the element to get library name
   * @return the name of the library that defines given element
   */
  private String getLibraryName(Element element) {
    if (element == null) {
      return StringUtilities.EMPTY;
    }
    LibraryElement library = element.getLibrary();
    if (library == null) {
      return StringUtilities.EMPTY;
    }
    ImportElement[] imports = definingLibrary.getImports();
    int count = imports.length;
    for (int i = 0; i < count; i++) {
      if (imports[i].getImportedLibrary() == library) {
        return library.getDefiningCompilationUnit().getDisplayName();
      }
    }
    ArrayList<String> indirectSources = new ArrayList<String>();
    for (int i = 0; i < count; i++) {
      LibraryElement importedLibrary = imports[i].getImportedLibrary();
      for (LibraryElement exportedLibrary : importedLibrary.getExportedLibraries()) {
        if (exportedLibrary == library) {
          indirectSources.add(importedLibrary.getDefiningCompilationUnit().getDisplayName());
        }
      }
    }
    int indirectCount = indirectSources.size();
    StringBuilder builder = new StringBuilder();
    builder.append(library.getDefiningCompilationUnit().getDisplayName());
    if (indirectCount > 0) {
      builder.append(" (via ");
      if (indirectCount > 1) {
        String[] indirectNames = indirectSources.toArray(new String[indirectCount]);
        Arrays.sort(indirectNames);
        builder.append(StringUtilities.printListOfQuotedNames(indirectNames));
      } else {
        builder.append(indirectSources.get(0));
      }
      builder.append(")");
    }
    return builder.toString();
  }

  /**
   * Given a collection of elements that a single name could all be mapped to, remove from the list
   * all of the names defined in the SDK. Return the element(s) that remain.
   *
   * @param identifier the identifier node to lookup element for, used to report correct kind of a
   *          problem and associate problem with
   * @param name the name associated with the element
   * @param foundElement the element encapsulating the collection of elements
   * @return all of the elements that are not defined in the SDK
   */
  private Element removeSdkElements(Identifier identifier, String name,
      MultiplyDefinedElementImpl foundElement) {
    Element[] conflictingMembers = foundElement.getConflictingElements();
    int length = conflictingMembers.length;
    int to = 0;
    Element sdkElement = null;
    for (Element member : conflictingMembers) {
      if (member.getLibrary().isInSdk()) {
        sdkElement = member;
      } else {
        conflictingMembers[to++] = member;
      }
    }
    if (sdkElement != null && to > 0) {
      String sdkLibName = getLibraryName(sdkElement);
      String otherLibName = getLibraryName(conflictingMembers[0]);
      errorListener.onError(new AnalysisError(
          getSource(identifier),
          identifier.getOffset(),
          identifier.getLength(),
          StaticWarningCode.CONFLICTING_DART_IMPORT,
          name,
          sdkLibName,
          otherLibName));
    }
    if (to == length) {
      // None of the members were removed
      return foundElement;
    } else if (to == 1) {
      // All but one member was removed
      return conflictingMembers[0];
    } else if (to == 0) {
      // All members were removed
      AnalysisEngine.getInstance().getLogger().logInformation(
          "Multiply defined SDK element: " + foundElement);
      return foundElement;
    }
    Element[] remaining = new Element[to];
    System.arraycopy(conflictingMembers, 0, remaining, 0, to);
    return new MultiplyDefinedElementImpl(definingLibrary.getContext(), remaining);
  }
}
TOP

Related Classes of com.google.dart.engine.internal.scope.LibraryImportScope

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.