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

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

/*
* 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.AstNode;
import com.google.dart.engine.ast.CatchClause;
import com.google.dart.engine.ast.ClassDeclaration;
import com.google.dart.engine.ast.ClassMember;
import com.google.dart.engine.ast.ClassTypeAlias;
import com.google.dart.engine.ast.CompilationUnit;
import com.google.dart.engine.ast.ConstructorDeclaration;
import com.google.dart.engine.ast.DeclaredIdentifier;
import com.google.dart.engine.ast.DefaultFormalParameter;
import com.google.dart.engine.ast.EnumConstantDeclaration;
import com.google.dart.engine.ast.EnumDeclaration;
import com.google.dart.engine.ast.ExportDirective;
import com.google.dart.engine.ast.Expression;
import com.google.dart.engine.ast.FieldFormalParameter;
import com.google.dart.engine.ast.FormalParameter;
import com.google.dart.engine.ast.FunctionDeclaration;
import com.google.dart.engine.ast.FunctionExpression;
import com.google.dart.engine.ast.FunctionTypeAlias;
import com.google.dart.engine.ast.FunctionTypedFormalParameter;
import com.google.dart.engine.ast.ImportDirective;
import com.google.dart.engine.ast.Label;
import com.google.dart.engine.ast.LabeledStatement;
import com.google.dart.engine.ast.MethodDeclaration;
import com.google.dart.engine.ast.PartDirective;
import com.google.dart.engine.ast.SimpleFormalParameter;
import com.google.dart.engine.ast.SimpleIdentifier;
import com.google.dart.engine.ast.StringInterpolation;
import com.google.dart.engine.ast.StringLiteral;
import com.google.dart.engine.ast.SwitchCase;
import com.google.dart.engine.ast.SwitchDefault;
import com.google.dart.engine.ast.TypeParameter;
import com.google.dart.engine.ast.VariableDeclaration;
import com.google.dart.engine.ast.visitor.RecursiveAstVisitor;
import com.google.dart.engine.element.ClassElement;
import com.google.dart.engine.element.CompilationUnitElement;
import com.google.dart.engine.element.ConstructorElement;
import com.google.dart.engine.element.Element;
import com.google.dart.engine.element.ExecutableElement;
import com.google.dart.engine.element.ExportElement;
import com.google.dart.engine.element.FieldElement;
import com.google.dart.engine.element.FunctionElement;
import com.google.dart.engine.element.FunctionTypeAliasElement;
import com.google.dart.engine.element.ImportElement;
import com.google.dart.engine.element.LabelElement;
import com.google.dart.engine.element.LibraryElement;
import com.google.dart.engine.element.LocalVariableElement;
import com.google.dart.engine.element.ParameterElement;
import com.google.dart.engine.element.PrefixElement;
import com.google.dart.engine.element.PropertyAccessorElement;
import com.google.dart.engine.element.TypeParameterElement;
import com.google.dart.engine.element.VariableElement;
import com.google.dart.engine.element.visitor.GeneralizingElementVisitor;
import com.google.dart.engine.scanner.Keyword;
import com.google.dart.engine.scanner.KeywordToken;
import com.google.dart.engine.scanner.Token;
import com.google.dart.engine.scanner.TokenType;
import com.google.dart.engine.source.Source;

import java.util.HashSet;

/**
* Instances of the class {@code DeclarationMatcher} determine whether the element model defined by
* a given AST structure matches an existing element model.
*/
public class DeclarationMatcher extends RecursiveAstVisitor<Void> {
  /**
   * Instances of the class {@code DeclarationMismatchException} represent an exception that is
   * thrown when the element model defined by a given AST structure does not match an existing
   * element model.
   */
  private static class DeclarationMismatchException extends RuntimeException {
    public DeclarationMismatchException() {
      super();
    }
  }

  /**
   * The compilation unit containing the AST nodes being visited.
   */
  private CompilationUnitElement enclosingUnit;

  /**
   * The function type alias containing the AST nodes being visited, or {@code null} if we are not
   * in the scope of a function type alias.
   */
  private FunctionTypeAliasElement enclosingAlias;

  /**
   * The class containing the AST nodes being visited, or {@code null} if we are not in the scope of
   * a class.
   */
  private ClassElement enclosingClass;

