### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: batch/org/eclipse/jdt/internal/compiler/batch/Main.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java,v retrieving revision 1.356 diff -u -r1.356 Main.java --- batch/org/eclipse/jdt/internal/compiler/batch/Main.java 26 Oct 2010 17:24:15 -0000 1.356 +++ batch/org/eclipse/jdt/internal/compiler/batch/Main.java 6 Dec 2010 06:58:21 -0000 @@ -3228,6 +3228,10 @@ CompilerOptions.OPTION_ReportMissingOverrideAnnotationForInterfaceMethodImplementation, isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); return; + } else if (token.equals("all-static-method")) { //$NON-NLS-1$ + setSeverity(CompilerOptions.OPTION_ReportMethodCanBeStatic, severity, isEnabling); + setSeverity(CompilerOptions.OPTION_ReportMethodCanBePotentiallyStatic, severity, isEnabling); + return; } break; case 'b' : @@ -3459,6 +3463,9 @@ } else if (token.equals("super")) { //$NON-NLS-1$ setSeverity(CompilerOptions.OPTION_ReportOverridingMethodWithoutSuperInvocation, severity, isEnabling); return; + } else if (token.equals("static-method")) { //$NON-NLS-1$ + setSeverity(CompilerOptions.OPTION_ReportMethodCanBeStatic, severity, isEnabling); + return; } break; case 't' : Index: batch/org/eclipse/jdt/internal/compiler/batch/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties,v retrieving revision 1.944 diff -u -r1.944 messages.properties --- batch/org/eclipse/jdt/internal/compiler/batch/messages.properties 4 Dec 2010 08:28:58 -0000 1.944 +++ batch/org/eclipse/jdt/internal/compiler/batch/messages.properties 6 Dec 2010 06:58:21 -0000 @@ -267,6 +267,7 @@ \ allDeprecation deprecation including inside deprecated code\n\ \ allJavadoc invalid or missing javadoc\n\ \ allOver-ann all missing @Override annotations\n\ +\ all-static-method all method can be declared as static warnings\n\ \ assertIdentifier + ''assert'' used as identifier\n\ \ boxing autoboxing conversion\n\ \ charConcat + char[] in String concat\n\ @@ -309,6 +310,7 @@ \ semicolon unnecessary semicolon, empty statement\n\ \ serial + missing serialVersionUID\n\ \ specialParamHiding constructor or setter parameter hiding a field\n\ +\ static-method method can be declared as static\n\ \ static-access macro for indirectStatic and staticReceiver\n\ \ staticReceiver + non-static reference to static member\n\ \ super overriding a method without making a super invocation\n\ Index: compiler/org/eclipse/jdt/core/compiler/IProblem.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java,v retrieving revision 1.222 diff -u -r1.222 IProblem.java --- compiler/org/eclipse/jdt/core/compiler/IProblem.java 7 Sep 2010 13:39:18 -0000 1.222 +++ compiler/org/eclipse/jdt/core/compiler/IProblem.java 6 Dec 2010 06:58:21 -0000 @@ -401,6 +401,10 @@ int IndirectAccessToStaticMethod = Internal + MethodRelated + 119; /** @since 3.4 */ int MissingTypeInMethod = MethodRelated + 120; + /** @since 3.7 */ + int MethodCanBeStatic = Internal + MethodRelated + 121; + /** @since 3.7 */ + int MethodCanBePotentiallyStatic = Internal + MethodRelated + 122; // constructors /** @since 3.4 */ Index: compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java,v retrieving revision 1.104 diff -u -r1.104 ASTNode.java --- compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java 22 Oct 2010 22:42:55 -0000 1.104 +++ compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java 6 Dec 2010 06:58:21 -0000 @@ -169,6 +169,7 @@ // for block and method declaration public static final int UndocumentedEmptyBlock = Bit4; public static final int OverridingMethodWithSupercall = Bit5; + public static final int CanBeStatic = Bit6; // used to flag a method that can be declared static // for initializer and method declaration public static final int ErrorInSignature = Bit6; Index: compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java,v retrieving revision 1.130 diff -u -r1.130 FieldReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 22 Oct 2010 22:42:55 -0000 1.130 +++ compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java 6 Dec 2010 06:58:21 -0000 @@ -108,6 +108,17 @@ currentScope.problemReporter().cannotAssignToFinalField(this.binding, this); } } + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 + if (!this.binding.isStatic()) { + if (this.receiver.isThis()) { + currentScope.resetEnclosingMethodStaticFlag(); + } + } else if (this.receiver.isThis()) { + if ((this.receiver.bits & ASTNode.IsImplicitThis) == 0) { + // explicit this, not allowed in static context + currentScope.resetEnclosingMethodStaticFlag(); + } + } return flowInfo; } @@ -120,6 +131,16 @@ this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic); if (nonStatic) { this.receiver.checkNPE(currentScope, flowContext, flowInfo); + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 + if (this.receiver.isThis()) { + currentScope.resetEnclosingMethodStaticFlag(); + } + } else if (this.receiver.isThis()) { + if ((this.receiver.bits & ASTNode.IsImplicitThis) == 0) { + // explicit this receiver, not allowed in static context + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 + currentScope.resetEnclosingMethodStaticFlag(); + } } if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) { Index: compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java,v retrieving revision 1.74 diff -u -r1.74 LocalDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 9 Sep 2010 17:36:21 -0000 1.74 +++ compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java 6 Dec 2010 06:58:21 -0000 @@ -39,6 +39,29 @@ if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { this.bits |= ASTNode.IsLocalDeclarationReachable; // only set if actually reached } + if (this.binding != null && this.type.resolvedType instanceof TypeVariableBinding) { + MethodScope methodScope= this.binding.declaringScope.methodScope(); + AbstractMethodDeclaration methodDeclaration = methodScope.referenceMethod(); + if (methodDeclaration != null && ((methodDeclaration.bits & ASTNode.CanBeStatic) != 0) && methodDeclaration.binding != null) { + TypeVariableBinding[] typeVariables = methodDeclaration.binding.typeVariables(); + if (typeVariables == Binding.NO_TYPE_VARIABLES) { + // Method declares no type variables. + currentScope.resetEnclosingMethodStaticFlag(); + } else { + boolean usingEnclosingMethodTypeVariable = false; + for (int i = 0; i < typeVariables.length ; i ++) { + if (typeVariables[i] == this.type.resolvedType){ + usingEnclosingMethodTypeVariable = true; + break; + } + } + if (!usingEnclosingMethodTypeVariable) { + // uses a type variable not declared by enclosing method + currentScope.resetEnclosingMethodStaticFlag(); + } + } + } + } if (this.initialization == null) { return flowInfo; } Index: compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java,v retrieving revision 1.148 diff -u -r1.148 MessageSend.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 12 Aug 2010 16:58:28 -0000 1.148 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java 6 Dec 2010 06:58:21 -0000 @@ -61,6 +61,16 @@ flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits(); if (nonStatic) { this.receiver.checkNPE(currentScope, flowContext, flowInfo); + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 + if (this.receiver.isThis()) { + // accessing non-static method without an object + currentScope.resetEnclosingMethodStaticFlag(); + } + } else if (this.receiver.isThis()) { + if ((this.receiver.bits & ASTNode.IsImplicitThis) == 0) { + // explicit this receiver, not allowed in static context + currentScope.resetEnclosingMethodStaticFlag(); + } } if (this.arguments != null) { Index: compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java,v retrieving revision 1.76 diff -u -r1.76 MethodDeclaration.java --- compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 3 Nov 2009 15:37:46 -0000 1.76 +++ compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java 6 Dec 2010 06:58:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2010 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 @@ -18,11 +18,15 @@ import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; +import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.MemberTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; import org.eclipse.jdt.internal.compiler.parser.Parser; import org.eclipse.jdt.internal.compiler.problem.AbortMethod; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; @@ -78,8 +82,19 @@ if (this.arguments != null) { for (int i = 0, count = this.arguments.length; i < count; i++) { flowInfo.markAsDefinitelyAssigned(this.arguments[i].binding); + // if this method uses a type parameter declared by the declaring class, + // it can't be static. https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 + if (this.arguments[i].binding != null && (this.arguments[i].binding.type instanceof TypeVariableBinding)) { + Binding declaringElement = ((TypeVariableBinding)this.arguments[i].binding.type).declaringElement; + if (this.binding != null && this.binding.declaringClass == declaringElement) + this.bits &= ~ASTNode.CanBeStatic; + } } } + if (this.binding.declaringClass instanceof MemberTypeBinding && !this.binding.declaringClass.isStatic()) { + // method of a non-static member type can't be static. + this.bits &= ~ASTNode.CanBeStatic; + } // propagate to statements if (this.statements != null) { int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) == 0 ? Statement.NOT_COMPLAINED : Statement.COMPLAINED_FAKE_REACHABLE; @@ -89,6 +104,9 @@ flowInfo = stat.analyseCode(this.scope, methodContext, flowInfo); } } + } else { + // method with empty body should not be flagged as static. + this.bits &= ~ASTNode.CanBeStatic; } // check for missing returning path TypeBinding returnTypeBinding = this.binding.returnType; @@ -105,6 +123,17 @@ methodContext.complainIfUnusedExceptionHandlers(this); // check unused parameters this.scope.checkUnusedParameters(this.binding); + // check if the method could have been static + if (!this.binding.isStatic() && (this.bits & ASTNode.CanBeStatic) != 0) { + if(!this.binding.isOverriding() && !this.binding.isImplementing()) { + if (this.binding.isPrivate() || this.binding.isFinal() || this.binding.declaringClass.isFinal()) { + this.scope.problemReporter().methodCanBeDeclaredStatic(this); + } else { + this.scope.problemReporter().methodCanBePotentiallyDeclaredStatic(this); + } + } + + } } catch (AbortMethod e) { this.ignoreFurtherInvestigation = true; } @@ -134,10 +163,16 @@ if (CharOperation.equals(this.scope.enclosingSourceType().sourceName, this.selector)) { this.scope.problemReporter().methodWithConstructorName(this); } - + boolean methodReturnsTypeParameterNotDeclaredByIt = false; + if (this.returnType != null && this.returnType.resolvedType instanceof TypeVariableBinding) { + methodReturnsTypeParameterNotDeclaredByIt = true; + } if (this.typeParameters != null) { for (int i = 0, length = this.typeParameters.length; i < length; i++) { this.typeParameters[i].resolve(this.scope); + if (methodReturnsTypeParameterNotDeclaredByIt && this.typeParameters[i].binding == this.returnType.resolvedType) { + methodReturnsTypeParameterNotDeclaredByIt = false; + } } } @@ -207,6 +242,10 @@ // the method HAS a body --> abstract native modifiers are forbiden if (((this.modifiers & ClassFileConstants.AccNative) != 0) || ((this.modifiers & ClassFileConstants.AccAbstract) != 0)) this.scope.problemReporter().methodNeedingNoBody(this); + else if (this.binding != null && !this.binding.isStatic() && !(this.binding.declaringClass instanceof LocalTypeBinding) && !methodReturnsTypeParameterNotDeclaredByIt) { + // Not a method of local type - can be static + this.bits |= ASTNode.CanBeStatic; + } } } super.resolveStatements(); Index: compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java,v retrieving revision 1.148 diff -u -r1.148 QualifiedNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 22 Oct 2010 22:42:55 -0000 1.148 +++ compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java 6 Dec 2010 06:58:21 -0000 @@ -81,6 +81,9 @@ currentScope.problemReporter().uninitializedBlankFinalField(lastFieldBinding, this); } } + if (!lastFieldBinding.isStatic()) { + currentScope.resetEnclosingMethodStaticFlag(); + } break; case Binding.LOCAL : // first binding is a local variable @@ -176,8 +179,8 @@ if (needValue || complyTo14) { manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) this.binding, 0, flowInfo); } + FieldBinding fieldBinding = (FieldBinding) this.binding; if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding - FieldBinding fieldBinding = (FieldBinding) this.binding; // check if reading a final blank field if (fieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { @@ -187,6 +190,9 @@ } } } + if (!fieldBinding.isStatic()) { + currentScope.resetEnclosingMethodStaticFlag(); + } break; case Binding.LOCAL : // reading a local variable LocalVariableBinding localBinding; Index: compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java,v retrieving revision 1.128 diff -u -r1.128 SingleNameReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 9 Nov 2010 19:59:19 -0000 1.128 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java 6 Dec 2010 06:58:21 -0000 @@ -63,14 +63,18 @@ if (isCompound) { // check the variable part is initialized if blank final switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD : // reading a field - FieldBinding fieldBinding; - if ((fieldBinding = (FieldBinding) this.binding).isBlankFinal() + FieldBinding fieldBinding = (FieldBinding) this.binding; + if (fieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo); if (!fieldInits.isDefinitelyAssigned(fieldBinding)) { currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); } } + if (!fieldBinding.isStatic()) { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 + currentScope.resetEnclosingMethodStaticFlag(); + } manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); break; case Binding.LOCAL : // reading a local variable @@ -115,6 +119,10 @@ currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this); } } + if (!fieldBinding.isStatic()) { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 + currentScope.resetEnclosingMethodStaticFlag(); + } break; case Binding.LOCAL : // assigning to a local variable LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; @@ -164,6 +172,10 @@ currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); } } + if (!fieldBinding.isStatic()) { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 + currentScope.resetEnclosingMethodStaticFlag(); + } break; case Binding.LOCAL : // reading a local variable LocalVariableBinding localBinding; Index: compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java,v retrieving revision 1.31 diff -u -r1.31 SuperReference.java --- compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java 7 Mar 2009 01:08:07 -0000 1.31 +++ compiler/org/eclipse/jdt/internal/compiler/ast/SuperReference.java 6 Dec 2010 06:58:21 -0000 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2010 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 @@ -11,6 +11,8 @@ package org.eclipse.jdt.internal.compiler.ast; import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; @@ -66,4 +68,9 @@ visitor.visit(this, blockScope); visitor.endVisit(this, blockScope); } + + public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { + currentScope.resetEnclosingMethodStaticFlag(); + return analyseCode(currentScope, flowContext, flowInfo); + } } Index: compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java,v retrieving revision 1.235 diff -u -r1.235 CompilerOptions.java --- compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 21 Oct 2010 19:59:58 -0000 1.235 +++ compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java 6 Dec 2010 06:58:21 -0000 @@ -133,6 +133,8 @@ public static final String OPTION_ReportTasks = "org.eclipse.jdt.core.compiler.problem.tasks"; //$NON-NLS-1$ public static final String OPTION_ReportUnusedObjectAllocation = "org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation"; //$NON-NLS-1$ public static final String OPTION_IncludeNullInfoFromAsserts = "org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts"; //$NON-NLS-1$ + public static final String OPTION_ReportMethodCanBeStatic = "org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic"; //$NON-NLS-1$ + public static final String OPTION_ReportMethodCanBePotentiallyStatic = "org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic"; //$NON-NLS-1$ // Backward compatibility public static final String OPTION_ReportInvalidAnnotation = "org.eclipse.jdt.core.compiler.problem.invalidAnnotation"; //$NON-NLS-1$ public static final String OPTION_ReportMissingAnnotation = "org.eclipse.jdt.core.compiler.problem.missingAnnotation"; //$NON-NLS-1$ @@ -238,6 +240,8 @@ public static final int DeadCode = IrritantSet.GROUP2 | ASTNode.Bit2; public static final int Tasks = IrritantSet.GROUP2 | ASTNode.Bit3; public static final int UnusedObjectAllocation = IrritantSet.GROUP2 | ASTNode.Bit4; + public static final int MethodCanBeStatic = IrritantSet.GROUP2 | ASTNode.Bit5; + public static final int MethodCanBePotentiallyStatic = IrritantSet.GROUP2 | ASTNode.Bit6; // Severity level for handlers /** @@ -375,6 +379,7 @@ "rawtypes", //$NON-NLS-1$ "serial", //$NON-NLS-1$ "static-access", //$NON-NLS-1$ + "static-method", //$NON-NLS-1$ "super", //$NON-NLS-1$ "synthetic-access", //$NON-NLS-1$ "unchecked", //$NON-NLS-1$ @@ -539,6 +544,10 @@ return OPTION_ReportDeadCode; case UnusedObjectAllocation: return OPTION_ReportUnusedObjectAllocation; + case MethodCanBeStatic : + return OPTION_ReportMethodCanBeStatic; + case MethodCanBePotentiallyStatic : + return OPTION_ReportMethodCanBePotentiallyStatic; } return null; } @@ -638,6 +647,8 @@ OPTION_ReportInvalidJavadoc, OPTION_ReportLocalVariableHiding, OPTION_ReportMethodWithConstructorName, + OPTION_ReportMethodCanBeStatic, + OPTION_ReportMethodCanBePotentiallyStatic, OPTION_ReportMissingDeprecatedAnnotation, OPTION_ReportMissingJavadocComments, OPTION_ReportMissingJavadocTagDescription, @@ -739,6 +750,9 @@ return "fallthrough"; //$NON-NLS-1$ case OverridingMethodWithoutSuperInvocation : return "super"; //$NON-NLS-1$ + case MethodCanBeStatic : + case MethodCanBePotentiallyStatic : + return "static-method"; //$NON-NLS-1$ } return null; } @@ -796,6 +810,8 @@ return IrritantSet.SERIAL; if ("static-access".equals(warningToken)) //$NON-NLS-1$ return IrritantSet.STATIC_ACCESS; + if ("static-method".equals(warningToken)) //$NON-NLS-1$ + return IrritantSet.STATIC_METHOD; if ("synthetic-access".equals(warningToken)) //$NON-NLS-1$ return IrritantSet.SYNTHETIC_ACCESS; if ("super".equals(warningToken)) { //$NON-NLS-1$ @@ -921,6 +937,8 @@ optionsMap.put(OPTION_ReportTasks, getSeverityString(Tasks)); optionsMap.put(OPTION_ReportUnusedObjectAllocation, getSeverityString(UnusedObjectAllocation)); optionsMap.put(OPTION_IncludeNullInfoFromAsserts, this.includeNullInfoFromAsserts ? ENABLED : DISABLED); + optionsMap.put(OPTION_ReportMethodCanBeStatic, getSeverityString(MethodCanBeStatic)); + optionsMap.put(OPTION_ReportMethodCanBePotentiallyStatic, getSeverityString(MethodCanBePotentiallyStatic)); return optionsMap; } @@ -1339,6 +1357,8 @@ if ((optionValue = optionsMap.get(OPTION_ReportDeadCode)) != null) updateSeverity(DeadCode, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportTasks)) != null) updateSeverity(Tasks, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportUnusedObjectAllocation)) != null) updateSeverity(UnusedObjectAllocation, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportMethodCanBeStatic)) != null) updateSeverity(MethodCanBeStatic, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportMethodCanBePotentiallyStatic)) != null) updateSeverity(MethodCanBePotentiallyStatic, optionValue); // Javadoc options if ((optionValue = optionsMap.get(OPTION_DocCommentSupport)) != null) { @@ -1551,6 +1571,8 @@ buf.append("\n\t- dead code in trivial if statement: ").append(this.reportDeadCodeInTrivialIfStatement ? ENABLED : DISABLED); //$NON-NLS-1$ buf.append("\n\t- tasks severity: ").append(getSeverityString(Tasks)); //$NON-NLS-1$ buf.append("\n\t- unused object allocation: ").append(getSeverityString(UnusedObjectAllocation)); //$NON-NLS-1$ + buf.append("\n\t- method can be static: ").append(getSeverityString(MethodCanBeStatic)); //$NON-NLS-1$ + buf.append("\n\t- method can be potentially static: ").append(getSeverityString(MethodCanBePotentiallyStatic)); //$NON-NLS-1$ return buf.toString(); } Index: compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java,v retrieving revision 1.10 diff -u -r1.10 IrritantSet.java --- compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java 18 May 2010 18:12:12 -0000 1.10 +++ compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java 6 Dec 2010 06:58:21 -0000 @@ -51,6 +51,7 @@ public static final IrritantSet RESTRICTION = new IrritantSet(CompilerOptions.ForbiddenReference); public static final IrritantSet SERIAL = new IrritantSet(CompilerOptions.MissingSerialVersion); public static final IrritantSet STATIC_ACCESS = new IrritantSet(CompilerOptions.IndirectStaticAccess); + public static final IrritantSet STATIC_METHOD = new IrritantSet(CompilerOptions.MethodCanBeStatic); public static final IrritantSet SYNTHETIC_ACCESS = new IrritantSet(CompilerOptions.AccessEmulation); public static final IrritantSet SUPER = new IrritantSet(CompilerOptions.OverridingMethodWithoutSuperInvocation); public static final IrritantSet UNUSED = new IrritantSet(CompilerOptions.UnusedLocalVariable); @@ -119,6 +120,8 @@ .set(CompilerOptions.RedundantSuperinterface) .set(CompilerOptions.DeadCode) .set(CompilerOptions.UnusedObjectAllocation); + STATIC_METHOD + .set(CompilerOptions.MethodCanBePotentiallyStatic); String suppressRawWhenUnchecked = System.getProperty("suppressRawWhenUnchecked"); //$NON-NLS-1$ if (suppressRawWhenUnchecked != null && "true".equalsIgnoreCase(suppressRawWhenUnchecked)) { //$NON-NLS-1$ UNCHECKED.set(CompilerOptions.RawTypeReference); Index: compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java,v retrieving revision 1.122 diff -u -r1.122 BlockScope.java --- compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 9 Nov 2010 19:59:19 -0000 1.122 +++ compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java 6 Dec 2010 06:58:21 -0000 @@ -941,4 +941,18 @@ s += ((BlockScope) this.subscopes[i]).toString(tab + 1) + "\n"; //$NON-NLS-1$ return s; } +// https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 +public void resetEnclosingMethodStaticFlag() { + MethodScope methodScope = methodScope(); + while (methodScope != null && methodScope.referenceContext instanceof MethodDeclaration) { + MethodDeclaration methodDeclaration= (MethodDeclaration) methodScope.referenceContext; + methodDeclaration.bits &= ~ASTNode.CanBeStatic; + ClassScope enclosingClassScope = methodScope.enclosingClassScope(); + if (enclosingClassScope != null) { + methodScope = enclosingClassScope.methodScope(); + } else { + break; + } + } +} } Index: compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java,v retrieving revision 1.426 diff -u -r1.426 ProblemReporter.java --- compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 19 Nov 2010 14:22:00 -0000 1.426 +++ compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java 6 Dec 2010 06:58:22 -0000 @@ -418,6 +418,12 @@ case IProblem.UnusedObjectAllocation: return CompilerOptions.UnusedObjectAllocation; + + case IProblem.MethodCanBeStatic: + return CompilerOptions.MethodCanBeStatic; + + case IProblem.MethodCanBePotentiallyStatic: + return CompilerOptions.MethodCanBePotentiallyStatic; } return 0; } @@ -448,6 +454,8 @@ case CompilerOptions.MissingOverrideAnnotation : case CompilerOptions.MissingDeprecatedAnnotation : case CompilerOptions.ParameterAssignment : + case CompilerOptions.MethodCanBeStatic : + case CompilerOptions.MethodCanBePotentiallyStatic : return CategorizedProblem.CAT_CODE_STYLE; case CompilerOptions.MaskedCatchBlock : @@ -5020,6 +5028,48 @@ methodDecl.sourceEnd); } +public void methodCanBeDeclaredStatic(MethodDeclaration methodDecl) { + int severity = computeSeverity(IProblem.MethodCanBeStatic); + if (severity == ProblemSeverities.Ignore) return; + MethodBinding method = methodDecl.binding; + this.handle( + IProblem.MethodCanBeStatic, + new String[] { + new String(method.declaringClass.readableName()), + new String(method.selector), + typesAsString(method.isVarargs(), method.parameters, false) + }, + new String[] { + new String(method.declaringClass.shortReadableName()), + new String(method.selector), + typesAsString(method.isVarargs(), method.parameters, true) + }, + severity, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} + +public void methodCanBePotentiallyDeclaredStatic(MethodDeclaration methodDecl) { + int severity = computeSeverity(IProblem.MethodCanBePotentiallyStatic); + if (severity == ProblemSeverities.Ignore) return; + MethodBinding method = methodDecl.binding; + this.handle( + IProblem.MethodCanBePotentiallyStatic, + new String[] { + new String(method.declaringClass.readableName()), + new String(method.selector), + typesAsString(method.isVarargs(), method.parameters, false) + }, + new String[] { + new String(method.declaringClass.shortReadableName()), + new String(method.selector), + typesAsString(method.isVarargs(), method.parameters, true) + }, + severity, + methodDecl.sourceStart, + methodDecl.sourceEnd); +} + public void missingDeprecatedAnnotationForField(FieldDeclaration field) { int severity = computeSeverity(IProblem.FieldMissingDeprecatedAnnotation); if (severity == ProblemSeverities.Ignore) return; Index: compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties,v retrieving revision 1.259 diff -u -r1.259 messages.properties --- compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 22 Oct 2010 22:42:56 -0000 1.259 +++ compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties 6 Dec 2010 06:58:22 -0000 @@ -103,6 +103,8 @@ 118 = The method {1}({2}) from the type {0} is never used locally 119 = The static method {1}({2}) from the type {0} should be accessed directly 120 = The method {1}({2}) from the type {0} refers to the missing type {3} +121 = The method {1}({2}) from the type {0} can be declared as static +122 = The method {1}({2}) from the type {0} can potentially be declared as static 129 = The constructor {0}({1}) refers to the missing type {2} 130 = The constructor {0}({1}) is undefined Index: formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java,v retrieving revision 1.80 diff -u -r1.80 DefaultCodeFormatter.java --- formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java 22 Feb 2010 11:01:46 -0000 1.80 +++ formatter/org/eclipse/jdt/internal/formatter/DefaultCodeFormatter.java 6 Dec 2010 06:58:22 -0000 @@ -338,6 +338,8 @@ optionsMap.put(CompilerOptions.OPTION_ReportSpecialParameterHidingField, CompilerOptions.DISABLED); optionsMap.put(CompilerOptions.OPTION_MaxProblemPerUnit, String.valueOf(100)); optionsMap.put(CompilerOptions.OPTION_InlineJsr, CompilerOptions.DISABLED); + optionsMap.put(CompilerOptions.OPTION_ReportMethodCanBeStatic, CompilerOptions.IGNORE); + optionsMap.put(CompilerOptions.OPTION_ReportMethodCanBePotentiallyStatic, CompilerOptions.IGNORE); this.defaultCompilerOptions = optionsMap; } Object sourceOption = this.options.get(CompilerOptions.OPTION_Source); Index: model/org/eclipse/jdt/core/JavaCore.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java,v retrieving revision 1.655 diff -u -r1.655 JavaCore.java --- model/org/eclipse/jdt/core/JavaCore.java 6 Oct 2010 13:57:36 -0000 1.655 +++ model/org/eclipse/jdt/core/JavaCore.java 6 Dec 2010 06:58:22 -0000 @@ -1314,6 +1314,33 @@ */ public static final String COMPILER_PB_PARAMETER_ASSIGNMENT = PLUGIN_ID + ".compiler.problem.parameterAssignment"; //$NON-NLS-1$ /** + * Compiler option ID: Reporting a method that qualifies as static, but not declared static. + *

