blob: 66aa87c2c71406d56081082035afdff8ebf8c361 [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.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.dart.compiler.DartSource;
import com.google.dart.compiler.LibrarySource;
import com.google.dart.compiler.Source;
import com.google.dart.compiler.ast.DartClass;
import com.google.dart.compiler.ast.DartClassMember;
import com.google.dart.compiler.ast.DartField;
import com.google.dart.compiler.ast.DartFunctionExpression;
import com.google.dart.compiler.ast.DartFunctionTypeAlias;
import com.google.dart.compiler.ast.DartIdentifier;
import com.google.dart.compiler.ast.DartLabel;
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.DartObsoleteMetadata;
import com.google.dart.compiler.ast.DartParameter;
import com.google.dart.compiler.ast.DartSuperExpression;
import com.google.dart.compiler.ast.DartTypeNode;
import com.google.dart.compiler.ast.DartTypeParameter;
import com.google.dart.compiler.ast.DartVariable;
import com.google.dart.compiler.ast.LibraryUnit;
import com.google.dart.compiler.ast.Modifiers;
import com.google.dart.compiler.common.SourceInfo;
import com.google.dart.compiler.resolver.LabelElement.LabeledStatementType;
import com.google.dart.compiler.type.InterfaceType;
import com.google.dart.compiler.type.InterfaceType.Member;
import com.google.dart.compiler.type.Type;
import com.google.dart.compiler.type.TypeVariable;
import com.google.dart.compiler.util.Paths;
import com.google.dart.compiler.util.apache.StringUtils;
import java.io.File;
import java.net.URI;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* Utility and factory methods for elements.
*/
public class Elements {
private Elements() {} // Prevent subclassing and instantiation.
static void setParameterInitializerElement(VariableElement varElement, FieldElement element) {
((VariableElementImplementation) varElement).setParameterInitializerElement(element);
}
static void setDefaultClass(ClassElement classElement, InterfaceType defaultClass) {
((ClassElementImplementation) classElement).setDefaultClass(defaultClass);
}
static void addInterface(ClassElement classElement, InterfaceType type) {
((ClassElementImplementation) classElement).addInterface(type);
}
static LabelElement statementLabelElement(DartLabel node, String name,
MethodElement enclosingFunction) {
return new LabelElementImplementation(node, name, enclosingFunction,
LabeledStatementType.STATEMENT);
}
static LabelElement switchMemberLabelElement(DartLabel node, String name,
MethodElement enclosingFunction) {
return new LabelElementImplementation(node, name, enclosingFunction,
LabeledStatementType.SWITCH_MEMBER_STATEMENT);
}
static LabelElement switchLabelElement(DartLabel node, String name,
MethodElement enclosingFunction) {
return new LabelElementImplementation(node, name, enclosingFunction,
LabeledStatementType.SWITCH_STATEMENT);
}
public static LibraryElement libraryElement(LibraryUnit libraryUnit) {
return new LibraryElementImplementation(libraryUnit);
}
public static void setLibraryMetadata(LibraryElement element, DartObsoleteMetadata metadata) {
((LibraryElementImplementation) element).setMetadata(metadata);
}
public static Element addExportedElement(LibraryElement libraryElement, Element element) {
return ((LibraryElementImplementation) libraryElement).addExportedElements(element);
}
public static LibraryElement getLibraryElement(Element element) {
while (element != null) {
if (ElementKind.of(element) == ElementKind.LIBRARY) {
return (LibraryElement) element;
}
EnclosingElement enclosingElement = element.getEnclosingElement();
if (enclosingElement == element) {
return null;
}
element = enclosingElement;
};
return null;
}
/**
* @return <code>true</code> if "a" and "b" are declared in the same {@link LibraryElement}.
*/
public static boolean areSameLibrary(Element a, Element b) {
LibraryElement aLibrary = getLibraryElement(a);
LibraryElement bLibrary = getLibraryElement(b);
return Objects.equal(aLibrary, bLibrary);
}
@VisibleForTesting
public static MethodElement methodElement(DartFunctionExpression node, String name) {
return new MethodElementImplementation(node, name, Modifiers.NONE);
}
public static TypeVariableElement typeVariableElement(String name, Type bound) {
return new TypeVariableElementImplementation(name, bound);
}
public static VariableElement variableElement(EnclosingElement owner,
DartVariable node,
String name,
Modifiers modifiers) {
return new VariableElementImplementation(owner,
node,
node.getName().getSourceInfo(),
name,
ElementKind.VARIABLE,
modifiers,
false,
null);
}
public static VariableElement parameterElement(EnclosingElement owner,
DartParameter node,
String name,
Modifiers modifiers) {
return new VariableElementImplementation(owner,
node,
node.getName().getSourceInfo(),
name,
ElementKind.PARAMETER,
modifiers,
node.getModifiers().isNamed(),
node.getDefaultExpr());
}
public static SuperElement superElement(DartSuperExpression node, ClassElement cls) {
return new SuperElementImplementation(node, cls);
}
static void addConstructor(ClassElement cls, ConstructorNodeElement constructor) {
((ClassElementImplementation) cls).addConstructor(constructor);
}
static void addField(EnclosingElement holder, FieldNodeElement field) {
if (ElementKind.of(holder).equals(ElementKind.CLASS)) {
((ClassElementImplementation) holder).addField(field);
} else if (ElementKind.of(holder).equals(ElementKind.LIBRARY)) {
((LibraryElementImplementation) holder).addField(field);
} else {
throw new IllegalArgumentException();
}
}
@VisibleForTesting
public static void addMethod(EnclosingElement holder, MethodNodeElement method) {
if (ElementKind.of(holder).equals(ElementKind.CLASS)) {
((ClassElementImplementation) holder).addMethod(method);
} else if (ElementKind.of(holder).equals(ElementKind.LIBRARY)) {
((LibraryElementImplementation) holder).addMethod(method);
} else {
throw new IllegalArgumentException();
}
}
public static void addParameter(MethodElement method, VariableElement parameter) {
((MethodElementImplementation) method).addParameter(parameter);
}
static Element findElement(EnclosingElement cls, String name) {
if (cls instanceof ClassElementImplementation) {
return ((ClassElementImplementation) cls).findElement(name);
}
return null;
}
public static MethodElement methodFromFunctionExpression(DartFunctionExpression node,
Modifiers modifiers) {
return MethodElementImplementation.fromFunctionExpression(node, modifiers);
}
public static MethodNodeElement methodFromMethodNode(DartMethodDefinition node,
EnclosingElement holder) {
return MethodElementImplementation.fromMethodNode(node, holder);
}
static ConstructorNodeElement constructorFromMethodNode(DartMethodDefinition node,
String name,
ClassElement declaringClass,
ClassElement constructorType) {
return ConstructorElementImplementation.fromMethodNode(node, name, declaringClass,
constructorType);
}
public static void setType(Element element, Type type) {
((AbstractNodeElement) element).setType(type);
}
public static void setOverridden(Element element, Set<Element> overridden) {
if (element instanceof MethodElementImplementation) {
((MethodElementImplementation) element).setOverridden(overridden);
}
if (element instanceof FieldElementImplementation) {
((FieldElementImplementation) element).setOverridden(overridden);
}
}
static FieldElementImplementation fieldFromNode(DartField node,
EnclosingElement holder,
DartObsoleteMetadata metadata,
Modifiers modifiers) {
return FieldElementImplementation.fromNode(node, holder, metadata, modifiers);
}
static ClassElement classFromNode(DartClass node, LibraryElement library) {
return ClassElementImplementation.fromNode(node, library);
}
public static ClassElement classNamed(String name) {
return ClassElementImplementation.named(name);
}
static TypeVariableElement typeVariableFromNode(DartTypeParameter node, EnclosingElement element) {
return TypeVariableElementImplementation.fromNode(node, element);
}
public static DynamicElement dynamicElement() {
return DynamicElementImplementation.getInstance();
}
static ConstructorElement lookupConstructor(ClassElement cls, ClassElement type, String name) {
return ((ClassElementImplementation) cls).lookupConstructor(type, name);
}
static ConstructorElement lookupConstructor(ClassElement cls, String name) {
if (cls instanceof ClassElementImplementation) {
return ((ClassElementImplementation) cls).lookupConstructor(name);
}
return null;
}
public static MethodElement lookupLocalMethod(ClassElement cls, String name) {
return ((ClassElementImplementation) cls).lookupLocalMethod(name);
}
public static FieldElement lookupLocalField(ClassElement cls, String name) {
return ((ClassElementImplementation) cls).lookupLocalField(name);
}
public static FunctionAliasElement functionTypeAliasFromNode(DartFunctionTypeAlias node,
LibraryElement library) {
return FunctionAliasElementImplementation.fromNode(node, library);
}
/**
* @return <code>true</code> if given {@link Element} represents {@link VariableElement} for
* parameter in {@link DartMethodDefinition}.
*/
public static boolean isConstructorParameter(Element element) {
Element parent = element.getEnclosingElement();
if (parent instanceof MethodElement) {
return ((MethodElement) parent).isConstructor();
}
return false;
}
/**
* @return <code>true</code> if given {@link Element} represents {@link VariableElement} for
* parameter in {@link DartMethodDefinition} without body, or with {@link DartNativeBlock}
* as body.
*/
public static boolean isParameterOfMethodWithoutBody(Element element) {
if (element instanceof VariableElement) {
Element parent = element.getEnclosingElement();
if (parent instanceof MethodElement) {
MethodElement parentMethod = (MethodElement) parent;
return !parentMethod.hasBody();
}
}
return false;
}
/**
* @return <code>non-null</code> {@link MethodElement} if "holder", or one of its
* interfaces, or its superclass has {@link FieldElement} with getter.
*/
public static MethodElement lookupFieldElementGetter(EnclosingElement holder, String name) {
Element element = holder.lookupLocalElement(name);
if (element instanceof FieldElement) {
FieldElement fieldElement = (FieldElement) element;
MethodElement result = fieldElement.getGetter();
if (result != null) {
return fieldElement.getGetter();
}
}
if (holder instanceof ClassElement) {
ClassElement classHolder = (ClassElement) holder;
for (InterfaceType interfaceType : classHolder.getInterfaces()) {
MethodElement result = lookupFieldElementGetter(interfaceType.getElement(), name);
if (result != null) {
return result;
}
}
if (classHolder.getSupertype() != null) {
MethodElement result = lookupFieldElementGetter(classHolder.getSupertype().getElement(),
name);
if (result != null) {
return result;
}
}
}
return null;
}
/**
* @return <code>non-null</code> {@link MethodElement} if "holder", or one of its interfaces,
* or its superclass has {@link FieldElement} with setter.
*/
public static MethodElement lookupFieldElementSetter(EnclosingElement holder, String name) {
Element element = holder.lookupLocalElement(name);
if (element instanceof FieldElement) {
FieldElement fieldElement = (FieldElement) element;
MethodElement result = fieldElement.getSetter();
if (result != null) {
return result;
}
}
if (holder instanceof ClassElement) {
ClassElement classHolder = (ClassElement)holder;
for (InterfaceType interfaceType : classHolder.getInterfaces()) {
MethodElement result = lookupFieldElementSetter(interfaceType.getElement(), name);
if (result != null) {
return result;
}
}
if (classHolder.getSupertype() != null) {
MethodElement result = lookupFieldElementSetter(classHolder.getSupertype().getElement(),
name);
if (result != null) {
return result;
}
}
}
return null;
}
/**
* @return <code>true</code> if {@link DartNode} of given {@link Element} if part of static
* {@link DartClassMember} or part of top level declaration.
*/
public static boolean isStaticContext(Element element) {
if (element instanceof ClassElement) {
return true;
}
while (element != null) {
if (element instanceof MethodElement) {
MethodElement methodElement = (MethodElement) element;
return methodElement.isStatic() || methodElement.getEnclosingElement() instanceof LibraryElement;
}
if (element instanceof FieldElement) {
FieldElement fieldElement = (FieldElement) element;
return fieldElement.isStatic()
|| fieldElement.getEnclosingElement() instanceof LibraryElement;
}
if (element instanceof ClassElement) {
return false;
}
element = element.getEnclosingElement();
}
return true;
}
public static boolean isNonFactoryConstructor(Element method) {
return !method.getModifiers().isFactory()
&& ElementKind.of(method) == ElementKind.CONSTRUCTOR;
}
public static boolean isTopLevel(Element element) {
return ElementKind.of(element.getEnclosingElement()) == ElementKind.LIBRARY;
}
static List<TypeVariable> makeTypeVariables(List<DartTypeParameter> parameterNodes,
EnclosingElement enclosingElement) {
if (parameterNodes == null) {
return Arrays.<TypeVariable>asList();
}
TypeVariable[] typeVariables = new TypeVariable[parameterNodes.size()];
int i = 0;
for (DartTypeParameter parameterNode : parameterNodes) {
TypeVariable typeVariable =
Elements.typeVariableFromNode(parameterNode, enclosingElement).getTypeVariable();
typeVariables[i++] = typeVariable;
parameterNode.getName().setElement(typeVariable.getElement());
}
return Arrays.asList(typeVariables);
}
public static Element voidElement() {
return VoidElement.getInstance();
}
/**
* Returns true if the class needs an implicit default constructor.
*/
public static boolean needsImplicitDefaultConstructor(ClassElement classElement) {
return classElement.getConstructors().isEmpty()
&& (!classElement.isInterface() || classElement.getDefaultClass() != null);
}
/**
* @return <code>true</code> if {@link #classElement} implements {@link #interfaceElement}.
*/
public static boolean implementsType(ClassElement classElement, ClassElement interfaceElement) {
try {
for (InterfaceType supertype : classElement.getAllSupertypes()) {
if (supertype.getElement().equals(interfaceElement)) {
return true;
}
}
} catch (Throwable e) {
}
return false;
}
/**
* @return the "name" or "qualifier.name" raw name of {@link DartMethodDefinition} which
* corresponds the given {@link MethodElement}.
*/
public static String getRawMethodName(MethodElement methodElement) {
if (methodElement instanceof ConstructorElement) {
ConstructorElement constructorElement = (ConstructorElement) methodElement;
return constructorElement.getRawName();
}
return methodElement.getName();
}
/**
* @return the number of required (not optional/named) parameters in given {@link MethodElement}.
*/
public static int getNumberOfRequiredParameters(MethodElement method) {
int num = 0;
List<VariableElement> parameters = method.getParameters();
for (VariableElement parameter : parameters) {
if (!parameter.isOptional() && !parameter.isNamed()) {
num++;
}
}
return num;
}
/**
* @return the number of optional positional parameters in given {@link MethodElement}.
*/
public static int getNumberOfOptionalPositionalParameters(MethodElement method) {
int num = 0;
List<VariableElement> parameters = method.getParameters();
for (VariableElement parameter : parameters) {
if (parameter.isOptional()) {
num++;
}
}
return num;
}
/**
* @return the names for named parameters in given {@link MethodElement}.
*/
public static List<String> getNamedParameters(MethodElement method) {
List<String> names = Lists.newArrayList();
List<VariableElement> parameters = method.getParameters();
for (VariableElement parameter : parameters) {
if (parameter.isNamed()) {
names.add(parameter.getName());
}
}
return names;
}
/**
* @return the names for parameters types in given {@link MethodElement}.
*/
public static List<String> getParameterTypeNames(MethodElement method) {
List<String> names = Lists.newArrayList();
List<VariableElement> parameters = method.getParameters();
for (VariableElement parameter : parameters) {
String typeName = parameter.getType().getElement().getName();
names.add(typeName);
}
return names;
}
/**
* Prepares title for {@link TypeErrorCode#DEPRECATED_ELEMENT}.
*/
public static String getDeprecatedElementTitle(Element element) {
String title = getUserElementTitle(element);
return StringUtils.capitalize(title);
}
/**
* @return the user readable title of the given {@link Element}, a little different than
* "technical" title returned from {@link Element#toString()}.
*/
public static String getUserElementTitle(Element element) {
return MessageFormat.format("{0} ''{1}''", getUserElementKindTitle(element), element.getName());
}
/**
* @return the user readable title of the given {@link Element}'s {@link ElementKind}, a little
* different than "technical" title returned from {@link Element#toString()}.
*/
private static String getUserElementKindTitle(Element element) {
ElementKind kind = element.getKind();
switch (kind) {
case CLASS:
if (((ClassElement) element).isInterface()) {
return "interface";
}
break;
case METHOD:
if (isTopLevel(element)) {
return "top-level function";
}
break;
case FIELD:
if (isTopLevel(element)) {
return "top-level variable";
}
break;
}
String title = kind.toString();
title = StringUtils.replace(title, "_", " ");
title = title.toLowerCase();
return title;
}
/**
* @return the {@link String} which contains user-readable description of "target" {@link Element}
* location relative to "source".
*/
public static String getRelativeElementLocation(Element source, Element target) {
// Prepare "target" SourceInfo.
SourceInfo targetInfo;
{
targetInfo = target.getNameLocation();
if (targetInfo == null) {
return "unknown";
}
}
// Prepare path to the target unit from source unit.
String targetPath;
{
SourceInfo sourceInfo = source.getSourceInfo();
targetPath = getRelativeSourcePath(sourceInfo, targetInfo);
}
// Prepare (may be empty) target class name.
String targetClassName;
{
EnclosingElement targetEnclosing = target.getEnclosingElement();
ClassElement targetClass = getEnclosingClassElement(targetEnclosing);
targetClassName = targetClass != null ? targetClass.getName() : "";
}
// Format location string.
if (StringUtils.isEmpty(targetClassName)) {
return MessageFormat.format("{0} line:{1} col:{2}", targetPath, targetInfo.getLine(),
targetInfo.getColumn());
} else {
return MessageFormat.format("{0} class:{1} line:{2} col:{3}", targetPath, targetClassName,
targetInfo.getLine(), targetInfo.getColumn());
}
}
/**
* @return the relative or absolute path from "source" to "target".
*/
private static String getRelativeSourcePath(SourceInfo source, SourceInfo target) {
Source sourceSource = source.getSource();
Source targetSource = target.getSource();
return getRelativeSourcePath(sourceSource, targetSource);
}
/**
* @return the relative or absolute path from "source" to "target".
*/
public static String getRelativeSourcePath(Source sourceSource, Source targetSource) {
// If both source are from file, prepare relative path.
if (sourceSource != null && targetSource != null) {
URI sourceUri = sourceSource.getUri();
URI targetUri = targetSource.getUri();
if (Objects.equal(sourceUri.getScheme(), "file")
&& Objects.equal(targetUri.getScheme(), "file")) {
return Paths.relativePathFor(new File(sourceUri.getPath()), new File(targetUri.getPath()));
}
}
// Else return absolute path (including dart:// protocol).
if (targetSource != null) {
URI targetUri = targetSource.getUri();
return targetUri.toString();
}
// No source for target.
return "<unknown>";
}
/**
* @return the full location of the given {@link Element} - library and unit.
*/
public static String getLibraryUnitLocation(Element element) {
try {
StringBuilder sb = new StringBuilder();
// library URI
String libraryUri;
{
LibraryUnit libraryUnit = getDeclaringLibrary(element).getLibraryUnit();
libraryUri = libraryUnit.getSource().getUri().toString();
sb.append(libraryUri);
}
// unit URI
SourceInfo sourceInfo = element.getSourceInfo();
{
String unitUri = sourceInfo.getSource().getUri().toString();
if (!unitUri.equals(libraryUri)) {
sb.append(" ");
sb.append(unitUri);
}
}
// line
sb.append(":");
sb.append(sourceInfo.getLine());
// done
return sb.toString();
} catch (Throwable e) {
return "<exception>";
}
}
/**
* @return the enclosing {@link ClassElement} (may be same if already given {@link ClassElement}),
* may be <code>null</code> if top level element.
*/
public static ClassElement getEnclosingClassElement(Element element) {
while (element != null) {
if (element instanceof ClassElement) {
return (ClassElement) element;
}
element = element.getEnclosingElement();
}
return null;
}
/**
* @return <code>true</code> if the given {@link DartTypeNode} is type with one of the given
* names.
*/
public static boolean isTypeNode(DartTypeNode typeNode, Set<String> names) {
if (typeNode != null) {
DartNode identifier = typeNode.getIdentifier();
String typeName = getIdentifierName(identifier);
return names.contains(typeName);
}
return false;
}
/**
* @return <code>true</code> if the given {@link DartTypeNode} is type with given name.
*/
public static boolean isTypeNode(DartTypeNode typeNode, String name) {
return typeNode != null && isIdentifierName(typeNode.getIdentifier(), name);
}
/**
* @return <code>true</code> if the given {@link DartNode} is type identifier with given name.
*/
public static boolean isIdentifierName(DartNode identifier, String name) {
String identifierName = getIdentifierName(identifier);
return Objects.equal(identifierName, name);
}
/**
* @return <code>true</code> if the given {@link ConstructorElement} is a synthetic default
* constructor.
*/
public static boolean isSyntheticConstructor(ConstructorElement element) {
return element != null && element.isSynthetic();
}
/**
* @return <code>true</code> if the given {@link ConstructorElement} is a default constructor.
*/
public static boolean isDefaultConstructor(ConstructorElement element) {
return element != null
&& element.getParameters().isEmpty()
&& getRawMethodName(element).equals(element.getEnclosingElement().getName());
}
public static void setRedirectingFactoryConstructor(ConstructorElement source,
ConstructorElement target) {
((ConstructorElementImplementation) source).setRedirectingFactoryConstructor(target);
}
/**
* @return the name of given {@link DartNode} if it is {@link DartIdentifier}, or
* <code>null</code> otherwise.
*/
private static String getIdentifierName(DartNode identifier) {
if (identifier != null && identifier instanceof DartIdentifier) {
return ((DartIdentifier) identifier).getName();
}
return null;
}
/**
* @return <code>true</code> if given {@link Source} represents library with given name.
*/
public static boolean isLibrarySource(Source source, String name) {
LibrarySource library = null;
if (source instanceof LibrarySource) {
library = (LibrarySource) source;
}
if (source instanceof DartSource) {
DartSource dartSource = (DartSource) source;
library = dartSource.getLibrary();
}
if (library != null) {
String libraryName = library.getName();
return libraryName.endsWith(name);
}
return false;
}
/**
* @return <code>true</code> if given {@link Source} represents code library declaration or
* implementation.
*/
public static boolean isCoreLibrarySource(Source source) {
if (source != null && source.getUri() != null
&& source.getUri().toString().equals("libraries.dart")) {
return true;
}
// TODO (danrubel) remove these when dartc libraries are removed
// Old core library file names
return Elements.isLibrarySource(source, "/core/corelib.dart")
|| Elements.isLibrarySource(source, "/core/corelib_impl.dart")
// New core library file names
|| Elements.isLibrarySource(source, "/core/core.dart");
}
public static boolean isCollectionLibrarySource(Source source) {
return Elements.isLibrarySource(source, "/collection/collection.dart");
}
public static boolean isHtmlLibrarySource(Source source) {
return Elements.isLibrarySource(source, "/html/dartium/html_dartium.dart");
}
public static boolean isSourceName(Source source, String requiredName) {
return source.getName().equals(requiredName);
}
/**
* @return the {@link LibraryElement} which declares given {@link Element}.
*/
public static LibraryElement getDeclaringLibrary(Element element) {
while (element != null) {
if (element instanceof LibraryElement) {
return (LibraryElement) element;
}
element = element.getEnclosingElement();
}
return null;
}
/**
* @return <code>true</code> if "element" is accessible in "scopeLibrary".
*/
public static boolean isAccessible(LibraryElement scopeLibrary, Element element) {
if (element != null && StringUtils.startsWith(element.getName(), "_")) {
return Objects.equal(scopeLibrary, getDeclaringLibrary(element));
}
return true;
}
/**
* @return <code>true</code> if given {@link Element} if {@link MethodElement} for
* function "identical".
*/
public static boolean isFunctionIdentical(Element element) {
if (element instanceof MethodElement) {
MethodElement methodElement = (MethodElement) element;
return Objects.equal(methodElement.getName(), "identical")
&& methodElement.getEnclosingElement() instanceof LibraryElement
&& methodElement.getEnclosingElement().getName().equals("dart://core/core.dart");
}
return false;
}
/**
* @return <code>true</code> if normal field or abstract field with getter.
*/
public static boolean isFieldWithGetter(FieldElement fieldElement) {
if (fieldElement.getModifiers().isAbstractField()) {
return fieldElement.getGetter() != null;
}
return true;
}
public static boolean isAbstractFieldWithoutGetter(Element element) {
if (element instanceof FieldElement) {
FieldElement fieldElement = (FieldElement) element;
return fieldElement.getModifiers().isAbstractField() && fieldElement.getGetter() == null;
}
return false;
}
public static boolean hasClassMember(ClassElement clazz, String name) {
if (clazz.lookupLocalElement(name) != null) {
return true;
}
for (InterfaceType interfaceType : clazz.getInterfaces()) {
if (hasClassMember(interfaceType.getElement(), name)) {
return true;
}
}
if (clazz.getSupertype() != null) {
if (hasClassMember(clazz.getSupertype().getElement(), name)) {
return true;
}
}
return false;
}
/**
* @return <code>true</code> if given {@link FieldElement} is explicitly declared static, or is
* static implicitly.
*/
public static boolean isStaticField(FieldElement field) {
Modifiers modifiers = field.getModifiers();
return modifiers.isStatic();
}
/**
* @return <code>true</code> if given {@link InterfaceType} overrides "noSuchMethod".
*/
public static boolean handlesNoSuchMethod(InterfaceType type) {
Member member = type.lookupMember("noSuchMethod");
if (member == null) {
return false;
}
Source source = member.getElement().getSourceInfo().getSource();
return !isCoreLibrarySource(source);
}
public static DuplicateElement createDuplicateElement(Element oldElement, Element newElement) {
return new DuplicateElementImplementation(oldElement, newElement);
}
public static List<Element> getAllMembers(ClassElement classElement) {
List<Element> allMembers = Lists.newArrayList();
Set<ClassElement> visited = Sets.newHashSet();
addAllMembers(visited, allMembers, classElement);
return allMembers;
}
private static void addAllMembers(Set<ClassElement> visited, List<Element> allMembers, ClassElement classElement) {
if (classElement == null) {
return;
}
if (visited.contains(classElement)) {
return;
}
visited.add(classElement);
Iterables.addAll(allMembers, classElement.getMembers());
{
InterfaceType superType = classElement.getSupertype();
if (superType != null)
addAllMembers(visited, allMembers, superType.getElement());
}
for (InterfaceType intf : classElement.getInterfaces()) {
addAllMembers(visited, allMembers, intf.getElement());
}
}
public static boolean isAbstractElement(Element element) {
if (element == null) {
return false;
}
if (element.getModifiers().isAbstract()) {
return true;
}
if (element.getModifiers().isExternal()) {
return false;
}
if (element.getModifiers().isStatic()) {
return false;
}
if (ElementKind.of(element) == ElementKind.METHOD) {
MethodElement method = (MethodElement) element;
return !method.hasBody();
}
if (ElementKind.of(element) == ElementKind.FIELD) {
FieldElement field = (FieldElement) element;
if (isAbstractElement(field.getGetter())) {
return true;
}
if (isAbstractElement(field.getSetter())) {
return true;
}
return false;
}
return false;
}
}