blob: 3a59eff93e467a661b7a112c0c6d960878c008f4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 xored software, Inc.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.internal.javascript.ti;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.dltk.compiler.problem.IProblemCategory;
import org.eclipse.dltk.core.ISourceRange;
import org.eclipse.dltk.javascript.ast.Argument;
import org.eclipse.dltk.javascript.ast.BinaryOperation;
import org.eclipse.dltk.javascript.ast.Comment;
import org.eclipse.dltk.javascript.ast.Expression;
import org.eclipse.dltk.javascript.ast.FunctionStatement;
import org.eclipse.dltk.javascript.ast.Identifier;
import org.eclipse.dltk.javascript.ast.Keyword;
import org.eclipse.dltk.javascript.ast.PropertyExpression;
import org.eclipse.dltk.javascript.ast.PropertyInitializer;
import org.eclipse.dltk.javascript.ast.VariableDeclaration;
import org.eclipse.dltk.javascript.parser.PropertyExpressionUtils;
import org.eclipse.dltk.javascript.typeinference.ReferenceLocation;
import org.eclipse.dltk.javascript.typeinfo.IModelBuilder.IMethod;
import org.eclipse.dltk.javascript.typeinfo.IModelBuilder.IParameter;
import org.eclipse.dltk.javascript.typeinfo.ReferenceSource;
import org.eclipse.dltk.javascript.typeinfo.model.JSType;
import org.eclipse.dltk.javascript.typeinfo.model.ParameterKind;
import org.eclipse.dltk.javascript.typeinfo.model.Visibility;
@SuppressWarnings("serial")
public class JSMethod extends ArrayList<IParameter> implements IMethod {
private String name;
private JSType type;
private boolean deprecated;
private Visibility visibility;
private boolean constructor;
private ReferenceLocation location = ReferenceLocation.UNKNOWN;
private ISourceRange docRange;
private JSType thisType;
private JSType extendsType;
public IParameter createParameter() {
return new Parameter();
}
public String getName() {
return name;
}
public List<IParameter> getParameters() {
return this;
}
public int getParameterCount() {
return size();
}
public IParameter getParameter(String name) {
if (name != null) {
for (IParameter parameter : this) {
if (name.equals(parameter.getName())) {
return parameter;
}
}
}
return null;
}
public JSType getType() {
return type;
}
public void setName(String name) {
this.name = name;
}
public void setType(JSType type) {
this.type = type;
}
public ReferenceLocation getLocation() {
return location;
}
public void setLocation(ReferenceLocation location) {
this.location = location;
}
public boolean isDeprecated() {
return deprecated;
}
public void setDeprecated(boolean deprecated) {
this.deprecated = deprecated;
}
public Visibility getVisibility() {
return visibility;
}
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
public boolean isConstructor() {
return constructor;
}
public void setConstructor(boolean constructor) {
this.constructor = constructor;
}
public ISourceRange getDocRange() {
return docRange;
}
public void setDocRange(ISourceRange docRange) {
this.docRange = docRange;
}
public JSType getThisType() {
return this.thisType;
}
public void setThisType(JSType thisType) {
this.thisType = thisType;
}
public JSType getExtendsType() {
return this.extendsType;
}
public void setExtendsType(JSType extendsType) {
this.extendsType = extendsType;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name);
sb.append('(');
boolean first = true;
if (thisType != null) {
sb.append("this:").append(thisType);
first = false;
}
for (IParameter parameter : this) {
if (!first) {
sb.append(',');
}
first = false;
sb.append(parameter);
}
sb.append(')');
if (type != null) {
sb.append(':').append(type);
}
return sb.toString();
}
public JSMethod() {
super(4);
}
/**
* @param node
* @param source
* @return
*/
public JSMethod(FunctionStatement node, ReferenceSource source) {
super(node.getArguments().size());
Identifier nameNode = node.getName();
if (nameNode == null && node.getParent() instanceof BinaryOperation) {
Expression left = ((BinaryOperation) node.getParent())
.getLeftExpression();
if (left instanceof PropertyExpression) {
Expression property = ((PropertyExpression) left).getProperty();
if (property instanceof Identifier)
nameNode = (Identifier) property;
}
}
initialize(node, source, nameNode);
}
public JSMethod(FunctionStatement node, ReferenceSource source,
Expression name) {
super(node.getArguments().size());
initialize(node, source, name);
}
protected void initialize(FunctionStatement node, ReferenceSource source,
Expression methodName) {
if (methodName != null) {
setName(PropertyExpressionUtils.nameOf(methodName));
setLocation(ReferenceLocation.create(source, node.sourceStart(),
node.sourceEnd(), methodName.sourceStart(),
methodName.sourceEnd()));
} else {
final Keyword kw = node.getFunctionKeyword();
setLocation(ReferenceLocation.create(source, node.sourceStart(),
node.sourceEnd(), kw.sourceStart(), kw.sourceEnd()));
Expression expression = null;
if (node.getParent() instanceof BinaryOperation) {
expression = ((BinaryOperation) node.getParent())
.getLeftExpression();
while (expression != null
&& !(expression instanceof Identifier)) {
if (expression instanceof PropertyExpression) {
expression = ((PropertyExpression) expression)
.getProperty();
} else
expression = null;
}
} else if (node.getParent() instanceof PropertyInitializer) {
expression = ((PropertyInitializer) node.getParent()).getName();
} else if (node.getParent() instanceof VariableDeclaration) {
expression = ((VariableDeclaration) node.getParent())
.getIdentifier();
}
if (expression instanceof Identifier) {
setName(((Identifier) expression).getName());
} else {
setName("<anonymous>");
}
}
for (Argument argument : node.getArguments()) {
final IParameter parameter = createParameter();
parameter.setName(argument.getIdentifier().getName());
parameter.setLocation(ReferenceLocation.create(source,
argument.sourceStart(), argument.sourceEnd()));
getParameters().add(parameter);
}
final Comment documentation = JSDocSupport.getComment(node);
if (documentation != null) {
setDocRange(documentation.getRange());
}
}
private Set<IProblemCategory> suppressedWarnings = null;
public Set<IProblemCategory> getSuppressedWarnings() {
return suppressedWarnings != null ? suppressedWarnings : Collections
.<IProblemCategory> emptySet();
}
public void addSuppressedWarning(IProblemCategory warningCategoryId) {
if (suppressedWarnings == null) {
suppressedWarnings = new HashSet<IProblemCategory>();
}
suppressedWarnings.add(warningCategoryId);
}
public static class Parameter extends JSElement implements IParameter {
private ParameterKind kind = ParameterKind.NORMAL;
public boolean isOptional() {
return kind == ParameterKind.OPTIONAL;
}
public boolean isVarargs() {
return kind == ParameterKind.VARARGS;
}
public ParameterKind getKind() {
return kind;
}
public void setKind(ParameterKind kind) {
this.kind = kind;
}
@Override
public String toString() {
return getType() != null ? getName() + ':' + getType().getName()
: getName();
}
}
}