When enabled, the compiler will issue an error or a warning if a method has + * not been declared as static, even though it qualifies as one. + *

+ *
Option id:
"org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic"
+ *
Possible values:
{ "error", "warning", "ignore" }
+ *
Default:
"ignore"
+ *
+ * @since 3.7 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_MISSING_STATIC_ON_METHOD = PLUGIN_ID + ".compiler.problem.reportMethodCanBeStatic"; //$NON-NLS-1$ + /** + * Compiler option ID: Reporting a method that may qualify as static, but not declared static. + *

When enabled, the compiler will issue an error or a warning if a method has + * not been declared as static, even though it may qualify as one, + * when another method doesn't override it. + *

+ *
Option id:
"org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic"
+ *
Possible values:
{ "error", "warning", "ignore" }
+ *
Default:
"ignore"
+ *
+ * @since 3.7 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_POTENTIALLY_MISSING_STATIC_ON_METHOD = PLUGIN_ID + ".compiler.problem.reportMethodCanBePotentiallyStatic"; //$NON-NLS-1$ + /** * Compiler option ID: Setting Source Compatibility Mode. *

Specify whether which source level compatibility is used. From 1.4 on, 'assert' is a keyword * reserved for assertion support. Also note, than when toggling to 1.4 mode, the target VM #P org.eclipse.jdt.core.tests.compiler Index: src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java,v retrieving revision 1.220 diff -u -r1.220 BatchCompilerTest.java --- src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java 19 Nov 2010 14:21:58 -0000 1.220 +++ src/org/eclipse/jdt/core/tests/compiler/regression/BatchCompilerTest.java 6 Dec 2010 06:58:25 -0000 @@ -48,7 +48,7 @@ private static final Main MAIN = new Main(null/*outWriter*/, null/*errWriter*/, false/*systemExit*/, null/*options*/, null/*progress*/); static { -// TESTS_NAMES = new String[] { "test292_warn_options" }; +// TESTS_NAMES = new String[] { "test295_warn_options" }; // TESTS_NUMBERS = new int[] { 306 }; // TESTS_RANGE = new int[] { 298, -1 }; } @@ -1663,6 +1663,7 @@ " allDeprecation deprecation including inside deprecated code\n" + " allJavadoc invalid or missing javadoc\n" + " allOver-ann all missing @Override annotations\n" + + " all-static-method all method can be declared as static warnings\n" + " assertIdentifier + ''assert'' used as identifier\n" + " boxing autoboxing conversion\n" + " charConcat + char[] in String concat\n" + @@ -1705,6 +1706,7 @@ " semicolon unnecessary semicolon, empty statement\n" + " serial + missing serialVersionUID\n" + " specialParamHiding constructor or setter parameter hiding a field\n" + + " static-method method can be declared as static\n" + " static-access macro for indirectStatic and staticReceiver\n" + " staticReceiver + non-static reference to static member\n" + " super overriding a method without making a super invocation\n" + @@ -1857,6 +1859,8 @@ "