  /**
   * The method or function containing the AST nodes being visited, or {@code null} if we are not in
   * the scope of a method or function.
   */
  private ExecutableElement enclosingExecutable;

  /**
   * The parameter containing the AST nodes being visited, or {@code null} if we are not in the
   * scope of a parameter.
   */
  private ParameterElement enclosingParameter;

  /**
   * A set containing all of the elements in the element model that were defined by the old AST node
   * corresponding to the AST node being visited.
   */
  private HashSet<Element> allElements = new HashSet<Element>();

  /**
   * A set containing all of the elements in the element model that were defined by the old AST node
   * corresponding to the AST node being visited that have not already been matched to nodes in the
   * AST structure being visited.
   */
  private HashSet<Element> unmatchedElements = new HashSet<Element>();

  /**
   * Initialize a newly created visitor.
   */
  public DeclarationMatcher() {
    super();
  }

  /**
   * Return {@code true} if the declarations within the given AST structure define an element model
   * that is equivalent to the corresponding elements rooted at the given element.
   *
   * @param node the AST structure being compared to the element model
   * @param element the root of the element model being compared to the AST structure
   * @return {@code true} if the AST structure defines the same elements as those in the given
   *         element model
   */
  public boolean matches(AstNode node, Element element) {
    captureEnclosingElements(element);
    gatherElements(element);
    try {
      node.accept(this);
    } catch (DeclarationMismatchException exception) {
      return false;
    }
    return unmatchedElements.isEmpty();
  }

  @Override
  public Void visitCatchClause(CatchClause node) {
    SimpleIdentifier exceptionParameter = node.getExceptionParameter();
    if (exceptionParameter != null) {
      LocalVariableElement[] localVariables = enclosingExecutable.getLocalVariables();
      LocalVariableElement exceptionElement = findIdentifier(localVariables, exceptionParameter);
      processElement(exceptionElement);

      SimpleIdentifier stackTraceParameter = node.getStackTraceParameter();
      if (stackTraceParameter != null) {
        LocalVariableElement stackTraceElement = findIdentifier(localVariables, stackTraceParameter);
        processElement(stackTraceElement);
      }
    }
    return super.visitCatchClause(node);
  }

  @Override
  public Void visitClassDeclaration(ClassDeclaration node) {
    ClassElement outerClass = enclosingClass;
    try {
      SimpleIdentifier className = node.getName();
      enclosingClass = findIdentifier(enclosingUnit.getTypes(), className);
      processElement(enclosingClass);
      if (!hasConstructor(node)) {
        ConstructorElement constructor = enclosingClass.getUnnamedConstructor();
        if (constructor.isSynthetic()) {
          processElement(constructor);
        }
      }
      return super.visitClassDeclaration(node);
    } finally {
      enclosingClass = outerClass;
    }
  }

  @Override
  public Void visitClassTypeAlias(ClassTypeAlias node) {
    ClassElement outerClass = enclosingClass;
    try {
      SimpleIdentifier className = node.getName();
      enclosingClass = findIdentifier(enclosingUnit.getTypes(), className);
      processElement(enclosingClass);
      return super.visitClassTypeAlias(node);
    } finally {
      enclosingClass = outerClass;
    }
  }

  @Override
  public Void visitCompilationUnit(CompilationUnit node) {
    processElement(enclosingUnit);
    return super.visitCompilationUnit(node);
  }

  @Override
  public Void visitConstructorDeclaration(ConstructorDeclaration node) {
    ExecutableElement outerExecutable = enclosingExecutable;
    try {
      SimpleIdentifier constructorName = node.getName();
      if (constructorName == null) {
        enclosingExecutable = enclosingClass.getUnnamedConstructor();
      } else {
        enclosingExecutable = enclosingClass.getNamedConstructor(constructorName.getName());
      }
      processElement(enclosingExecutable);
      return super.visitConstructorDeclaration(node);
    } finally {
      enclosingExecutable = outerExecutable;
    }
  }

  @Override
  public Void visitDeclaredIdentifier(DeclaredIdentifier node) {
    SimpleIdentifier variableName = node.getIdentifier();
    LocalVariableElement element = findIdentifier(
        enclosingExecutable.getLocalVariables(),
        variableName);
    processElement(element);
    return super.visitDeclaredIdentifier(node);
  }

