| /******************************************************************************* |
| * Copyright (c) 2000, 2013 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.wst.jsdt.internal.compiler.ast; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.wst.jsdt.core.ast.IASTNode; |
| import org.eclipse.wst.jsdt.core.ast.IAbstractFunctionDeclaration; |
| import org.eclipse.wst.jsdt.core.ast.IArgument; |
| import org.eclipse.wst.jsdt.core.ast.IAssignment; |
| import org.eclipse.wst.jsdt.core.ast.IFunctionDeclaration; |
| import org.eclipse.wst.jsdt.core.ast.IFunctionExpression; |
| import org.eclipse.wst.jsdt.core.ast.IJsDoc; |
| import org.eclipse.wst.jsdt.core.ast.IProgramElement; |
| import org.eclipse.wst.jsdt.core.compiler.CategorizedProblem; |
| import org.eclipse.wst.jsdt.core.infer.InferredMethod; |
| import org.eclipse.wst.jsdt.core.infer.InferredType; |
| import org.eclipse.wst.jsdt.internal.compiler.ASTVisitor; |
| import org.eclipse.wst.jsdt.internal.compiler.CompilationResult; |
| import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.eclipse.wst.jsdt.internal.compiler.flow.FlowContext; |
| import org.eclipse.wst.jsdt.internal.compiler.flow.FlowInfo; |
| import org.eclipse.wst.jsdt.internal.compiler.impl.ReferenceContext; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.Binding; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.BlockScope; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.ExtraCompilerModifiers; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.LocalFunctionBinding; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.LocalVariableBinding; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.MethodBinding; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.MethodScope; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.ProblemBinding; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.ReferenceBinding; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.Scope; |
| import org.eclipse.wst.jsdt.internal.compiler.lookup.SourceTypeBinding; |
| import org.eclipse.wst.jsdt.internal.compiler.parser.Parser; |
| import org.eclipse.wst.jsdt.internal.compiler.problem.AbortCompilation; |
| import org.eclipse.wst.jsdt.internal.compiler.problem.AbortCompilationUnit; |
| import org.eclipse.wst.jsdt.internal.compiler.problem.AbortMethod; |
| import org.eclipse.wst.jsdt.internal.compiler.problem.AbortType; |
| import org.eclipse.wst.jsdt.internal.compiler.problem.ProblemSeverities; |
| |
| |
| public abstract class AbstractMethodDeclaration extends Statement |
| implements IAbstractFunctionDeclaration, ProblemSeverities, ReferenceContext { |
| |
| /** |
| * <p>Current scope used by this declaration.</p> |
| */ |
| private MethodScope fScope; |
| |
| private MethodScope prevScope; |
| |
| /** |
| * <p>The function selector</p> |
| */ |
| public char[] selector; |
| |
| /** |
| * <p><code>true</code> if this function is defined as an anonymous function, |
| * <code>false</code> otherwise.</p> |
| * |
| * <p><b>NOTE:</b> A function could be defend as anonymous but |
| * still have a selector if assigned to a variable.</p> |
| */ |
| private boolean fIsAnonymous; |
| |
| public int declarationSourceStart; |
| public int declarationSourceEnd; |
| public int modifiers; |
| public Argument[] arguments; |
| public Statement[] statements; |
| public int explicitDeclarations; |
| protected MethodBinding binding; |
| public boolean ignoreFurtherInvestigation = false; |
| public boolean needFreeReturn = false; |
| public boolean resolveChildStatments = true; |
| public boolean hasResolvedChildStatements = false; |
| |
| public Javadoc javadoc; |
| |
| public int bodyStart; |
| public int bodyEnd = -1; |
| public CompilationResult compilationResult; |
| |
| public InferredType inferredType; |
| public InferredMethod inferredMethod; |
| |
| public boolean errorInSignature = false; |
| public int exprStackPtr; |
| |
| /** |
| * <p> |
| * <code>true</code> if {@link #buildLocals(BlockScope)} has been called, |
| * <code>false</code> otherwise. |
| * </p> |
| */ |
| private boolean fhasBuiltLocals; |
| |
| /** |
| * <p> |
| * <code>true</code> if {@link #resolve(Scope)} has been called, |
| * <code>false</code> otherwise. |
| * </p> |
| */ |
| private boolean fHasResolved; |
| |
| /** |
| * <p> |
| * {@link IFunctionDeclaration} that this declaration is contained in, |
| * or <code>null</code> if declaration not contained in an {@link IFunctionDeclaration} |
| */ |
| private IFunctionDeclaration fContainingFunction; |
| |
| AbstractMethodDeclaration(CompilationResult compilationResult){ |
| this.compilationResult = compilationResult; |
| this.prevScope = null; |
| |
| this.fhasBuiltLocals = false; |
| this.fHasResolved = false; |
| this.fContainingFunction = null; |
| } |
| |
| public void setArguments( IArgument[] args) { |
| if(args instanceof Argument[]) this.arguments = (Argument[])args; |
| } |
| |
| public IArgument[] getArguments() { |
| return this.arguments; |
| } |
| |
| /* |
| * We cause the compilation task to abort to a given extent. |
| */ |
| public void abort(int abortLevel, CategorizedProblem problem) { |
| |
| switch (abortLevel) { |
| case AbortCompilation : |
| throw new AbortCompilation(this.compilationResult, problem); |
| case AbortCompilationUnit : |
| throw new AbortCompilationUnit(this.compilationResult, problem); |
| case AbortType : |
| throw new AbortType(this.compilationResult, problem); |
| default : |
| throw new AbortMethod(this.compilationResult, problem); |
| } |
| } |
| |
| public FlowInfo analyseCode(BlockScope classScope, FlowContext initializationContext, FlowInfo info) |
| { |
| return this.analyseCode((Scope)classScope, initializationContext, info); |
| } |
| |
| public abstract FlowInfo analyseCode(Scope classScope, FlowContext initializationContext, FlowInfo info); |
| |
| /** |
| * Bind and add argument's binding into the scope of the method |
| */ |
| public void bindArguments() { |
| //only bind arguments if the current scope does not equal the scope last used to bind args |
| if (this.arguments != null && (this.prevScope == null || this.prevScope != this.fScope)) { |
| this.prevScope = this.fScope; |
| |
| if (this.binding == null) { |
| for (int i = 0, length = this.arguments.length; i < length; i++) { |
| this.arguments[i].resolve(this.fScope); |
| } |
| return; |
| } |
| if (this.arguments.length>0 && this.binding.parameters.length==0) // types not set yet |
| { |
| ReferenceBinding declaringClass = this.binding.declaringClass; |
| if (declaringClass instanceof SourceTypeBinding) { |
| SourceTypeBinding binding = (SourceTypeBinding) declaringClass; |
| binding.resolveTypesFor(this.binding,this); |
| } |
| } |
| boolean used = this.binding.isAbstract(); |
| for (int i = 0, length = this.arguments.length; i < length && i < this.binding.parameters.length; i++) { |
| IArgument argument = this.arguments[i]; |
| argument.bind(this.fScope, this.binding.parameters[i], used); |
| } |
| } |
| } |
| |
| public CompilationResult compilationResult() { |
| |
| return this.compilationResult; |
| } |
| |
| public boolean hasErrors() { |
| return this.ignoreFurtherInvestigation; |
| } |
| |
| public boolean isAbstract() { |
| |
| if (this.binding != null) |
| return this.binding.isAbstract(); |
| return (this.modifiers & ClassFileConstants.AccAbstract) != 0; |
| } |
| |
| public boolean isClinit() { |
| |
| return false; |
| } |
| |
| |
| /** |
| * @return If the {@link #inferredMethod} is set then use that to determine if |
| * this declaration is a constructor, else <code>false</code> |
| */ |
| public boolean isConstructor() { |
| boolean isConstructor = false; |
| if(this.inferredMethod != null) { |
| isConstructor = this.inferredMethod.isConstructor; |
| } |
| return isConstructor; |
| } |
| |
| public boolean isDefaultConstructor() { |
| |
| return false; |
| } |
| |
| public boolean isInitializationMethod() { |
| |
| return false; |
| } |
| |
| public boolean isMethod() { |
| |
| return false; |
| } |
| |
| public boolean isStatic() { |
| |
| if (this.binding != null) |
| return this.binding.isStatic(); |
| return (this.modifiers & ClassFileConstants.AccStatic) != 0; |
| } |
| |
| public boolean isInferredJsDocType() { |
| return (this.bits & ASTNode.IsInferredJsDocType) != 0; |
| } |
| |
| /** |
| * Fill up the method body with statement |
| * @param parser |
| * @param unit |
| */ |
| public abstract void parseStatements( |
| Parser parser, |
| CompilationUnitDeclaration unit); |
| |
| public StringBuffer printStatement(int indent, StringBuffer output) |
| { |
| return print(indent,output); |
| } |
| |
| public StringBuffer print(int tab, StringBuffer output) { |
| |
| if (this.javadoc != null) { |
| this.javadoc.print(tab, output); |
| } |
| printIndent(tab, output); |
| |
| output.append("function "); //$NON-NLS-1$ |
| if (this.selector!=null) |
| output.append(this.selector); |
| output.append('('); |
| if (this.arguments != null) { |
| for (int i = 0; i < this.arguments.length; i++) { |
| if (i > 0) output.append(", "); //$NON-NLS-1$ |
| this.arguments[i].print(0, output); |
| } |
| } |
| output.append(')'); |
| printBody(tab + 1, output); |
| return output; |
| } |
| |
| public StringBuffer printBody(int indent, StringBuffer output) { |
| |
| if (isAbstract() || (this.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) |
| return output.append(';'); |
| |
| output.append(" {"); //$NON-NLS-1$ |
| if (this.statements != null) { |
| for (int i = 0; i < this.statements.length; i++) { |
| output.append('\n'); |
| this.statements[i].printStatement(indent, output); |
| } |
| } |
| output.append('\n'); |
| printIndent(indent == 0 ? 0 : indent - 1, output).append('}'); |
| return output; |
| } |
| |
| public StringBuffer printReturnType(int indent, StringBuffer output) { |
| return output; |
| } |
| |
| public void resolve(Scope upperScope) { |
| /* resolve if the scope is not yet set or |
| * the locals were built causing the scope to be set without resolving */ |
| if (this.getScope() == null || this.fhasBuiltLocals) { |
| this.fHasResolved = true; |
| |
| //set the scope if it has not yet been set |
| if(this.getScope() == null) { |
| this.setScope(new MethodScope(upperScope,this, false)); |
| } |
| |
| SourceTypeBinding compilationUnitBinding = upperScope.enclosingCompilationUnit(); |
| if (this.getName()!=null && !this.hasBinding()) { |
| //is local if the upper scope is not a compilation unit scope |
| boolean isLocal = upperScope.kind != Scope.COMPILATION_UNIT_SCOPE; |
| |
| /* if inferred method has declaring binding, use that |
| * else use compilation unit binding */ |
| SourceTypeBinding declaringBinding = null; |
| if(this.getInferredMethod() != null && |
| this.getInferredMethod().inType != null && |
| this.getInferredMethod().inType.binding != null) { |
| |
| declaringBinding = this.getInferredMethod().inType.binding; |
| } else { |
| declaringBinding = compilationUnitBinding; |
| } |
| |
| //create and set the method binding |
| MethodBinding methodBinding = fScope.createMethod(this, |
| this.getName(), declaringBinding, false, isLocal); |
| this.setBinding(methodBinding); |
| } |
| |
| if (this.binding != null) { |
| MethodBinding methodBinding = compilationUnitBinding |
| .resolveTypesFor(this.binding,this); |
| if (methodBinding != null && methodBinding.selector != null) { |
| MethodScope enclosingMethodScope = upperScope.enclosingMethodScope(); |
| if (enclosingMethodScope != null) { |
| enclosingMethodScope.addLocalMethod(methodBinding); |
| } else { |
| compilationUnitBinding.addMethod(methodBinding); |
| upperScope.environment().defaultPackage.addBinding( |
| methodBinding, methodBinding.selector, |
| Binding.METHOD); |
| } |
| } |
| } |
| } |
| |
| if (this.binding == null) { |
| this.ignoreFurtherInvestigation = true; |
| } |
| |
| try { |
| // only need to resolve args, jsdoc, and statments once per function |
| if(resolveChildStatments && !hasResolvedChildStatements) { |
| hasResolvedChildStatements = true; |
| bindArguments(); |
| resolveJavadoc(); |
| resolveStatements(); |
| } |
| } catch (AbortMethod e) { // ========= abort on fatal error ============= |
| this.ignoreFurtherInvestigation = true; |
| } |
| } |
| |
| public void resolveJavadoc() { |
| |
| if (this.binding == null) return; |
| if (this.javadoc != null) { |
| this.javadoc.resolve(this.fScope); |
| return; |
| } |
| if (this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) { |
| this.fScope.problemReporter().javadocMissing(this.sourceStart, this.sourceEnd, this.binding.modifiers); |
| } |
| } |
| |
| // made some changes here to fix https://bugs.eclipse.org/bugs/show_bug.cgi?id=262728 |
| public void resolveStatements() { |
| if (this.statements != null) { |
| List nonFunctions = null; |
| List functions = null; |
| for (int i = 0, length = this.statements.length; i < length; i++) { |
| Statement statement = this.statements[i]; |
| |
| //look for an AbstractMethodDeclaration as part of the statement |
| AbstractMethodDeclaration methodDecl = null; |
| BlockScope scope = this.fScope; |
| if (statement instanceof AbstractMethodDeclaration) { |
| methodDecl = (AbstractMethodDeclaration)statement; |
| |
| //fully process the method declaration later |
| if(functions == null) { |
| functions = new ArrayList(); |
| } |
| functions.add(methodDecl); |
| } |
| if(methodDecl != null) { |
| methodDecl.resolveChildStatments = false; |
| methodDecl.resolve(scope); |
| methodDecl.resolveChildStatments = true; |
| } |
| |
| //if the statement itself was not a method declaration save it to processes after processing all functions |
| if(!(statement instanceof AbstractMethodDeclaration)) { |
| if(nonFunctions == null) { |
| nonFunctions = new ArrayList(); |
| } |
| nonFunctions.add(statements[i]); |
| } |
| } |
| |
| /* resolve all none method declarations, this includes expressions that have a child method declaration, |
| * such as an assignment |
| */ |
| if(nonFunctions != null) { |
| for(int j = 0; j < nonFunctions.size(); j++) { |
| Statement statement = (Statement)nonFunctions.get(j); |
| AbstractMethodDeclaration methodDecl = null; |
| BlockScope scope = this.fScope; |
| if(statement instanceof AbstractVariableDeclaration) { |
| AbstractVariableDeclaration variableDecl = (AbstractVariableDeclaration)statement; |
| if(variableDecl.initialization instanceof IFunctionExpression) { |
| methodDecl = ((IFunctionExpression)variableDecl.initialization).getMethodDeclaration(); |
| } |
| } else if(statement instanceof IAssignment) { |
| IAssignment assignment = (IAssignment)statement; |
| if(assignment.getExpression() instanceof IFunctionExpression) { |
| methodDecl = ((IFunctionExpression)assignment.getExpression()).getMethodDeclaration(); |
| } |
| |
| //if the LHS is an undeclared single name resolve the function at the compilation unit level |
| if(assignment.getLeftHandSide() instanceof SingleNameReference) { |
| SingleNameReference nameRef = (SingleNameReference)assignment.getLeftHandSide(); |
| |
| /* if the binding is a problem binding or not a local function |
| * binding then built with unit scope because it is not a local function */ |
| Binding binding = nameRef.findBinding(this.fScope); |
| if(binding instanceof ProblemBinding || !(binding instanceof LocalFunctionBinding || binding instanceof LocalVariableBinding)) { |
| scope = this.fScope.compilationUnitScope(); |
| } |
| } |
| } |
| if(methodDecl != null) { |
| methodDecl.resolveChildStatments = false; |
| methodDecl.resolve(scope); |
| methodDecl.resolveChildStatments = true; |
| } |
| statement.resolve(this.fScope); |
| } |
| } |
| |
| // now its time to resolve the children statements of the method declarations |
| if(functions != null) { |
| for(int f = 0; f < functions.size(); f++) { |
| ((Statement)functions.get(f)).resolve(this.fScope); |
| } |
| } |
| } else if ((this.bits & UndocumentedEmptyBlock) != 0) { |
| this.fScope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd+1); |
| } |
| } |
| |
| public void tagAsHavingErrors() { |
| this.ignoreFurtherInvestigation = true; |
| } |
| |
| public void traverse( |
| ASTVisitor visitor, |
| Scope classScope) { |
| // default implementation: subclass will define it |
| } |
| |
| public void resolve(BlockScope scope) { |
| this.resolve((Scope)scope); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.wst.jsdt.internal.compiler.ast.ASTNode#isInferred() |
| */ |
| public boolean isInferred() { |
| return this.inferredMethod != null; |
| } |
| |
| public int getASTType() { |
| return IASTNode.ABSTRACT_FUNCTION_DECLARATION; |
| |
| } |
| |
| public IJsDoc getJsDoc() { |
| return this.javadoc; |
| } |
| |
| public IProgramElement[] getStatements() { |
| return this.statements; |
| } |
| |
| /** |
| * <p>Returns this functions selector or inferred selector in that priority |
| * order, or <code>null</code> if neither are defined.</p> |
| * |
| * @see org.eclipse.wst.jsdt.core.ast.IAbstractFunctionDeclaration#getName() |
| */ |
| public char[] getName() { |
| char[] name = null; |
| |
| if(this.selector != null) { |
| name = this.selector; |
| } else if(this.inferredMethod != null && this.inferredMethod.name != null) { |
| name = this.inferredMethod.name; |
| } |
| |
| return name; |
| } |
| |
| public void setInferredType(InferredType type) { |
| this.inferredType=type; |
| } |
| |
| public InferredMethod getInferredMethod() { |
| return this.inferredMethod; |
| } |
| |
| public InferredType getInferredType() { |
| return this.inferredType; |
| } |
| |
| /** |
| * @return {@link MethodBinding} associated with this function declaration |
| */ |
| public MethodBinding getBinding() { |
| return this.binding; |
| } |
| |
| /** |
| * <p>Sets the {@link MethodBinding} associated with this function declaration. |
| * If one is already set then it will be overwritten.</p> |
| * |
| * @param binding {@link MethodBinding} to associate with this function declaration |
| */ |
| public void setBinding(MethodBinding binding) { |
| this.binding = binding; |
| } |
| |
| /** |
| * @return <code>true</code> if a {@link MethodBinding} has already been associated |
| * with this function declaration, <code>false</code> otherwise. |
| */ |
| public boolean hasBinding() { |
| return this.binding != null; |
| } |
| |
| /** |
| * <p>Sets the selector.</p> |
| * |
| * @param selector for this function declaration |
| */ |
| public void setSelector(char[] selector) { |
| this.selector = selector; |
| } |
| |
| /** |
| * <p>Set whether this function declared as anonymous or not.</p> |
| * |
| * <p><b>NOTE:</b> A function could be defend as anonymous but |
| * still have a selector if assigned to a variable.</p> |
| * |
| * @param isAnonymous <code>true</code> if this function is anonymous, |
| * <code>false</code> otherwise |
| */ |
| public void setIsAnonymous(boolean isAnonymous) { |
| this.fIsAnonymous = isAnonymous; |
| } |
| |
| /** |
| * <p><b>NOTE:</b> A function could be defend as anonymous but |
| * still have a selector if assigned to a variable.</p> |
| * |
| * @return <code>true</code> if this function is anonymous, |
| * <code>false</code> otherwise. |
| */ |
| public boolean isAnonymous() { |
| return this.fIsAnonymous || this.getName() == null; |
| } |
| |
| /** |
| * @param scope |
| * {@link MethodScope} to use for this declaration |
| */ |
| public void setScope(MethodScope scope) { |
| this.fScope = scope; |
| } |
| |
| /** |
| * @return {@link MethodScope} used by this declaration, or |
| * <code>null</code> if none is set |
| */ |
| public MethodScope getScope() { |
| return this.fScope; |
| } |
| |
| /** |
| * @param containingFunction {@link IFunctionDeclaration} that contains this declaration |
| */ |
| public void setContainingFunction(IFunctionDeclaration containingFunction) { |
| //declaration can never and should never contain itself |
| if(containingFunction != this) { |
| this.fContainingFunction = containingFunction; |
| } |
| } |
| |
| /** |
| * @return {@link IFunctionDeclaration} that contains this declaration, |
| * or <code>null</code> if this declaration is not contained in an {@link IFunctionDeclaration} |
| */ |
| public IFunctionDeclaration getContainingFunction() { |
| return this.fContainingFunction; |
| } |
| |
| /** |
| * <p> |
| * Finds all of the variables and functions defined in this function |
| * declaration and adds them to this functions scope. |
| * </p> |
| * |
| * <p> |
| * This is much cheaper then {@link #resolve(Scope)} and should be used |
| * whenever possible. |
| * </p> |
| * |
| * <p> |
| * <b>NOTE:</b> This is a no-op if this function has already been invoked |
| * or {@link #resolve(Scope)} has already been invoked. |
| * </p> |
| * |
| * @param givenUpperScope |
| * {@link BlockScope} to use as the upper scope for this |
| * functions scope |
| */ |
| public void buildLocals(Scope givenUpperScope) { |
| //this is not resolving, but there is no point in doing it if already resolved |
| if(!this.fhasBuiltLocals && !this.fHasResolved) { |
| this.fhasBuiltLocals = true; |
| |
| //build the locals all for all of the containing functions |
| Scope upperScope = givenUpperScope; |
| IFunctionDeclaration containingFunc = this.getContainingFunction(); |
| if(containingFunc instanceof AbstractMethodDeclaration) { |
| ((AbstractMethodDeclaration) containingFunc).buildLocals(givenUpperScope); |
| upperScope = ((AbstractMethodDeclaration) containingFunc).getScope(); |
| } |
| |
| //create scope if it has not yet been created |
| if (this.getScope() == null ) { |
| this.setScope(new MethodScope(upperScope, this, false)); |
| } |
| |
| //traverse this functions statements looking for variables and functions |
| this.traverse(new ASTVisitor() { |
| /** |
| * @see org.eclipse.wst.jsdt.internal.compiler.ASTVisitor#visit(org.eclipse.wst.jsdt.internal.compiler.ast.Argument, org.eclipse.wst.jsdt.internal.compiler.lookup.BlockScope) |
| */ |
| public boolean visit(Argument argument, BlockScope scope) { |
| if(scope != null && scope instanceof MethodScope) { |
| ((MethodScope) scope).addUnresolvedLocalVar(argument.getName(), argument); |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @see org.eclipse.wst.jsdt.internal.compiler.ASTVisitor#visit(org.eclipse.wst.jsdt.internal.compiler.ast.LocalDeclaration, org.eclipse.wst.jsdt.internal.compiler.lookup.BlockScope) |
| */ |
| public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) { |
| if(scope != null && scope instanceof MethodScope) { |
| /* be sure to add all variable declarations |
| * |
| * var b, c, d = "foo" */ |
| AbstractVariableDeclaration currVarDecl = localDeclaration; |
| while(currVarDecl != null) { |
| ((MethodScope) scope).addUnresolvedLocalVar(currVarDecl.getName(), currVarDecl); |
| |
| currVarDecl = currVarDecl.nextLocal; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @see org.eclipse.wst.jsdt.internal.compiler.ASTVisitor#visit(org.eclipse.wst.jsdt.internal.compiler.ast.MethodDeclaration, org.eclipse.wst.jsdt.internal.compiler.lookup.Scope) |
| */ |
| public boolean visit(MethodDeclaration methodDeclaration, Scope scope) { |
| boolean isSelf = AbstractMethodDeclaration.this == methodDeclaration; |
| if(scope != null && scope instanceof MethodScope) { |
| if(!isSelf) { |
| ((MethodScope) scope).addUnresolvedLocalFunc(methodDeclaration.getName(), methodDeclaration); |
| } |
| } |
| |
| return isSelf; |
| } |
| }, this.getScope()); |
| } |
| } |
| |
| /** |
| * <p>Given an {@link IProgramElement} returns the {@link AbstractMethodDeclaration} |
| * if there is one in the given element. The element itself could be the method, or |
| * the method could be part of a declaration, assignment, and so on.</p> |
| * |
| * @param element to search for an {@link AbstractMethodDeclaration} |
| * |
| * @return {@link AbstractMethodDeclaration} if the given {@link IProgramElement} contains |
| * one, <code>null</code> otherwise |
| */ |
| public static AbstractMethodDeclaration findMethodDeclaration(IProgramElement element) { |
| AbstractMethodDeclaration methodDecl = null; |
| |
| /* if the statement is a method declaration |
| * else if statement is a variable declaration that could have a function assigned to it |
| * else if the statement is an assignment that could be assigning a function to a variable |
| */ |
| if (element instanceof AbstractMethodDeclaration) { |
| methodDecl = (AbstractMethodDeclaration)element; |
| } else if(element instanceof AbstractVariableDeclaration) { |
| AbstractVariableDeclaration variableDecl = (AbstractVariableDeclaration)element; |
| if(variableDecl.initialization instanceof IFunctionExpression) { |
| methodDecl = ((IFunctionExpression)variableDecl.initialization).getMethodDeclaration(); |
| } |
| } else if(element instanceof IAssignment) { |
| IAssignment assignment = (IAssignment)element; |
| if(assignment.getExpression() instanceof IFunctionExpression) { |
| methodDecl = ((IFunctionExpression)assignment.getExpression()).getMethodDeclaration(); |
| } |
| } else if(element instanceof IFunctionExpression) { |
| methodDecl = ((IFunctionExpression)element).getMethodDeclaration(); |
| } |
| |
| return methodDecl; |
| } |
| } |