public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { // need assertion flag: $assertionsDisabled on outer most source clas // (in case of static member of interface, will use the outermost static member - bug 22334) SourceTypeBinding outerMostClass = currentScope.enclosingSourceType(); while (outerMostClass.isLocalType()) { ReferenceBinding enclosing = outerMostClass.enclosingType(); if (enclosing == null || enclosing.isInterface()) break; outerMostClass = (SourceTypeBinding) enclosing; } this.assertionSyntheticFieldBinding = outerMostClass.addSyntheticFieldForAssert(currentScope); // find <clinit> and enable assertion support TypeDeclaration typeDeclaration = outerMostClass.scope.referenceType(); AbstractMethodDeclaration[] methods = typeDeclaration.methods; for (int i = 0, max = methods.length; i < max; i++) { AbstractMethodDeclaration method = methods[i]; if (method.isClinit()) { ((Clinit) method) .setAssertionSupport( this.assertionSyntheticFieldBinding, currentScope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5); break; } } } }
private TypeBinding getTypeFromSignature(String typeSignature, Scope scope) { TypeBinding assignableTypeBinding = null; TypeVariableBinding[] typeVariables = Binding.NO_TYPE_VARIABLES; ReferenceContext referenceContext = scope.referenceContext(); if (referenceContext instanceof AbstractMethodDeclaration) { AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) referenceContext; TypeParameter[] typeParameters = methodDeclaration.typeParameters(); if (typeParameters != null && typeParameters.length > 0) { int length = typeParameters.length; int count = 0; typeVariables = new TypeVariableBinding[length]; for (int i = 0; i < length; i++) { if (typeParameters[i].binding != null) { typeVariables[count++] = typeParameters[i].binding; } } if (count != length) { System.arraycopy( typeVariables, 0, typeVariables = new TypeVariableBinding[count], 0, count); } } } CompilationUnitDeclaration previousUnitBeingCompleted = this.lookupEnvironment.unitBeingCompleted; this.lookupEnvironment.unitBeingCompleted = this.compilationUnitDeclaration; // {ObjectTeams: protect call into the compiler /* orig: try { :giro */ try (Config config = Dependencies.setup(this, this.parser, this.lookupEnvironment, true, true)) { // orig: SignatureWrapper wrapper = new SignatureWrapper(replacePackagesDot(typeSignature.toCharArray())); // FIXME(stephan): do we interpret type annotations here? assignableTypeBinding = this.lookupEnvironment.getTypeFromTypeSignature( wrapper, typeVariables, this.assistScope.enclosingClassScope().referenceContext.binding, null, ITypeAnnotationWalker.EMPTY_ANNOTATION_WALKER); assignableTypeBinding = BinaryTypeBinding.resolveType(assignableTypeBinding, this.lookupEnvironment, true); } catch (AbortCompilation e) { assignableTypeBinding = null; } finally { this.lookupEnvironment.unitBeingCompleted = previousUnitBeingCompleted; } return assignableTypeBinding; }
@Override public void process(CompilationUnitDeclaration cud, int i) { super.process(cud, i); ClassFile[] classFiles = cud.compilationResult().getClassFiles(); Map<ClassFile, CompiledClass> results = new LinkedHashMap<ClassFile, CompiledClass>(); for (ClassFile classFile : classFiles) { createCompiledClass(classFile, results); } List<CompiledClass> compiledClasses = new ArrayList<CompiledClass>(results.values()); addBinaryTypes(compiledClasses); ICompilationUnit icu = cud.compilationResult().compilationUnit; Adapter adapter = (Adapter) icu; CompilationUnitBuilder builder = adapter.getBuilder(); // TODO this code was added for the arquillian gwt extension if (cud.types != null) { for (TypeDeclaration type : cud.types) { if (type.methods != null) { if (isAnnotationPresent(RunWith.class.getSimpleName(), type.annotations)) { Set<AbstractMethodDeclaration> filteredMethods = new HashSet<AbstractMethodDeclaration>(); boolean match = false; for (AbstractMethodDeclaration decl : type.methods) { if (decl.annotations != null) { // TODO make this configurable if ((isAnnotationPresent(RunAsGwtClient.class.getSimpleName(), decl.annotations) || isAnnotationPresent( RunAsGwtClient.class.getSimpleName(), type.annotations)) && !isAnnotationPresent(Deployment.class.getSimpleName(), decl.annotations)) { filteredMethods.add(decl); } else { match = true; System.out.println("Ignoring non-translatable method:\n" + decl.toString()); } } } if (match) { type.methods = filteredMethods.toArray(new AbstractMethodDeclaration[filteredMethods.size()]); } } } } } processor.process(builder, cud, compiledClasses); }
/** * Find all methods which have the requested name. * * <p>{@code <clinit>} is not supported. * * @param type JDT type declaration * @param name name of methods to find * @return list of matching methods */ private static List<AbstractMethodDeclaration> findNamedMethods( TypeDeclaration type, String name) { List<AbstractMethodDeclaration> matching = new ArrayList<AbstractMethodDeclaration>(); boolean isCtor = "<init>".equals(name); char[] nameArray = name.toCharArray(); for (AbstractMethodDeclaration method : type.methods) { if ((isCtor && method.isConstructor()) || (!isCtor && !method.isConstructor() && !method.isClinit() && Arrays.equals(method.selector, nameArray))) { matching.add(method); } } return matching; }
private static void computeDietRange0(TypeDeclaration[] types, RangeResult result) { for (int j = 0; j < types.length; j++) { // members TypeDeclaration[] memberTypeDeclarations = types[j].memberTypes; if (memberTypeDeclarations != null && memberTypeDeclarations.length > 0) { computeDietRange0(types[j].memberTypes, result); } // methods AbstractMethodDeclaration[] methods = types[j].methods; if (methods != null) { int length = methods.length; for (int i = 0; i < length; i++) { AbstractMethodDeclaration method = methods[i]; if (containsIgnoredBody(method)) { if (containsErrorInSignature(method)) { method.errorInSignature = true; result.addInterval( method.declarationSourceStart, method.declarationSourceEnd, IGNORE); } else { int flags = method.sourceEnd + 1 == method.bodyStart ? LBRACE_MISSING : NO_FLAG; result.addInterval(method.bodyStart, method.bodyEnd, flags); } } } } // initializers FieldDeclaration[] fields = types[j].fields; if (fields != null) { int length = fields.length; for (int i = 0; i < length; i++) { if (fields[i] instanceof Initializer) { Initializer initializer = (Initializer) fields[i]; if (initializer.declarationSourceEnd == initializer.bodyEnd) { initializer.errorInSignature = true; result.addInterval( initializer.declarationSourceStart, initializer.declarationSourceEnd, IGNORE); } else { result.addInterval(initializer.bodyStart, initializer.bodyEnd); } } } } } }
public static boolean containsIgnoredBody(AbstractMethodDeclaration method) { return !method.isDefaultConstructor() && !method.isClinit() && (method.modifiers & CompilerModifiers.AccSemicolonBody) == 0; }
public void checkExceptionHandlers( TypeBinding[] raisedExceptions, ASTNode location, FlowInfo flowInfo, BlockScope scope) { // check that all the argument exception types are handled // JDK Compatible implementation - when an exception type is thrown, // all related catch blocks are marked as reachable... instead of those only // until the point where it is safely handled (Smarter - see comment at the end) int remainingCount; // counting the number of remaining unhandled exceptions int raisedCount; // total number of exceptions raised if ((raisedExceptions == null) || ((raisedCount = raisedExceptions.length) == 0)) return; remainingCount = raisedCount; // duplicate the array of raised exceptions since it will be updated // (null replaces any handled exception) System.arraycopy( raisedExceptions, 0, (raisedExceptions = new TypeBinding[raisedCount]), 0, raisedCount); FlowContext traversedContext = this; ArrayList abruptlyExitedLoops = null; while (traversedContext != null) { SubRoutineStatement sub; if (((sub = traversedContext.subroutine()) != null) && sub.isSubRoutineEscaping()) { // traversing a non-returning subroutine means that all unhandled // exceptions will actually never get sent... return; } // filter exceptions that are locally caught from the innermost enclosing // try statement to the outermost ones. if (traversedContext instanceof ExceptionHandlingFlowContext) { ExceptionHandlingFlowContext exceptionContext = (ExceptionHandlingFlowContext) traversedContext; ReferenceBinding[] caughtExceptions; if ((caughtExceptions = exceptionContext.handledExceptions) != Binding.NO_EXCEPTIONS) { int caughtCount = caughtExceptions.length; boolean[] locallyCaught = new boolean[raisedCount]; // at most for (int caughtIndex = 0; caughtIndex < caughtCount; caughtIndex++) { ReferenceBinding caughtException = caughtExceptions[caughtIndex]; for (int raisedIndex = 0; raisedIndex < raisedCount; raisedIndex++) { TypeBinding raisedException; if ((raisedException = raisedExceptions[raisedIndex]) != null) { FlowInfo exceptionFlow = flowInfo; int state = caughtException == null ? Scope.EQUAL_OR_MORE_SPECIFIC /* any exception */ : Scope.compareTypes(raisedException, caughtException); if (abruptlyExitedLoops != null && caughtException != null && state != Scope.NOT_RELATED) { for (int i = 0, abruptlyExitedLoopsCount = abruptlyExitedLoops.size(); i < abruptlyExitedLoopsCount; i++) { LoopingFlowContext loop = (LoopingFlowContext) abruptlyExitedLoops.get(i); loop.recordCatchContextOfEscapingException( exceptionContext, caughtException, flowInfo); } exceptionFlow = FlowInfo.DEAD_END; // don't use flow info on first round, flow info will be // evaluated during loopback simulation } switch (state) { case Scope.EQUAL_OR_MORE_SPECIFIC: exceptionContext.recordHandlingException( caughtException, exceptionFlow.unconditionalInits(), raisedException, raisedException, // precise exception that will be caught location, locallyCaught[raisedIndex]); // was already definitely caught ? if (!locallyCaught[raisedIndex]) { locallyCaught[raisedIndex] = true; // remember that this exception has been definitely caught remainingCount--; } break; case Scope.MORE_GENERIC: exceptionContext.recordHandlingException( caughtException, exceptionFlow.unconditionalInits(), raisedException, caughtException, location, false); // was not caught already per construction } } } } // remove locally caught exceptions from the remaining ones for (int i = 0; i < raisedCount; i++) { if (locallyCaught[i]) { raisedExceptions[i] = null; // removed from the remaining ones. } } } // method treatment for unchecked exceptions if (exceptionContext.isMethodContext) { for (int i = 0; i < raisedCount; i++) { TypeBinding raisedException; if ((raisedException = raisedExceptions[i]) != null) { if (raisedException.isUncheckedException(false)) { remainingCount--; raisedExceptions[i] = null; } } } boolean shouldMergeUnhandledException = exceptionContext instanceof ExceptionInferenceFlowContext; // anonymous constructors are allowed to throw any exceptions (their thrown exceptions // clause will be fixed up later as per JLS 8.6). if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration) { AbstractMethodDeclaration method = (AbstractMethodDeclaration) exceptionContext.associatedNode; if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()) shouldMergeUnhandledException = true; } if (shouldMergeUnhandledException) { for (int i = 0; i < raisedCount; i++) { TypeBinding raisedException; if ((raisedException = raisedExceptions[i]) != null) { exceptionContext.mergeUnhandledException(raisedException); } } return; // no need to complain, will fix up constructor/lambda exceptions } break; // not handled anywhere, thus jump to error handling } } else if (traversedContext instanceof LoopingFlowContext) { if (abruptlyExitedLoops == null) { abruptlyExitedLoops = new ArrayList(5); } abruptlyExitedLoops.add(traversedContext); } if (remainingCount == 0) return; traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); if (traversedContext instanceof InsideSubRoutineFlowContext) { ASTNode node = traversedContext.associatedNode; if (node instanceof TryStatement) { TryStatement tryStatement = (TryStatement) node; flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits } } traversedContext = traversedContext.getLocalParent(); } // if reaches this point, then there are some remaining unhandled exception types. nextReport: for (int i = 0; i < raisedCount; i++) { TypeBinding exception; if ((exception = raisedExceptions[i]) != null) { // only one complaint if same exception declared to be thrown more than once for (int j = 0; j < i; j++) { if (TypeBinding.equalsEquals(raisedExceptions[j], exception)) continue nextReport; // already reported } scope.problemReporter().unhandledException(exception, location); } } }
/** * @param isExceptionOnAutoClose This is for checking exception handlers for exceptions raised * during the auto close of resources inside a try with resources statement. (Relevant for * source levels 1.7 and above only) */ public void checkExceptionHandlers( TypeBinding raisedException, ASTNode location, FlowInfo flowInfo, BlockScope scope, boolean isExceptionOnAutoClose) { // LIGHT-VERSION OF THE EQUIVALENT WITH AN ARRAY OF EXCEPTIONS // check that all the argument exception types are handled // JDK Compatible implementation - when an exception type is thrown, // all related catch blocks are marked as reachable... instead of those only // until the point where it is safely handled (Smarter - see comment at the end) FlowContext traversedContext = this; ArrayList abruptlyExitedLoops = null; if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_7 && location instanceof ThrowStatement) { Expression throwExpression = ((ThrowStatement) location).exception; LocalVariableBinding throwArgBinding = throwExpression.localVariableBinding(); if (throwExpression instanceof SingleNameReference // https://bugs.eclipse.org/bugs/show_bug.cgi?id=350361 && throwArgBinding instanceof CatchParameterBinding && throwArgBinding.isEffectivelyFinal()) { CatchParameterBinding parameter = (CatchParameterBinding) throwArgBinding; checkExceptionHandlers(parameter.getPreciseTypes(), location, flowInfo, scope); return; } } while (traversedContext != null) { SubRoutineStatement sub; if (((sub = traversedContext.subroutine()) != null) && sub.isSubRoutineEscaping()) { // traversing a non-returning subroutine means that all unhandled // exceptions will actually never get sent... return; } // filter exceptions that are locally caught from the innermost enclosing // try statement to the outermost ones. if (traversedContext instanceof ExceptionHandlingFlowContext) { ExceptionHandlingFlowContext exceptionContext = (ExceptionHandlingFlowContext) traversedContext; ReferenceBinding[] caughtExceptions; if ((caughtExceptions = exceptionContext.handledExceptions) != Binding.NO_EXCEPTIONS) { boolean definitelyCaught = false; for (int caughtIndex = 0, caughtCount = caughtExceptions.length; caughtIndex < caughtCount; caughtIndex++) { ReferenceBinding caughtException = caughtExceptions[caughtIndex]; FlowInfo exceptionFlow = flowInfo; int state = caughtException == null ? Scope.EQUAL_OR_MORE_SPECIFIC /* any exception */ : Scope.compareTypes(raisedException, caughtException); if (abruptlyExitedLoops != null && caughtException != null && state != Scope.NOT_RELATED) { for (int i = 0, abruptlyExitedLoopsCount = abruptlyExitedLoops.size(); i < abruptlyExitedLoopsCount; i++) { LoopingFlowContext loop = (LoopingFlowContext) abruptlyExitedLoops.get(i); loop.recordCatchContextOfEscapingException( exceptionContext, caughtException, flowInfo); } exceptionFlow = FlowInfo .DEAD_END; // don't use flow info on first round, flow info will be evaluated // during loopback simulation } switch (state) { case Scope.EQUAL_OR_MORE_SPECIFIC: exceptionContext.recordHandlingException( caughtException, exceptionFlow.unconditionalInits(), raisedException, raisedException, // precise exception that will be caught location, definitelyCaught); // was it already definitely caught ? definitelyCaught = true; break; case Scope.MORE_GENERIC: exceptionContext.recordHandlingException( caughtException, exceptionFlow.unconditionalInits(), raisedException, caughtException, location, false); // was not caught already per construction } } if (definitelyCaught) return; } // method treatment for unchecked exceptions if (exceptionContext.isMethodContext) { if (raisedException.isUncheckedException(false)) return; boolean shouldMergeUnhandledExceptions = exceptionContext instanceof ExceptionInferenceFlowContext; // anonymous constructors are allowed to throw any exceptions (their thrown exceptions // clause will be fixed up later as per JLS 8.6). if (exceptionContext.associatedNode instanceof AbstractMethodDeclaration) { AbstractMethodDeclaration method = (AbstractMethodDeclaration) exceptionContext.associatedNode; if (method.isConstructor() && method.binding.declaringClass.isAnonymousType()) shouldMergeUnhandledExceptions = true; } if (shouldMergeUnhandledExceptions) { exceptionContext.mergeUnhandledException(raisedException); return; // no need to complain, will fix up constructor/lambda exceptions } break; // not handled anywhere, thus jump to error handling } } else if (traversedContext instanceof LoopingFlowContext) { if (abruptlyExitedLoops == null) { abruptlyExitedLoops = new ArrayList(5); } abruptlyExitedLoops.add(traversedContext); } traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); if (!isExceptionOnAutoClose) { if (traversedContext instanceof InsideSubRoutineFlowContext) { ASTNode node = traversedContext.associatedNode; if (node instanceof TryStatement) { TryStatement tryStatement = (TryStatement) node; flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits } } } traversedContext = traversedContext.getLocalParent(); } // if reaches this point, then there are some remaining unhandled exception types. if (isExceptionOnAutoClose) { scope.problemReporter().unhandledExceptionFromAutoClose(raisedException, location); } else { scope.problemReporter().unhandledException(raisedException, location); } }
/** * For predicates the parser doesn't know if they are static, update the method once we know the * role method is indeed static. Updates declaration, binding and scope for both class- and * interface-part. */ private void makeMethodStatic(AbstractMethodDeclaration method) { method.modifiers |= ClassFileConstants.AccStatic; if (method.binding != null) method.binding.modifiers |= ClassFileConstants.AccStatic; if (method.scope != null) method.scope.isStatic = true; if (method.interfacePartMethod != null) makeMethodStatic(method.interfacePartMethod); }
/* * Update the corresponding parse node from parser state which * is about to disappear because of restarting recovery */ public void updateFromParserState() { // if parent is null then recovery already occured in diet parser. if (this.bodyStartsAtHeaderEnd() && this.parent != null) { Parser parser = this.parser(); /* might want to recover arguments or thrown exceptions */ if (parser.listLength > 0 && parser.astLengthPtr > 0) { // awaiting interface type references /* has consumed the arguments - listed elements must be thrown exceptions */ if (methodDeclaration.sourceEnd == parser.rParenPos) { // protection for bugs 15142 int length = parser.astLengthStack[parser.astLengthPtr]; int astPtr = parser.astPtr - length; boolean canConsume = astPtr >= 0; if (canConsume) { if ((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) { canConsume = false; } for (int i = 1, max = length + 1; i < max; i++) { if (!(parser.astStack[astPtr + i] instanceof TypeReference)) { canConsume = false; } } } if (canConsume) { parser.consumeMethodHeaderThrowsClause(); // will reset typeListLength to zero // thus this check will only be performed on first errorCheck after void foo() throws X, // Y, } else { parser.listLength = 0; } } else { /* has not consumed arguments yet, listed elements must be arguments */ if (parser.currentToken == TokenNameLPAREN || parser.currentToken == TokenNameSEMICOLON) { /* if currentToken is parenthesis this last argument is a method/field signature */ parser.astLengthStack[parser.astLengthPtr]--; parser.astPtr--; parser.listLength--; parser.currentToken = 0; } int argLength = parser.astLengthStack[parser.astLengthPtr]; int argStart = parser.astPtr - argLength + 1; boolean needUpdateRParenPos = parser.rParenPos < parser.lParenPos; // 12387 : rParenPos will be used // remove unfinished annotation nodes MemberValuePair[] memberValuePairs = null; while (argLength > 0 && parser.astStack[parser.astPtr] instanceof MemberValuePair) { System.arraycopy( parser.astStack, argStart, memberValuePairs = new MemberValuePair[argLength], 0, argLength); parser.astLengthPtr--; parser.astPtr -= argLength; argLength = parser.astLengthStack[parser.astLengthPtr]; argStart = parser.astPtr - argLength + 1; needUpdateRParenPos = true; } // to compute bodyStart, and thus used to set next checkpoint. int count; for (count = 0; count < argLength; count++) { ASTNode aNode = parser.astStack[argStart + count]; if (aNode instanceof Argument) { Argument argument = (Argument) aNode; /* cannot be an argument if non final */ char[][] argTypeName = argument.type.getTypeName(); if ((argument.modifiers & ~ClassFileConstants.AccFinal) != 0 || (argTypeName.length == 1 && CharOperation.equals(argTypeName[0], TypeBinding.VOID.sourceName()))) { parser.astLengthStack[parser.astLengthPtr] = count; parser.astPtr = argStart + count - 1; parser.listLength = count; parser.currentToken = 0; break; } if (needUpdateRParenPos) parser.rParenPos = argument.sourceEnd + 1; } else { parser.astLengthStack[parser.astLengthPtr] = count; parser.astPtr = argStart + count - 1; parser.listLength = count; parser.currentToken = 0; break; } } if (parser.listLength > 0 && parser.astLengthPtr > 0) { // protection for bugs 15142 int length = parser.astLengthStack[parser.astLengthPtr]; int astPtr = parser.astPtr - length; boolean canConsume = astPtr >= 0; if (canConsume) { if ((!(parser.astStack[astPtr] instanceof AbstractMethodDeclaration))) { canConsume = false; } for (int i = 1, max = length + 1; i < max; i++) { if (!(parser.astStack[astPtr + i] instanceof Argument)) { canConsume = false; } } } if (canConsume) { parser.consumeMethodHeaderRightParen(); /* fix-up positions, given they were updated against rParenPos, which did not get set */ if (parser.currentElement == this) { // parameter addition might have added an awaiting (no return type) // method - see 1FVXQZ4 */ methodDeclaration.sourceEnd = methodDeclaration.arguments[methodDeclaration.arguments.length - 1].sourceEnd; methodDeclaration.bodyStart = methodDeclaration.sourceEnd + 1; parser.lastCheckPoint = methodDeclaration.bodyStart; } } } if (memberValuePairs != null) { System.arraycopy( memberValuePairs, 0, parser.astStack, parser.astPtr + 1, memberValuePairs.length); parser.astPtr += memberValuePairs.length; parser.astLengthStack[++parser.astLengthPtr] = memberValuePairs.length; } } } } }
public AbstractMethodDeclaration updatedMethodDeclaration() { /* update annotations */ if (modifiers != 0) { this.methodDeclaration.modifiers |= modifiers; if (this.modifiersStart < this.methodDeclaration.declarationSourceStart) { this.methodDeclaration.declarationSourceStart = modifiersStart; } } /* update annotations */ if (annotationCount > 0) { int existingCount = methodDeclaration.annotations == null ? 0 : methodDeclaration.annotations.length; Annotation[] annotationReferences = new Annotation[existingCount + annotationCount]; if (existingCount > 0) { System.arraycopy( methodDeclaration.annotations, 0, annotationReferences, annotationCount, existingCount); } for (int i = 0; i < annotationCount; i++) { annotationReferences[i] = annotations[i].updatedAnnotationReference(); } methodDeclaration.annotations = annotationReferences; int start = this.annotations[0].annotation.sourceStart; if (start < this.methodDeclaration.declarationSourceStart) { this.methodDeclaration.declarationSourceStart = start; } } if (methodBody != null) { Block block = methodBody.updatedBlock(); if (block != null) { methodDeclaration.statements = block.statements; if (methodDeclaration.declarationSourceEnd == 0) { methodDeclaration.declarationSourceEnd = block.sourceEnd; methodDeclaration.bodyEnd = block.sourceEnd; } /* first statement might be an explict constructor call destinated to a special slot */ if (methodDeclaration.isConstructor()) { ConstructorDeclaration constructor = (ConstructorDeclaration) methodDeclaration; if (methodDeclaration.statements != null && methodDeclaration.statements[0] instanceof ExplicitConstructorCall) { constructor.constructorCall = (ExplicitConstructorCall) methodDeclaration.statements[0]; int length = methodDeclaration.statements.length; System.arraycopy( methodDeclaration.statements, 1, (methodDeclaration.statements = new Statement[length - 1]), 0, length - 1); } if (constructor.constructorCall == null) { // add implicit constructor call constructor.constructorCall = SuperReference.implicitSuperConstructorCall(); } } } } else { if (methodDeclaration.declarationSourceEnd == 0) { if (methodDeclaration.sourceEnd + 1 == methodDeclaration.bodyStart) { // right brace is missing methodDeclaration.declarationSourceEnd = methodDeclaration.sourceEnd; methodDeclaration.bodyStart = methodDeclaration.sourceEnd; methodDeclaration.bodyEnd = methodDeclaration.sourceEnd; } else { methodDeclaration.declarationSourceEnd = methodDeclaration.bodyStart; methodDeclaration.bodyEnd = methodDeclaration.bodyStart; } } } if (localTypeCount > 0) methodDeclaration.bits |= ASTNode.HasLocalType; return methodDeclaration; }
public TypeBinding resolveType(BlockScope scope) { // Answer the signature return type // Base type promotion this.constant = Constant.NotAConstant; boolean receiverCast = false, argsContainCast = false; if (this.receiver instanceof CastExpression) { this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on receiverCast = true; } this.actualReceiverType = this.receiver.resolveType(scope); boolean receiverIsType = this.receiver instanceof NameReference && (((NameReference) this.receiver).bits & Binding.TYPE) != 0; if (receiverCast && this.actualReceiverType != null) { // due to change of declaring class with receiver type, only identity cast should be notified if (((CastExpression) this.receiver).expression.resolvedType == this.actualReceiverType) { scope.problemReporter().unnecessaryCast((CastExpression) this.receiver); } } // resolve type arguments (for generic constructor call) if (this.typeArguments != null) { int length = this.typeArguments.length; boolean argHasError = scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5; // typeChecks all arguments this.genericTypeArguments = new TypeBinding[length]; for (int i = 0; i < length; i++) { TypeReference typeReference = this.typeArguments[i]; if ((this.genericTypeArguments[i] = typeReference.resolveType(scope, true /* check bounds*/)) == null) { argHasError = true; } if (argHasError && typeReference instanceof Wildcard) { scope.problemReporter().illegalUsageOfWildcard(typeReference); } } if (argHasError) { if (this.arguments != null) { // still attempt to resolve arguments for (int i = 0, max = this.arguments.length; i < max; i++) { this.arguments[i].resolveType(scope); } } return null; } } // will check for null after args are resolved TypeBinding[] argumentTypes = Binding.NO_PARAMETERS; if (this.arguments != null) { boolean argHasError = false; // typeChecks all arguments int length = this.arguments.length; argumentTypes = new TypeBinding[length]; for (int i = 0; i < length; i++) { Expression argument = this.arguments[i]; if (argument instanceof CastExpression) { argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on argsContainCast = true; } if ((argumentTypes[i] = argument.resolveType(scope)) == null) { argHasError = true; } } if (argHasError) { if (this.actualReceiverType instanceof ReferenceBinding) { // record a best guess, for clients who need hint about possible method match TypeBinding[] pseudoArgs = new TypeBinding[length]; for (int i = length; --i >= 0; ) pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL : argumentTypes[i]; // replace args with errors with null type this.binding = this.receiver.isImplicitThis() ? scope.getImplicitMethod(this.selector, pseudoArgs, this) : scope.findMethod( (ReferenceBinding) this.actualReceiverType, this.selector, pseudoArgs, this); if (this.binding != null && !this.binding.isValidBinding()) { MethodBinding closestMatch = ((ProblemMethodBinding) this.binding).closestMatch; // record the closest match, for clients who may still need hint about possible method // match if (closestMatch != null) { if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method // shouldn't return generic method outside its context, rather convert it to raw // method (175409) closestMatch = scope .environment() .createParameterizedGenericMethod( closestMatch.original(), (RawTypeBinding) null); } this.binding = closestMatch; MethodBinding closestMatchOriginal = closestMatch.original(); if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { // ignore cases where method is used from within inside itself (e.g. direct // recursions) closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; } } } } return null; } } if (this.actualReceiverType == null) { return null; } // base type cannot receive any message if (this.actualReceiverType.isBaseType()) { scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); return null; } this.binding = this.receiver.isImplicitThis() ? scope.getImplicitMethod(this.selector, argumentTypes, this) : scope.getMethod(this.actualReceiverType, this.selector, argumentTypes, this); if (!this.binding.isValidBinding()) { if (this.binding.declaringClass == null) { if (this.actualReceiverType instanceof ReferenceBinding) { this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType; } else { scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, argumentTypes); return null; } } // https://bugs.eclipse.org/bugs/show_bug.cgi?id=245007 avoid secondary errors in case of // missing super type for anonymous classes ... ReferenceBinding declaringClass = this.binding.declaringClass; boolean avoidSecondary = declaringClass != null && declaringClass.isAnonymousType() && declaringClass.superclass() instanceof MissingTypeBinding; if (!avoidSecondary) scope.problemReporter().invalidMethod(this, this.binding); MethodBinding closestMatch = ((ProblemMethodBinding) this.binding).closestMatch; switch (this.binding.problemId()) { case ProblemReasons.Ambiguous: break; // no resilience on ambiguous case ProblemReasons.NotVisible: case ProblemReasons.NonStaticReferenceInConstructorInvocation: case ProblemReasons.NonStaticReferenceInStaticContext: case ProblemReasons.ReceiverTypeNotVisible: case ProblemReasons.ParameterBoundMismatch: // only steal returnType in cases listed above if (closestMatch != null) this.resolvedType = closestMatch.returnType; break; } // record the closest match, for clients who may still need hint about possible method match if (closestMatch != null) { this.binding = closestMatch; MethodBinding closestMatchOriginal = closestMatch.original(); if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { // ignore cases where method is used from within inside itself (e.g. direct recursions) closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; } } return (this.resolvedType != null && (this.resolvedType.tagBits & TagBits.HasMissingType) == 0) ? this.resolvedType : null; } final CompilerOptions compilerOptions = scope.compilerOptions(); if (compilerOptions.complianceLevel <= ClassFileConstants.JDK1_6 && this.binding.isPolymorphic()) { scope.problemReporter().polymorphicMethodNotBelow17(this); return null; } if (((this.bits & ASTNode.InsideExpressionStatement) != 0) && this.binding.isPolymorphic()) { // we only set the return type to be void if this method invocation is used inside an // expression statement this.binding = scope .environment() .updatePolymorphicMethodReturnType( (PolymorphicMethodBinding) this.binding, TypeBinding.VOID); } if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { scope.problemReporter().missingTypeInMethod(this, this.binding); } if (!this.binding.isStatic()) { // the "receiver" must not be a type if (receiverIsType) { scope.problemReporter().mustUseAStaticMethod(this, this.binding); if (this.actualReceiverType.isRawType() && (this.receiver.bits & ASTNode.IgnoreRawTypeCheck) == 0 && compilerOptions.getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) { scope.problemReporter().rawTypeReference(this.receiver, this.actualReceiverType); } } else { // handle indirect inheritance thru variable secondary bound // receiver may receive generic cast, as part of implicit conversion TypeBinding oldReceiverType = this.actualReceiverType; this.actualReceiverType = this.actualReceiverType.getErasureCompatibleType(this.binding.declaringClass); this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType); if (this.actualReceiverType != oldReceiverType && this.receiver.postConversionType(scope) != this .actualReceiverType) { // record need for explicit cast at codegen since // receiver could not handle it this.bits |= NeedReceiverGenericCast; } } } else { // static message invoked through receiver? legal but unoptimal (optional warning). if (!(this.receiver.isImplicitThis() || this.receiver.isSuper() || receiverIsType)) { scope.problemReporter().nonStaticAccessToStaticMethod(this, this.binding); } if (!this.receiver.isImplicitThis() && this.binding.declaringClass != this.actualReceiverType) { scope.problemReporter().indirectAccessToStaticMethod(this, this.binding); } } if (checkInvocationArguments( scope, this.receiver, this.actualReceiverType, this.binding, this.arguments, argumentTypes, argsContainCast, this)) { this.bits |= ASTNode.Unchecked; } // -------message send that are known to fail at compile time----------- if (this.binding.isAbstract()) { if (this.receiver.isSuper()) { scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding); } // abstract private methods cannot occur nor abstract static............ } if (isMethodUseDeprecated(this.binding, scope, true)) scope.problemReporter().deprecatedMethod(this.binding, this); // from 1.5 source level on, array#clone() returns the array type (but binding still shows // Object) if (this.binding == scope.environment().arrayClone && compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5) { this.resolvedType = this.actualReceiverType; } else { TypeBinding returnType; if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6 returnType = this.binding.returnType; if (returnType != null) { returnType = scope.environment().convertToRawType(returnType.erasure(), true); } } else { returnType = this.binding.returnType; if (returnType != null) { returnType = returnType.capture(scope, this.sourceEnd); } } this.resolvedType = returnType; } if (this.receiver.isSuper() && compilerOptions.getSeverity(CompilerOptions.OverridingMethodWithoutSuperInvocation) != ProblemSeverities.Ignore) { final ReferenceContext referenceContext = scope.methodScope().referenceContext; if (referenceContext instanceof AbstractMethodDeclaration) { final AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) referenceContext; MethodBinding enclosingMethodBinding = abstractMethodDeclaration.binding; if (enclosingMethodBinding.isOverriding() && CharOperation.equals(this.binding.selector, enclosingMethodBinding.selector) && this.binding.areParametersEqual(enclosingMethodBinding)) { abstractMethodDeclaration.bits |= ASTNode.OverridingMethodWithSupercall; } } } if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { scope .problemReporter() .unnecessaryTypeArgumentsForMethodInvocation( this.binding, this.genericTypeArguments, this.typeArguments); } return (this.resolvedType.tagBits & TagBits.HasMissingType) == 0 ? this.resolvedType : null; }