  @Override
  public Void visitDefaultFormalParameter(DefaultFormalParameter node) {
    SimpleIdentifier parameterName = node.getParameter().getIdentifier();
    ParameterElement element = getElementForParameter(node, parameterName);
    Expression defaultValue = node.getDefaultValue();
    if (defaultValue != null) {
      ExecutableElement outerExecutable = enclosingExecutable;
      try {
        if (element == null) {
          // TODO(brianwilkerson) Report this internal error.
        } else {
          enclosingExecutable = element.getInitializer();
        }
        defaultValue.accept(this);
      } finally {
        enclosingExecutable = outerExecutable;
      }
      processElement(enclosingExecutable);
    }
    ParameterElement outerParameter = enclosingParameter;
    try {
      enclosingParameter = element;
      processElement(enclosingParameter);
      return super.visitDefaultFormalParameter(node);
    } finally {
      enclosingParameter = outerParameter;
    }
  }

  @Override
  public Void visitEnumDeclaration(EnumDeclaration node) {
    ClassElement enclosingEnum = findIdentifier(enclosingUnit.getEnums(), node.getName());
    processElement(enclosingEnum);
    FieldElement[] constants = enclosingEnum.getFields();
    for (EnumConstantDeclaration constant : node.getConstants()) {
      FieldElement constantElement = findIdentifier(constants, constant.getName());
      processElement(constantElement);
    }
    return super.visitEnumDeclaration(node);
  }

  @Override
  public Void visitExportDirective(ExportDirective node) {
    String uri = getStringValue(node.getUri());
    if (uri != null) {
      LibraryElement library = enclosingUnit.getLibrary();
      ExportElement exportElement = findExport(
          library.getExports(),
          enclosingUnit.getContext().getSourceFactory().resolveUri(enclosingUnit.getSource(), uri));
      processElement(exportElement);
    }
    return super.visitExportDirective(node);
  }

  @Override
  public Void visitFieldFormalParameter(FieldFormalParameter node) {
    if (!(node.getParent() instanceof DefaultFormalParameter)) {
      SimpleIdentifier parameterName = node.getIdentifier();
      ParameterElement element = getElementForParameter(node, parameterName);
      ParameterElement outerParameter = enclosingParameter;
      try {
        enclosingParameter = element;
        processElement(enclosingParameter);
        return super.visitFieldFormalParameter(node);
      } finally {
        enclosingParameter = outerParameter;
      }
    } else {
      return super.visitFieldFormalParameter(node);
    }
  }

  @Override
  public Void visitFunctionDeclaration(FunctionDeclaration node) {
    ExecutableElement outerExecutable = enclosingExecutable;
    try {
      SimpleIdentifier functionName = node.getName();
      Token property = node.getPropertyKeyword();
      if (property == null) {
        if (enclosingExecutable != null) {
          enclosingExecutable = findIdentifier(enclosingExecutable.getFunctions(), functionName);
        } else {
          enclosingExecutable = findIdentifier(enclosingUnit.getFunctions(), functionName);
        }
      } else {
        PropertyAccessorElement accessor = findIdentifier(
            enclosingUnit.getAccessors(),
            functionName);
        if (((KeywordToken) property).getKeyword() == Keyword.SET) {
          accessor = accessor.getVariable().getSetter();
        }
        enclosingExecutable = accessor;
      }
      processElement(enclosingExecutable);
      return super.visitFunctionDeclaration(node);
    } finally {
      enclosingExecutable = outerExecutable;
    }
  }

  @Override
  public Void visitFunctionExpression(FunctionExpression node) {
    if (!(node.getParent() instanceof FunctionDeclaration)) {
      FunctionElement element = findAtOffset(
          enclosingExecutable.getFunctions(),
          node.getBeginToken().getOffset());
      processElement(element);
    }
    ExecutableElement outerExecutable = enclosingExecutable;
    try {
      enclosingExecutable = node.getElement();
      processElement(enclosingExecutable);
      return super.visitFunctionExpression(node);
    } finally {
      enclosingExecutable = outerExecutable;
    }
  }

