blob: a46aa61d2adf7ecc38df285d5f3c834c8a4def46 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.resolver;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
import com.google.dart.compiler.DartCompilerContext;
import com.google.dart.compiler.ErrorCode;
import com.google.dart.compiler.ast.ASTVisitor;
import com.google.dart.compiler.ast.DartBlock;
import com.google.dart.compiler.ast.DartClass;
import com.google.dart.compiler.ast.DartExpression;
import com.google.dart.compiler.ast.DartField;
import com.google.dart.compiler.ast.DartFieldDefinition;
import com.google.dart.compiler.ast.DartFunction;
import com.google.dart.compiler.ast.DartFunctionTypeAlias;
import com.google.dart.compiler.ast.DartIdentifier;
import com.google.dart.compiler.ast.DartMethodDefinition;
import com.google.dart.compiler.ast.DartNativeBlock;
import com.google.dart.compiler.ast.DartNode;
import com.google.dart.compiler.ast.DartParameter;
import com.google.dart.compiler.ast.DartParameterizedTypeNode;
import com.google.dart.compiler.ast.DartPropertyAccess;
import com.google.dart.compiler.ast.DartThisExpression;
import com.google.dart.compiler.ast.DartUnit;
import com.google.dart.compiler.ast.Modifiers;
import com.google.dart.compiler.common.HasSourceInfo;
import com.google.dart.compiler.common.SourceInfo;
import com.google.dart.compiler.type.Type;
import com.google.dart.compiler.type.Types;
import com.google.dart.compiler.util.apache.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* Builds the method, field and constructor elements of classes and the library in a DartUnit.
*/
public class MemberBuilder {
private ResolutionContext topLevelContext;
private LibraryElement libraryElement;
public void exec(DartUnit unit, DartCompilerContext context, CoreTypeProvider typeProvider) {
Scope scope = unit.getLibrary().getElement().getScope();
exec(unit, context, scope, typeProvider);
}
@VisibleForTesting
public void exec(DartUnit unit, DartCompilerContext compilerContext, Scope scope,
CoreTypeProvider typeProvider) {
libraryElement = unit.getLibrary().getElement();
topLevelContext = new ResolutionContext(scope, compilerContext, typeProvider);
unit.accept(new MemberElementBuilder(typeProvider));
}
/**
* Creates elements for the fields, methods and constructors of a class. The
* elements are added to the ClassElement.
*
* TODO(ngeoffray): Errors reported:
* - Duplicate member names in the same class.
* - Unresolved types.
*/
private class MemberElementBuilder extends ResolveVisitor {
EnclosingElement currentHolder;
private EnclosingElement enclosingElement;
private ResolutionContext context;
private boolean isStatic;
private boolean isFactory;
MemberElementBuilder(CoreTypeProvider typeProvider) {
super(typeProvider);
context = topLevelContext;
currentHolder = libraryElement;
}
@Override
ResolutionContext getContext() {
return context;
}
@Override
protected EnclosingElement getEnclosingElement() {
return enclosingElement;
}
@Override
public Element visitClass(DartClass node) {
assert !ElementKind.of(currentHolder).equals(ElementKind.CLASS) : "nested class?";
beginClassContext(node);
ClassElement classElement = node.getElement();
EnclosingElement previousEnclosingElement = enclosingElement;
enclosingElement = classElement;
// visit fields, to make their Elements ready for constructor parameters
for (DartNode member : node.getMembers()) {
if (member instanceof DartFieldDefinition) {
member.accept(this);
}
}
// visit all other members
for (DartNode member : node.getMembers()) {
if (!(member instanceof DartFieldDefinition)) {
member.accept(this);
}
}
// check constructor names
for (ConstructorElement constructor : classElement.getConstructors()) {
String name = constructor.getName();
SourceInfo nameLocation = constructor.getNameLocation();
// should be name of immediately enclosing class
if (constructor.getModifiers().isFactory()) {
String rawName = constructor.getRawName();
String consClassName = StringUtils.substringBefore(rawName, ".");
String consUserName = StringUtils.substringAfter(rawName, ".");
if (!StringUtils.equals(consClassName, classElement.getName())) {
// report error for for M part of M.id or pure M
SourceInfo consClassLocation = new SourceInfo(nameLocation.getSource(),
nameLocation.getOffset(), consClassName.length());
resolutionError(consClassLocation,
ResolverErrorCode.CONSTRUCTOR_NAME_NOT_ENCLOSING_CLASS);
// in addition also report warning for whole constructor name
if (!StringUtils.isEmpty(consUserName)) {
resolutionError(nameLocation,
ResolverErrorCode.CONSTRUCTOR_NAME_NOT_ENCLOSING_CLASS_ID);
}
}
}
// should not conflict with member names
{
Element member = classElement.lookupLocalElement(name);
if (member != null) {
resolutionError(nameLocation,
ResolverErrorCode.CONSTRUCTOR_WITH_NAME_OF_MEMBER);
}
}
}
// done with this class
enclosingElement = previousEnclosingElement;
endClassContext();
return null;
}
private void checkParameterInitializer(DartMethodDefinition method, DartParameter parameter) {
if (Elements.isNonFactoryConstructor(method.getElement())) {
if (method.getModifiers().isRedirectedConstructor()) {
resolutionError(parameter.getName(),
ResolverErrorCode.PARAMETER_INIT_WITH_REDIR_CONSTRUCTOR);
}
FieldElement element =
Elements.lookupLocalField((ClassElement) currentHolder, parameter.getParameterName());
if (element == null) {
resolutionError(parameter, ResolverErrorCode.PARAMETER_NOT_MATCH_FIELD,
parameter.getName());
} else if (element.isStatic()) {
resolutionError(parameter,
ResolverErrorCode.PARAMETER_INIT_STATIC_FIELD,
parameter.getName());
}
// Field parameters are not visible as parameters, so we do not declare them
// in the context. Instead we record the resolved field element.
Elements.setParameterInitializerElement(parameter.getElement(), element);
// The editor expects the referenced elements to be non-null
DartPropertyAccess prop = (DartPropertyAccess)parameter.getName();
prop.setElement(element);
prop.getName().setElement(element);
// If no type specified, use type of field.
if (parameter.getTypeNode() == null && element != null) {
Elements.setType(parameter.getElement(), element.getType());
}
} else {
resolutionError(parameter.getName(),
ResolverErrorCode.PARAMETER_INIT_OUTSIDE_CONSTRUCTOR);
}
}
@Override
public Element visitFunctionTypeAlias(DartFunctionTypeAlias node) {
isStatic = false;
isFactory = false;
assert !ElementKind.of(currentHolder).equals(ElementKind.CLASS) : "nested class?";
FunctionAliasElement element = node.getElement();
currentHolder = element;
context = context.extend((ClassElement) currentHolder); // Put type variables in scope.
visit(node.getTypeParameters());
List<VariableElement> parameters = new ArrayList<VariableElement>();
for (DartParameter parameter : node.getParameters()) {
parameters.add((VariableElement) parameter.accept(this));
}
Type returnType = resolveType(node.getReturnTypeNode(), false, false, true,
TypeErrorCode.NO_SUCH_TYPE, TypeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS);
ClassElement functionElement = getTypeProvider().getFunctionType().getElement();
element.setFunctionType(Types.makeFunctionType(getContext(), functionElement,
parameters, returnType));
currentHolder = libraryElement;
context = topLevelContext;
return null;
}
@Override
public Element visitMethodDefinition(final DartMethodDefinition method) {
isFactory = method.getModifiers().isFactory();
isStatic = method.getModifiers().isStatic() || isFactory;
MethodNodeElement element = method.getElement();
if (element == null) {
switch (getMethodKind(method)) {
case NONE:
case CONSTRUCTOR:
element = buildConstructor(method);
checkConstructor(element, method);
addConstructor((ClassElement) currentHolder, (ConstructorNodeElement) element);
break;
case METHOD:
element = Elements.methodFromMethodNode(method, currentHolder);
addMethod(currentHolder, element);
break;
}
} else {
// This is a top-level element, and an element was already created in
// TopLevelElementBuilder.
Elements.addMethod(currentHolder, element);
assertTopLevel(method);
}
if (element != null) {
checkTopLevelMainFunction(method);
checkModifiers(element, method);
recordElement(method, element);
recordElement(method.getName(), element);
ResolutionContext previous = context;
context = context.extend(element.getName());
EnclosingElement previousEnclosingElement = enclosingElement;
enclosingElement = element;
resolveFunction(method.getFunction(), element);
enclosingElement = previousEnclosingElement;
context = previous;
}
return null;
}
@Override
protected void resolveFunctionWithParameters(DartFunction node, MethodElement element) {
super.resolveFunctionWithParameters(node, element);
// Bind "formal initializers" to fields.
if (node.getParent() instanceof DartMethodDefinition) {
DartMethodDefinition method = (DartMethodDefinition) node.getParent();
for (DartParameter parameter : node.getParameters()) {
if (parameter.getQualifier() instanceof DartThisExpression) {
checkParameterInitializer(method, parameter);
}
}
}
}
@Override
public Element visitFieldDefinition(DartFieldDefinition node) {
isStatic = false;
isFactory = false;
for (DartField fieldNode : node.getFields()) {
if (fieldNode.getModifiers().isStatic()) {
isStatic = true;
}
}
Type type = resolveType(node.getTypeNode(), isStatic, false, true, TypeErrorCode.NO_SUCH_TYPE,
TypeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS);
for (DartField fieldNode : node.getFields()) {
if (fieldNode.getModifiers().isAbstractField()) {
buildAbstractField(fieldNode);
} else {
buildField(fieldNode, type);
}
}
return null;
}
private void beginClassContext(final DartClass node) {
assert !ElementKind.of(currentHolder).equals(ElementKind.CLASS) : "nested class?";
currentHolder = node.getElement();
context = context.extend((ClassElement) currentHolder);
}
private void endClassContext() {
currentHolder = libraryElement;
context = topLevelContext;
}
private Element resolveConstructorName(final DartMethodDefinition method) {
return method.getName().accept(new ASTVisitor<Element>() {
@Override
public Element visitPropertyAccess(DartPropertyAccess node) {
Element element = context.resolveName(node);
if (ElementKind.of(element) == ElementKind.CLASS) {
return resolveType(node);
} else {
element = node.getQualifier().accept(this);
recordElement(node.getQualifier(), element);
}
if (ElementKind.of(element) == ElementKind.CLASS) {
return Elements.constructorFromMethodNode(
method, node.getPropertyName(), (ClassElement) currentHolder, (ClassElement) element);
} else {
// Nothing else is valid. Already warned in getMethodKind().
return getTypeProvider().getDynamicType().getElement();
}
}
@Override
public Element visitIdentifier(DartIdentifier node) {
return resolveType(node);
}
private Element resolveType(DartNode node) {
return context.resolveType(
node,
node,
null,
true,
false,
false,
ResolverErrorCode.NO_SUCH_TYPE_CONSTRUCTOR,
ResolverErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS).getElement();
}
@Override
public Element visitParameterizedTypeNode(DartParameterizedTypeNode node) {
Element element = node.getExpression().accept(this);
if (ElementKind.of(element).equals(ElementKind.CONSTRUCTOR)) {
recordElement(node.getExpression(), currentHolder);
} else {
recordElement(node.getExpression(), element);
}
return element;
}
@Override
public Element visitNode(DartNode node) {
throw new RuntimeException("Unexpected node " + node);
}
});
}
private MethodNodeElement buildConstructor(final DartMethodDefinition method) {
// Resolve the constructor's name and class name.
Element e = resolveConstructorName(method);
switch (ElementKind.of(e)) {
default:
// Report an error and create a fake constructor element below.
resolutionError(method.getName(), ResolverErrorCode.INVALID_TYPE_NAME_IN_CONSTRUCTOR);
break;
case DYNAMIC:
case CLASS:
break;
case CONSTRUCTOR:
return (ConstructorNodeElement) e;
}
// If the constructor name resolves to a class or there was an error,
// create the unnamed constructor.
return Elements.constructorFromMethodNode(method, "", (ClassElement) currentHolder,
(ClassElement) e);
}
private FieldElement buildField(DartField fieldNode, Type type) {
assert !fieldNode.getModifiers().isAbstractField();
Modifiers modifiers = fieldNode.getModifiers();
// top-level fields are implicitly static.
if (context == topLevelContext) {
modifiers = modifiers.makeStatic();
}
if (fieldNode.getValue() != null) {
modifiers = modifiers.makeInitialized();
}
FieldNodeElement fieldElement = fieldNode.getElement();
if (fieldElement == null) {
fieldElement = Elements.fieldFromNode(fieldNode, currentHolder, fieldNode.getObsoleteMetadata(),
modifiers);
addField(currentHolder, fieldElement);
} else {
// This is a top-level element, and an element was already created in
// TopLevelElementBuilder.
Elements.addField(currentHolder, fieldElement);
assertTopLevel(fieldNode);
}
fieldElement.setType(type);
recordElement(fieldNode.getName(), fieldElement);
return recordElement(fieldNode, fieldElement);
}
private void assertTopLevel(DartNode node) throws AssertionError {
if (!currentHolder.getKind().equals(ElementKind.LIBRARY)) {
throw topLevelContext.internalError(node, "expected top-level node");
}
}
/**
* Creates FieldElement for AST getters and setters.
*
* class A {
* int get foo() { ... }
* set foo(x) { ... }
* }
*
* The AST will have the shape (simplified):
* DartClass
* members
* DartFieldDefinition
* DartField
* + name: foo
* + modifiers: abstractfield
* + accessor: int get foo() { ... }
* DartFieldDefinition
* DartField
* + name: foo
* + modifiers: abstractfield
* + accessor: set foo(x) { ... }
*
* MemberBuilder will reduce to one class element as below (simplified):
* ClassElement
* members:
* FieldElement
* + name: foo
* + getter:
* MethodElement
* + name: foo
* + function: int get foo() { ... }
* + setter:
* MethodElement
* + name: foo
* + function: set foo(x) { ... }
*
*/
private FieldElement buildAbstractField(DartField fieldNode) {
assert fieldNode.getModifiers().isAbstractField();
boolean topLevelDefinition = fieldNode.getParent().getParent() instanceof DartUnit;
DartMethodDefinition accessorNode = fieldNode.getAccessor();
MethodNodeElement accessorElement = Elements.methodFromMethodNode(accessorNode, currentHolder);
EnclosingElement previousEnclosingElement = enclosingElement;
enclosingElement = accessorElement;
recordElement(accessorNode, accessorElement);
resolveFunction(accessorNode.getFunction(), accessorElement);
enclosingElement = previousEnclosingElement;
String name = fieldNode.getName().getName();
Element element = null;
if (currentHolder != null) {
element = currentHolder.lookupLocalElement(name);
if (element == null) {
element = currentHolder.lookupLocalElement("setter " + name);
}
} else {
// Top level nodes are not handled gracefully
Scope scope = topLevelContext.getScope();
LibraryElement library = context.getScope().getLibrary();
element = scope.findElement(library, name);
if (element == null) {
element = scope.findElement(library, "setter " + name);
}
}
FieldElementImplementation fieldElement = null;
if (element == null || element.getKind().equals(ElementKind.FIELD)
&& element.getModifiers().isAbstractField()) {
fieldElement = (FieldElementImplementation) element;
}
if (accessorNode.getModifiers().isGetter() && fieldElement != null && fieldElement.getSetter() != null) {
MethodNodeElement oldSetter = fieldElement.getSetter();
fieldElement = Elements.fieldFromNode(fieldNode, currentHolder, fieldNode.getObsoleteMetadata(),
fieldNode.getModifiers());
fieldElement.setSetter(oldSetter);
addField(currentHolder, fieldElement);
}
if (fieldElement == null) {
fieldElement = Elements.fieldFromNode(fieldNode, currentHolder, fieldNode.getObsoleteMetadata(),
fieldNode.getModifiers());
addField(currentHolder, fieldElement);
}
if (accessorNode.getModifiers().isGetter()) {
if (fieldElement.getGetter() != null) {
if (!topLevelDefinition) {
reportDuplicateDeclaration(ResolverErrorCode.DUPLICATE_MEMBER, fieldElement.getGetter());
reportDuplicateDeclaration(ResolverErrorCode.DUPLICATE_MEMBER, accessorElement);
}
} else {
fieldElement.setGetter(accessorElement);
fieldElement.setType(accessorElement.getReturnType());
}
} else if (accessorNode.getModifiers().isSetter()) {
if (fieldElement.getSetter() != null) {
if (!topLevelDefinition) {
reportDuplicateDeclaration(ResolverErrorCode.DUPLICATE_MEMBER, fieldElement.getSetter());
reportDuplicateDeclaration(ResolverErrorCode.DUPLICATE_MEMBER, accessorElement);
}
} else {
fieldElement.setSetter(accessorElement);
List<VariableElement> parameters = accessorElement.getParameters();
Type type;
if (parameters.size() == 0) {
// Error flagged in parser
type = getTypeProvider().getDynamicType();
} else {
type = parameters.get(0).getType();
}
fieldElement.setType(type);
}
}
recordElement(fieldNode.getName(), accessorElement);
return recordElement(fieldNode, fieldElement);
}
private void addField(EnclosingElement holder, FieldNodeElement element) {
if (holder != null) {
checkUniqueName(holder, element);
checkMemberNameNotSameAsEnclosingClassName(holder, element);
Elements.addField(holder, element);
}
}
private void addMethod(EnclosingElement holder, MethodNodeElement element) {
checkUniqueName(holder, element);
checkMemberNameNotSameAsEnclosingClassName(holder, element);
Elements.addMethod(holder, element);
}
private void addConstructor(ClassElement cls, ConstructorNodeElement element) {
checkUniqueName(cls, element);
Elements.addConstructor(cls, element);
}
private ElementKind getMethodKind(DartMethodDefinition method) {
if (!ElementKind.of(currentHolder).equals(ElementKind.CLASS)) {
return ElementKind.METHOD;
}
if (method.getModifiers().isFactory()) {
return ElementKind.CONSTRUCTOR;
}
DartExpression name = method.getName();
if (name instanceof DartIdentifier) {
if (((DartIdentifier) name).getName().equals(currentHolder.getName())) {
return ElementKind.CONSTRUCTOR;
} else {
return ElementKind.METHOD;
}
} else {
DartPropertyAccess property = (DartPropertyAccess) name;
if (property.getQualifier() instanceof DartIdentifier) {
DartIdentifier qualifier = (DartIdentifier) property.getQualifier();
if (qualifier.getName().equals(currentHolder.getName())) {
return ElementKind.CONSTRUCTOR;
}
resolutionError(method.getName(),
ResolverErrorCode.CANNOT_DECLARE_NON_FACTORY_CONSTRUCTOR);
} else if (property.getQualifier() instanceof DartParameterizedTypeNode) {
DartParameterizedTypeNode paramNode = (DartParameterizedTypeNode)property.getQualifier();
if (paramNode.getExpression() instanceof DartIdentifier) {
return ElementKind.CONSTRUCTOR;
}
resolutionError(method.getName(),
ResolverErrorCode.TOO_MANY_QUALIFIERS_FOR_METHOD);
} else {
// Multiple qualifiers (Foo.bar.baz)
resolutionError(method.getName(),
ResolverErrorCode.TOO_MANY_QUALIFIERS_FOR_METHOD);
}
}
return ElementKind.NONE;
}
/**
* Checks that top-level "main()" has no parameters.
*/
private void checkTopLevelMainFunction(DartMethodDefinition method) {
if (!method.getFunction().getParameters().isEmpty()
&& currentHolder instanceof LibraryElement
&& Objects.equal(method.getName().toString(), "main")) {
resolutionError(method.getName(), ResolverErrorCode.MAIN_FUNCTION_PARAMETERS);
}
}
private void checkModifiers(MethodElement element, DartMethodDefinition method) {
Modifiers modifiers = method.getModifiers();
boolean isNonFactoryConstructor = Elements.isNonFactoryConstructor(element);
// TODO(ngeoffray): The errors should report the position of the modifier.
if (isNonFactoryConstructor) {
if (modifiers.isStatic()) {
resolutionError(method.getName(), ResolverErrorCode.CONSTRUCTOR_CANNOT_BE_STATIC);
}
if (modifiers.isAbstract()) {
resolutionError(method.getName(), ResolverErrorCode.CONSTRUCTOR_CANNOT_BE_ABSTRACT);
}
if (modifiers.isConstant()) {
// Allow const ... native ... ; type of constructors. Used in core libraries.
DartBlock dartBlock = method.getFunction().getBody();
if (dartBlock != null && !(dartBlock instanceof DartNativeBlock)) {
resolutionError(method.getName(),
ResolverErrorCode.CONST_CONSTRUCTOR_CANNOT_HAVE_BODY);
}
}
}
if (modifiers.isFactory()) {
if (modifiers.isConstant()) {
// Allow const factory ... native ... ; type of constructors, used in core libraries.
// Allow const factory redirecting.
DartBlock dartBlock = method.getFunction().getBody();
if (!(dartBlock instanceof DartNativeBlock || method.getRedirectedTypeName() != null)) {
resolutionError(method.getName(), ResolverErrorCode.FACTORY_CANNOT_BE_CONST);
}
}
}
// TODO(ngeoffray): Add more checks on the modifiers. For
// example const and missing body.
}
private void checkConstructor(MethodElement element, DartMethodDefinition method) {
if (Elements.isNonFactoryConstructor(element) && method.getFunction() != null
&& method.getFunction().getReturnTypeNode() != null) {
resolutionError(method.getFunction().getReturnTypeNode(),
ResolverErrorCode.CONSTRUCTOR_CANNOT_HAVE_RETURN_TYPE);
}
}
private void checkMemberNameNotSameAsEnclosingClassName(EnclosingElement holder, Element e) {
if (ElementKind.of(holder) == ElementKind.CLASS) {
if (Objects.equal(holder.getName(), e.getName())) {
resolutionError(e.getNameLocation(), ResolverErrorCode.MEMBER_WITH_NAME_OF_CLASS);
}
}
}
private void checkUniqueName(EnclosingElement holder, Element e) {
if (ElementKind.of(holder) == ElementKind.LIBRARY) {
return;
}
Element other = lookupElementByName(holder, e.getName(), e.getModifiers());
assert e != other : "forgot to call checkUniqueName() before adding to the class?";
if (other == null && e instanceof FieldElement) {
FieldElement eField = (FieldElement) e;
if (!eField.getModifiers().isAbstractField()) {
other = lookupElementByName(holder, "setter " + e.getName(), e.getModifiers());
}
if (eField.getModifiers().isAbstractField()
&& StringUtils.startsWith(e.getName(), "setter ")) {
Element other2 = lookupElementByName(holder,
StringUtils.removeStart(e.getName(), "setter "), e.getModifiers());
if (other2 instanceof FieldElement) {
FieldElement otherField = (FieldElement) other2;
if (!otherField.getModifiers().isAbstractField()) {
other = otherField;
}
}
}
}
if (other != null) {
ElementKind eKind = ElementKind.of(e);
ElementKind oKind = ElementKind.of(other);
// Constructors have a separate namespace.
boolean oIsConstructor = oKind.equals(ElementKind.CONSTRUCTOR);
boolean eIsConstructor = eKind.equals(ElementKind.CONSTRUCTOR);
if (oIsConstructor != eIsConstructor) {
return;
}
// Both can be constructors, as long as they're for different classes.
if (oIsConstructor && eIsConstructor) {
if (((ConstructorElement) e).getConstructorType() !=
((ConstructorElement) other).getConstructorType()) {
return;
}
}
boolean eIsOperator = e.getModifiers().isOperator();
boolean oIsOperator = other.getModifiers().isOperator();
if (oIsOperator != eIsOperator) {
return;
}
// Operators and methods can share the same name.
boolean oIsMethod = oKind.equals(ElementKind.METHOD);
boolean eIsMethod = eKind.equals(ElementKind.METHOD);
if ((oIsOperator && eIsMethod) || (oIsMethod && eIsOperator)) {
return;
}
// Report initial declaration and current declaration.
reportDuplicateDeclaration(ResolverErrorCode.DUPLICATE_MEMBER, other);
reportDuplicateDeclaration(ResolverErrorCode.DUPLICATE_MEMBER, e);
}
}
private Element lookupElementByName(EnclosingElement holder, String name, Modifiers modifiers) {
Element element = holder.lookupLocalElement(name);
if (element == null && ElementKind.of(holder).equals(ElementKind.CLASS)) {
ClassElement cls = (ClassElement) holder;
String ctorName = name.equals(holder.getName()) ? "" : name;
for (Element e : cls.getConstructors()) {
if (e.getName().equals(ctorName)) {
return e;
}
}
}
return element;
}
void resolutionError(HasSourceInfo node, ErrorCode errorCode, Object... arguments) {
resolutionError(node.getSourceInfo(), errorCode, arguments);
}
void resolutionError(SourceInfo sourceInfo, ErrorCode errorCode, Object... arguments) {
topLevelContext.onError(sourceInfo, errorCode, arguments);
}
/**
* Reports duplicate declaration for given named element.
*/
private void reportDuplicateDeclaration(ErrorCode errorCode, Element element) {
String name =
element instanceof MethodElement
? Elements.getRawMethodName((MethodElement) element)
: element.getName();
resolutionError(element.getNameLocation(), errorCode, name);
}
}
}