  @Override
  public Void visitFunctionTypeAlias(FunctionTypeAlias node) {
    FunctionTypeAliasElement outerAlias = enclosingAlias;
    try {
      SimpleIdentifier aliasName = node.getName();
      enclosingAlias = findIdentifier(enclosingUnit.getFunctionTypeAliases(), aliasName);
      processElement(enclosingAlias);
      return super.visitFunctionTypeAlias(node);
    } finally {
      enclosingAlias = outerAlias;
    }
  }

  @Override
  public Void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
    if (!(node.getParent() instanceof DefaultFormalParameter)) {
      SimpleIdentifier parameterName = node.getIdentifier();
      ParameterElement element = getElementForParameter(node, parameterName);
      ParameterElement outerParameter = enclosingParameter;
      try {
        enclosingParameter = element;
        processElement(enclosingParameter);
        return super.visitFunctionTypedFormalParameter(node);
      } finally {
        enclosingParameter = outerParameter;
      }
    } else {
      return super.visitFunctionTypedFormalParameter(node);
    }
  }

  @Override
  public Void visitImportDirective(ImportDirective node) {
    String uri = getStringValue(node.getUri());
    if (uri != null) {
      LibraryElement library = enclosingUnit.getLibrary();
      ImportElement importElement = findImport(
          library.getImports(),
          enclosingUnit.getContext().getSourceFactory().resolveUri(enclosingUnit.getSource(), uri),
          node.getPrefix());
      processElement(importElement);
    }
    return super.visitImportDirective(node);
  }

  @Override
  public Void visitLabeledStatement(LabeledStatement node) {
    for (Label label : node.getLabels()) {
      SimpleIdentifier labelName = label.getLabel();
      LabelElement element = findIdentifier(enclosingExecutable.getLabels(), labelName);
      processElement(element);
    }
    return super.visitLabeledStatement(node);
  }

  @Override
  public Void visitMethodDeclaration(MethodDeclaration node) {
    ExecutableElement outerExecutable = enclosingExecutable;
    try {
      Token property = node.getPropertyKeyword();
      SimpleIdentifier methodName = node.getName();
      String nameOfMethod = methodName.getName();
      if (nameOfMethod.equals(TokenType.MINUS.getLexeme())
          && node.getParameters().getParameters().size() == 0) {
        nameOfMethod = "unary-";
      }
      if (property == null) {
        enclosingExecutable = findWithNameAndOffset(
            enclosingClass.getMethods(),
            nameOfMethod,
            methodName.getOffset());
        methodName.setStaticElement(enclosingExecutable);
      } else {
        PropertyAccessorElement accessor = findIdentifier(enclosingClass.getAccessors(), methodName);
        if (((KeywordToken) property).getKeyword() == Keyword.SET) {
          accessor = accessor.getVariable().getSetter();
          methodName.setStaticElement(accessor);
        }
        enclosingExecutable = accessor;
      }
      processElement(enclosingExecutable);
      return super.visitMethodDeclaration(node);
    } finally {
      enclosingExecutable = outerExecutable;
    }
  }

  @Override
  public Void visitPartDirective(PartDirective node) {
    String uri = getStringValue(node.getUri());
    if (uri != null) {
      Source partSource = enclosingUnit.getContext().getSourceFactory().resolveUri(
          enclosingUnit.getSource(),
          uri);
      CompilationUnitElement element = findPart(enclosingUnit.getLibrary().getParts(), partSource);
      processElement(element);
    }
    return super.visitPartDirective(node);
  }

  @Override
  public Void visitSimpleFormalParameter(SimpleFormalParameter node) {
    if (!(node.getParent() instanceof DefaultFormalParameter)) {
      SimpleIdentifier parameterName = node.getIdentifier();
      ParameterElement element = getElementForParameter(node, parameterName);
      ParameterElement outerParameter = enclosingParameter;
      try {
        enclosingParameter = element;
        processElement(enclosingParameter);
        return super.visitSimpleFormalParameter(node);
      } finally {
        enclosingParameter = outerParameter;
      }
    } else {
    }
    return super.visitSimpleFormalParameter(node);
  }

  @Override
  public Void visitSwitchCase(SwitchCase node) {
    for (Label label : node.getLabels()) {
      SimpleIdentifier labelName = label.getLabel();
      LabelElement element = findIdentifier(enclosingExecutable.getLabels(), labelName);
      processElement(element);
    }
    return super.visitSwitchCase(node);
  }

  @Override
  public Void visitSwitchDefault(SwitchDefault node) {
    for (Label label : node.getLabels()) {
      SimpleIdentifier labelName = label.getLabel();
      LabelElement element = findIdentifier(enclosingExecutable.getLabels(), labelName);
      processElement(element);
    }
    return super.visitSwitchDefault(node);
  }

  @Override
  public Void visitTypeParameter(TypeParameter node) {
    SimpleIdentifier parameterName = node.getName();
    TypeParameterElement element = null;
    if (enclosingClass != null) {
      element = findIdentifier(enclosingClass.getTypeParameters(), parameterName);
    } else if (enclosingAlias != null) {
      element = findIdentifier(enclosingAlias.getTypeParameters(), parameterName);
    }
    processElement(element);
    return super.visitTypeParameter(node);
  }

  @Override
  public Void visitVariableDeclaration(VariableDeclaration node) {
    VariableElement element = null;
    SimpleIdentifier variableName = node.getName();
    if (enclosingExecutable != null) {
      element = findIdentifier(enclosingExecutable.getLocalVariables(), variableName);
    }
    if (element == null && enclosingClass != null) {
      element = findIdentifier(enclosingClass.getFields(), variableName);
    }
    if (element == null && enclosingUnit != null) {
      element = findIdentifier(enclosingUnit.getTopLevelVariables(), variableName);
    }
    Expression initializer = node.getInitializer();
    if (initializer != null) {
      ExecutableElement outerExecutable = enclosingExecutable;
      try {
        if (element == null) {
          // TODO(brianwilkerson) Report this internal error.
        } else {
          enclosingExecutable = element.getInitializer();
        }
        processElement(element);
        processElement(enclosingExecutable);
        return super.visitVariableDeclaration(node);
      } finally {
        enclosingExecutable = outerExecutable;
      }
    }
    return super.visitVariableDeclaration(node);
  }

  protected void processElement(Element element) {
    if (element == null) {
      throw new DeclarationMismatchException();
    }
    if (!allElements.contains(element)) {
      throw new DeclarationMismatchException();
    }
    unmatchedElements.remove(element);
  }

  /**
   * Given that the comparison is to begin with the given element, capture the enclosing elements
   * that might be used while performing the comparison.
   *
   * @param element the element corresponding to the AST structure to be compared
   */
  private void captureEnclosingElements(Element element) {
    Element parent = element instanceof CompilationUnitElement ? element
        : element.getEnclosingElement();
    while (parent != null) {
      if (parent instanceof CompilationUnitElement) {
        enclosingUnit = (CompilationUnitElement) parent;
      } else if (parent instanceof ClassElement) {
        if (enclosingClass == null) {
          enclosingClass = (ClassElement) parent;
        }
      } else if (parent instanceof FunctionTypeAliasElement) {
        if (enclosingAlias == null) {
          enclosingAlias = (FunctionTypeAliasElement) parent;
        }
      } else if (parent instanceof ExecutableElement) {
        if (enclosingExecutable == null) {
          enclosingExecutable = (ExecutableElement) parent;
        }
      } else if (parent instanceof ParameterElement) {
        if (enclosingParameter == null) {
          enclosingParameter = (ParameterElement) parent;
        }
      }
      parent = parent.getEnclosingElement();
    }
  }

  /**
   * Return the element in the given array of elements that was created for the declaration at the
   * given offset. This method should only be used when there is no name
   *
   * @param elements the elements of the appropriate kind that exist in the current context
   * @param offset the offset of the name of the element to be returned
   * @return the element at the given offset
   */
  private <E extends Element> E findAtOffset(E[] elements, int offset) {
    return findWithNameAndOffset(elements, "", offset);
  }

  /**
   * Return the export element from the given array whose library has the given source, or
   * {@code null} if there is no such export.
   *
   * @param exports the export elements being searched
   * @param source the source of the library associated with the export element to being searched
   *          for
   * @return the export element whose library has the given source
   */
  private ExportElement findExport(ExportElement[] exports, Source source) {
    for (ExportElement export : exports) {
      if (export.getExportedLibrary().getSource().equals(source)) {
        return export;
      }
    }
    return null;
  }

  /**
   * Return the element in the given array of elements that was created for the declaration with the
   * given name.
   *
   * @param elements the elements of the appropriate kind that exist in the current context
   * @param identifier the name node in the declaration of the element to be returned
   * @return the element created for the declaration with the given name
   */
  private <E extends Element> E findIdentifier(E[] elements, SimpleIdentifier identifier) {
    return findWithNameAndOffset(elements, identifier.getName(), identifier.getOffset());
  }

  /**
   * Return the import element from the given array whose library has the given source and that has
   * the given prefix, or {@code null} if there is no such import.
   *
   * @param imports the import elements being searched
   * @param source the source of the library associated with the import element to being searched
   *          for
   * @param prefix the prefix with which the library was imported
   * @return the import element whose library has the given source and prefix
   */
  private ImportElement findImport(ImportElement[] imports, Source source, SimpleIdentifier prefix) {
    for (ImportElement element : imports) {
      if (element.getImportedLibrary().getSource().equals(source)) {
        PrefixElement prefixElement = element.getPrefix();
        if (prefix == null) {
          if (prefixElement == null) {
            return element;
          }
        } else {
          if (prefixElement != null && prefix.getName().equals(prefixElement.getDisplayName())) {
            return element;
          }
        }
      }
    }
    return null;
  }

  /**
   * Return the element for the part with the given source, or {@code null} if there is no element
   * for the given source.
   *
   * @param parts the elements for the parts
   * @param partSource the source for the part whose element is to be returned
   * @return the element for the part with the given source
   */
  private CompilationUnitElement findPart(CompilationUnitElement[] parts, Source partSource) {
    for (CompilationUnitElement part : parts) {
      if (part.getSource().equals(partSource)) {
        return part;
      }
    }
    return null;
  }

  /**
   * Return the element in the given array of elements that was created for the declaration with the
   * given name at the given offset.
   *
   * @param elements the elements of the appropriate kind that exist in the current context
   * @param name the name of the element to be returned
   * @param offset the offset of the name of the element to be returned
   * @return the element with the given name and offset
   */
  private <E extends Element> E findWithNameAndOffset(E[] elements, String name, int offset) {
    for (E element : elements) {
      if (element.getDisplayName().equals(name) && element.getNameOffset() == offset) {
        return element;
      }
    }
    return null;
  }

  private void gatherElements(Element element) {
    element.accept(new GeneralizingElementVisitor<Void>() {
      @Override
      public Void visitElement(Element element) {
        allElements.add(element);
        unmatchedElements.add(element);
        return super.visitElement(element);
      }
    });
  }

  /**
   * Search the most closely enclosing list of parameters for a parameter with the given name.
   *
   * @param node the node defining the parameter with the given name
   * @param parameterName the name of the parameter being searched for
   * @return the element representing the parameter with that name
   */
  private ParameterElement getElementForParameter(FormalParameter node,
      SimpleIdentifier parameterName) {
    ParameterElement[] parameters = null;
    if (enclosingParameter != null) {
      parameters = enclosingParameter.getParameters();
    }
    if (parameters == null && enclosingExecutable != null) {
      parameters = enclosingExecutable.getParameters();
    }
    if (parameters == null && enclosingAlias != null) {
      parameters = enclosingAlias.getParameters();
    }
    return parameters == null ? null : findIdentifier(parameters, parameterName);
  }

  /**
   * Return the value of the given string literal, or {@code null} if the string is not a constant
   * string without any string interpolation.
   *
   * @param literal the string literal whose value is to be returned
   * @return the value of the given string literal
   */
  private String getStringValue(StringLiteral literal) {
    if (literal instanceof StringInterpolation) {
      return null;
    }
    return literal.getStringValue();
  }

  /**
   * Return {@code true} if the given class defines at least one constructor.
   *
   * @param node the class being tested
   * @return {@code true} if the class defines at least one constructor
   */
  private boolean hasConstructor(ClassDeclaration node) {
    for (ClassMember member : node.getMembers()) {
      if (member instanceof ConstructorDeclaration) {
        return true;
      }
    }
    return false;
  }
}
TOP

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

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.