diff options
author | Stephan Herrmann | 2015-04-28 15:54:14 +0000 |
---|---|---|
committer | Stephan Herrmann | 2015-04-28 15:54:14 +0000 |
commit | 075533e70f43b34233c7fdad30af6ff9bb0a36a8 (patch) | |
tree | ebd195d622208318dc02f82b3005d660728dc1ac /org.eclipse.jdt.core/compiler | |
parent | 1e97f79ee10aa0e956f4ba6f5e68262525ef39b0 (diff) | |
download | org.eclipse.objectteams-075533e70f43b34233c7fdad30af6ff9bb0a36a8.tar.gz org.eclipse.objectteams-075533e70f43b34233c7fdad30af6ff9bb0a36a8.tar.xz org.eclipse.objectteams-075533e70f43b34233c7fdad30af6ff9bb0a36a8.zip |
Update jdt.core to I20150428-0800 (M7 warm-up).
Manually merge from origin (bogus lineend changes):
- NullTypeAnnotationTest
- AstConverter18Test (no real change)
- FormatterBugsTests (no real change)
- SpacePreparator
- SourceTypeBinding
Diffstat (limited to 'org.eclipse.jdt.core/compiler')
37 files changed, 663 insertions, 283 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java index bef278010..bbfc6c95a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/CompilationResult.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -78,7 +78,7 @@ public class CompilationResult { public int problemCount; public int taskCount; public ICompilationUnit compilationUnit; - private Map problemsMap; + private Map<CategorizedProblem, ReferenceContext> problemsMap; private Set firstErrors; private int maxProblemPerUnit; public char[][][] qualifiedReferences; @@ -205,7 +205,7 @@ private int computePriority(CategorizedProblem problem){ if (problem.isError()){ priority += P_ERROR; } - ReferenceContext context = this.problemsMap == null ? null : (ReferenceContext) this.problemsMap.get(problem); + ReferenceContext context = this.problemsMap == null ? null : this.problemsMap.get(problem); if (context != null){ if (context instanceof AbstractMethodDeclaration){ AbstractMethodDeclaration method = (AbstractMethodDeclaration) context; @@ -500,6 +500,13 @@ public void record(CategorizedProblem newProblem, ReferenceContext referenceCont } } +ReferenceContext getContext(CategorizedProblem problem) { + if (problem != null) { + return this.problemsMap.get(problem); + } + return null; +} + /** * For now, remember the compiled type using its compound name. */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java index 963b53ac6..beef5ebec 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/Compiler.java @@ -17,6 +17,7 @@ package org.eclipse.jdt.internal.compiler; import java.io.PrintWriter; +import java.util.HashMap; import java.util.Map; import org.eclipse.jdt.core.compiler.CategorizedProblem; @@ -32,6 +33,7 @@ import org.eclipse.jdt.internal.compiler.env.ISourceType; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.CompilerStats; import org.eclipse.jdt.internal.compiler.impl.ITypeRequestor; +import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; @@ -88,6 +90,8 @@ public class Compiler implements ITypeRequestor, ProblemSeverities { //public CompilationUnitResult currentCompilationUnitResult; public CompilationUnitDeclaration[] unitsToProcess; public int totalUnits; // (totalUnits-1) gives the last unit in unitToProcess + + private Map<String, APTProblem[]> aptProblems; // name lookup public LookupEnvironment lookupEnvironment; @@ -496,6 +500,7 @@ public class Compiler implements ITypeRequestor, ProblemSeverities { return; } } catch (SourceTypeCollisionException e) { + backupAptProblems(); reset(); // a generated type was referenced before it was created // the compiler either created a MissingType or found a BinaryType for it @@ -511,6 +516,8 @@ public class Compiler implements ITypeRequestor, ProblemSeverities { return; } } + // Restore the problems before the results are processed and cleaned up. + restoreAptProblems(); processCompiledUnits(0); } catch (AbortCompilation e) { this.handleInternalException(e, null); @@ -526,6 +533,58 @@ public class Compiler implements ITypeRequestor, ProblemSeverities { } } + class APTProblem { + CategorizedProblem problem; + ReferenceContext context; + APTProblem(CategorizedProblem problem, ReferenceContext context) { + this.problem = problem; + this.context = context; + } + } + + protected void backupAptProblems() { + if (this.unitsToProcess == null) return; + for (CompilationUnitDeclaration unitDecl : this.unitsToProcess) { + if (unitDecl == null) continue; + CompilationResult result = unitDecl.compilationResult; + if (result != null && result.hasErrors()) { + CategorizedProblem[] errors = result.getErrors(); + for (CategorizedProblem problem : errors) { + if (problem.getCategoryID() == CategorizedProblem.CAT_UNSPECIFIED) { + if (this.aptProblems == null) { + this.aptProblems = new HashMap<>(); + } + APTProblem[] problems = this.aptProblems.get(new String(unitDecl.getFileName())); + if (problems == null) { + this.aptProblems.put( + new String(unitDecl.getFileName()), + new APTProblem[] { new APTProblem(problem, result.getContext(problem)) }); + } else { + APTProblem[] temp = new APTProblem[problems.length + 1]; + System.arraycopy(problems, 0, temp, 0, problems.length); + temp[problems.length] = new APTProblem(problem, result.getContext(problem)); + this.aptProblems.put(new String(unitDecl.getFileName()), temp); + } + } + } + } + } + } + + protected void restoreAptProblems() { + if (this.unitsToProcess != null && this.aptProblems!= null) { + for (CompilationUnitDeclaration unit : this.unitsToProcess) { + APTProblem[] problems = this.aptProblems.get(new String(unit.getFileName())); + if (problems != null) { + for (APTProblem problem : problems) { + unit.compilationResult.record(problem.problem, problem.context); + } + } + } + } + this.aptProblems = null; // No need for this. + } + protected void processCompiledUnits(int startingIndex) throws java.lang.Error { CompilationUnitDeclaration unit = null; ProcessTaskManager processingTask = null; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java index 9692df5a0..f1ef793b7 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -40,6 +40,7 @@ * Bug 429430 - [1.8] Lambdas and method reference infer wrong exception type with generics (RuntimeException instead of IOException) * Bug 434297 - [1.8] NPE in LamdaExpression.analyseCode with lamda expression nested in a conditional expression * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression + * Bug 448709 - [1.8][null] ensure we don't infer types that violate null constraints on a type parameter's bound * Jesper S Moller <jesper@selskabet.org> - Contributions for * bug 378674 - "The method can be declared as static" is wrong * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for @@ -613,9 +614,18 @@ public TypeBinding resolveType(BlockScope scope) { if (!isDiamond && this.resolvedType.isParameterizedTypeWithActualArguments()) { checkTypeArgumentRedundancy((ParameterizedTypeBinding) this.resolvedType, scope); } - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) { - new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations) - .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope); + if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { + if ((this.binding.tagBits & TagBits.IsNullnessKnown) == 0) { + new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations) + .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope); + } + if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) { + if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) { + TypeVariableBinding[] typeVariables = this.binding.original().typeVariables(); + for (int i = 0; i < this.typeArguments.length; i++) + this.typeArguments[i].checkNullConstraints(scope, typeVariables, i); + } + } } //{ObjectTeams: may need to wrap the resolved type this.resolvedType = RoleTypeCreator.maybeWrapUnqualifiedRoleType(this.resolvedType, scope, this); @@ -914,7 +924,7 @@ public TypeBinding invocationTargetType() { } public boolean statementExpression() { - return true; + return ((this.bits & ASTNode.ParenthesizedMASK) == 0); } //-- interface Invocation: -- diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java index cc8bae713..2a2638004 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java @@ -56,6 +56,7 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutB * * Annotation */ +@SuppressWarnings({"rawtypes", "unchecked"}) public abstract class Annotation extends Expression { Annotation persistibleAnnotation = this; // Emit this into class file, unless this is a repeating annotation, in which case package this into the designated container. @@ -987,37 +988,13 @@ public abstract class Annotation extends Expression { return this.resolvedType; } - static boolean isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) { - long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference - if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { - // does not specify any target restriction - all locations supported in Java 7 and before are possible - if (kind == Binding.TYPE_PARAMETER || kind == Binding.TYPE_USE) { - scope.problemReporter().explitAnnotationTargetRequired(annotation); - } - return true; - } - - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391201 - if ((metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0 - && (metaTagBits & (TagBits.AnnotationForTypeUse | TagBits.AnnotationForTypeParameter)) != 0) { - if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) { - switch (kind) { - case Binding.PACKAGE : - case Binding.TYPE : - case Binding.GENERIC_TYPE : - case Binding.METHOD : - case Binding.FIELD : - case Binding.LOCAL : - scope.problemReporter().invalidUsageOfTypeAnnotations(annotation); - } - } - } + private static boolean isAnnotationTargetAllowed(Binding recipient, BlockScope scope, TypeBinding annotationType, int kind, long metaTagBits) { switch (kind) { case Binding.PACKAGE : if ((metaTagBits & TagBits.AnnotationForPackage) != 0) return true; else if (scope.compilerOptions().sourceLevel <= ClassFileConstants.JDK1_6) { - SourceTypeBinding sourceType = (SourceTypeBinding) annotation.recipient; + SourceTypeBinding sourceType = (SourceTypeBinding) recipient; if (CharOperation.equals(sourceType.sourceName, TypeConstants.PACKAGE_INFO_NAME)) return true; } @@ -1034,18 +1011,18 @@ public abstract class Annotation extends Expression { break; case Binding.TYPE : case Binding.GENERIC_TYPE : - if (((ReferenceBinding)annotation.recipient).isAnnotationType()) { + if (((ReferenceBinding)recipient).isAnnotationType()) { if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) return true; } else if ((metaTagBits & (TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) { return true; } else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) { - if (CharOperation.equals(((ReferenceBinding) annotation.recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME)) + if (CharOperation.equals(((ReferenceBinding) recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME)) return true; } //{ObjectTeams: allow @Override for roles: - if ( (((ReferenceBinding)annotation.recipient).isRole()) - && (annotation.resolvedType.id == TypeIds.T_JavaLangOverride)) + if ( (((ReferenceBinding)recipient).isRole()) + && (annotationType.id == TypeIds.T_JavaLangOverride)) return true; //SH} break; @@ -1057,7 +1034,7 @@ public abstract class Annotation extends Expression { break; //SH} case Binding.METHOD : - MethodBinding methodBinding = (MethodBinding) annotation.recipient; + MethodBinding methodBinding = (MethodBinding) recipient; if (methodBinding.isConstructor()) { if ((metaTagBits & (TagBits.AnnotationForConstructor | TagBits.AnnotationForTypeUse)) != 0) return true; @@ -1075,7 +1052,7 @@ public abstract class Annotation extends Expression { if ((metaTagBits & TagBits.AnnotationForField) != 0) { return true; } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - FieldBinding sourceField = (FieldBinding) annotation.recipient; + FieldBinding sourceField = (FieldBinding) recipient; SourceTypeBinding sourceType = (SourceTypeBinding) sourceField.declaringClass; FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField); if (isTypeUseCompatible(fieldDeclaration.type, scope)) { @@ -1084,7 +1061,7 @@ public abstract class Annotation extends Expression { } break; case Binding.LOCAL : - LocalVariableBinding localVariableBinding = (LocalVariableBinding) annotation.recipient; + LocalVariableBinding localVariableBinding = (LocalVariableBinding) recipient; if ((localVariableBinding.tagBits & TagBits.IsArgument) != 0) { if ((metaTagBits & TagBits.AnnotationForParameter) != 0) { return true; @@ -1110,6 +1087,43 @@ public abstract class Annotation extends Expression { return false; } + public static boolean isAnnotationTargetAllowed(BlockScope scope, TypeBinding annotationType, Binding recipient) { + long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference + if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { + return true; + } + return isAnnotationTargetAllowed(recipient, scope, annotationType, recipient.kind(), metaTagBits); + } + + static boolean isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) { + + long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference + if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { + // does not specify any target restriction - all locations supported in Java 7 and before are possible + if (kind == Binding.TYPE_PARAMETER || kind == Binding.TYPE_USE) { + scope.problemReporter().explitAnnotationTargetRequired(annotation); + } + return true; + } + + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391201 + if ((metaTagBits & TagBits.SE7AnnotationTargetMASK) == 0 + && (metaTagBits & (TagBits.AnnotationForTypeUse | TagBits.AnnotationForTypeParameter)) != 0) { + if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) { + switch (kind) { + case Binding.PACKAGE : + case Binding.TYPE : + case Binding.GENERIC_TYPE : + case Binding.METHOD : + case Binding.FIELD : + case Binding.LOCAL : + scope.problemReporter().invalidUsageOfTypeAnnotations(annotation); + } + } + } + return isAnnotationTargetAllowed(annotation.recipient, scope, annotationType, kind, metaTagBits); + } + static void checkAnnotationTarget(Annotation annotation, BlockScope scope, ReferenceBinding annotationType, int kind, Binding recipient, long tagBitsToRevert) { // check (meta)target compatibility if (!annotationType.isValidBinding()) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java index c6e5fead0..b842bd35e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Assignment.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -30,6 +30,7 @@ * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) * Bug 453483 - [compiler][null][loop] Improve null analysis for loops + * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -194,6 +195,8 @@ FieldBinding getLastField(Expression someExpression) { } public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { + if ((this.implicitConversion & TypeIds.BOXING) != 0) + return FlowInfo.NON_NULL; return this.expression.nullStatus(flowInfo, flowContext); } @@ -336,6 +339,6 @@ public LocalVariableBinding localVariableBinding() { return this.lhs.localVariableBinding(); } public boolean statementExpression() { - return true; + return ((this.bits & ASTNode.ParenthesizedMASK) == 0); } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java index c42e78067..4e740a628 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Block.java @@ -15,6 +15,7 @@ * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" * bug 383368 - [compiler][null] syntactic null analysis for field references * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check + * Bug 440282 - [resource] Resource leak detection false negative with empty finally block *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -60,9 +61,11 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl flowContext.expireNullCheckedFieldInfo(); } } - if (this.explicitDeclarations > 0) { - // if block has its own scope analyze tracking vars now: + if (this.scope != currentScope) { + // if block is tracking any resources other than the enclosing 'currentScope', analyse them now: this.scope.checkUnclosedCloseables(flowInfo, flowContext, null, null); + } + if (this.explicitDeclarations > 0) { // cleanup assignment info for locals that are scoped to this block: LocalVariableBinding[] locals = this.scope.locals; if (locals != null) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java index bd9b012c1..97a4a1d3a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -24,6 +24,7 @@ * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) * Bug 430150 - [1.8][null] stricter checking against type variables * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations + * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 415541 - [1.8][compiler] Type annotations in the body of static initializer get dropped *******************************************************************************/ @@ -591,6 +592,8 @@ public LocalVariableBinding localVariableBinding() { } public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { + if ((this.implicitConversion & TypeIds.BOXING) != 0) + return FlowInfo.NON_NULL; return this.expression.nullStatus(flowInfo, flowContext); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java index 079a10870..d285c6d72 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -24,6 +24,7 @@ * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) * Bug 418537 - [1.8][null] Fix null type annotation analysis for poly conditional expressions * Bug 428352 - [1.8][compiler] Resolution errors don't always surface + * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -418,6 +419,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, } public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { + if ((this.implicitConversion & TypeIds.BOXING) != 0) + return FlowInfo.NON_NULL; return this.nullStatus; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java index 6cf57e7fa..6ef6d1de0 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -24,6 +24,8 @@ * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 415399 - [1.8][compiler] Type annotations on constructor results dropped by the code generator + * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for + * bug 386692 - Missing "unused" warning on "autowired" fields *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -379,6 +381,14 @@ boolean isValueProvidedUsingAnnotation(FieldDeclaration fieldDecl) { if (CharOperation.equals(memberValuePairs[j].name, TypeConstants.OPTIONAL)) return memberValuePairs[j].value instanceof FalseLiteral; } + } else if (annotation.resolvedType.id == TypeIds.T_OrgSpringframeworkBeansFactoryAnnotationAutowired) { + MemberValuePair[] memberValuePairs = annotation.memberValuePairs(); + if (memberValuePairs == Annotation.NoValuePairs) + return true; + for (int j = 0; j < memberValuePairs.length; j++) { + if (CharOperation.equals(memberValuePairs[j].name, TypeConstants.REQUIRED)) + return memberValuePairs[j].value instanceof TrueLiteral; + } } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java index 45b882b53..1a1f7878a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2014 GK Software AG and others. + * Copyright (c) 2011, 2015 GK Software AG 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 @@ -13,7 +13,9 @@ package org.eclipse.jdt.internal.compiler.ast; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -33,6 +35,7 @@ import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.Scope; +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.TypeIds; @@ -182,6 +185,8 @@ public class FakedTrackingVariable extends LocalDeclaration { return local.closeTracker; if (!isAnyCloseable(expression.resolvedType)) return null; + if ((local.tagBits & TagBits.IsResource) != 0) + return null; // tracking var doesn't yet exist. This happens in finally block // which is analyzed before the corresponding try block Statement location = local.declaration; @@ -237,6 +242,8 @@ public class FakedTrackingVariable extends LocalDeclaration { ConditionalExpression conditional = (ConditionalExpression) location; return containsAllocation(conditional.valueIfTrue) || containsAllocation(conditional.valueIfFalse); } + if (location instanceof CastExpression) + return containsAllocation(((CastExpression) location).expression); return false; } @@ -246,6 +253,8 @@ public class FakedTrackingVariable extends LocalDeclaration { preConnectTrackerAcrossAssignment(location, local, flowInfo, (AllocationExpression) expression, closeTracker); } else if (expression instanceof ConditionalExpression) { preConnectTrackerAcrossAssignment(location, local, flowInfo, (ConditionalExpression) expression, closeTracker); + } else if (expression instanceof CastExpression) { + preConnectTrackerAcrossAssignment(location, local, ((CastExpression) expression).expression, flowInfo); } } @@ -273,7 +282,7 @@ public class FakedTrackingVariable extends LocalDeclaration { if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitResourceFreeCloseable)) { // remove unnecessary attempts (closeable is not relevant) if (allocation.closeTracker != null) { - scope.removeTrackingVar(allocation.closeTracker); + allocation.closeTracker.withdraw(); allocation.closeTracker = null; } } else if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable)) { @@ -328,7 +337,7 @@ public class FakedTrackingVariable extends LocalDeclaration { if (isWrapper) { // remove unnecessary attempts (wrapper has no relevant inner) if (allocation.closeTracker != null) { - scope.removeTrackingVar(allocation.closeTracker); + allocation.closeTracker.withdraw(); allocation.closeTracker = null; } } else { @@ -353,7 +362,7 @@ public class FakedTrackingVariable extends LocalDeclaration { } private static FakedTrackingVariable pick(FakedTrackingVariable tracker1, FakedTrackingVariable tracker2, BlockScope scope) { - scope.removeTrackingVar(tracker2); + tracker2.withdraw(); return tracker1; } @@ -600,14 +609,14 @@ public class FakedTrackingVariable extends LocalDeclaration { if (expression instanceof AllocationExpression) { FakedTrackingVariable tracker = ((AllocationExpression) expression).closeTracker; if (tracker != null && tracker.originalBinding == null) { - currentScope.removeTrackingVar(tracker); + tracker.withdraw(); ((AllocationExpression) expression).closeTracker = null; } } else { // assignment passing a local into a field? LocalVariableBinding local = expression.localVariableBinding(); if (local != null && local.closeTracker != null && ((lhsBits & Binding.FIELD) != 0)) - currentScope.removeTrackingVar(local.closeTracker); // TODO: may want to use local.closeTracker.markPassedToOutside(..,true) + local.closeTracker.withdraw(); // TODO: may want to use local.closeTracker.markPassedToOutside(..,true) } } @@ -686,7 +695,7 @@ public class FakedTrackingVariable extends LocalDeclaration { int finallyStatus = currentScope.finallyInfo.nullStatus(local); if (finallyStatus == FlowInfo.NON_NULL) return finallyStatus; - if (finallyStatus != FlowInfo.NULL) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL + if (finallyStatus != FlowInfo.NULL && currentScope.finallyInfo.hasNullInfoFor(local)) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL status = FlowInfo.POTENTIALLY_NULL; } if (currentScope != outerScope && currentScope.parent instanceof BlockScope) @@ -701,7 +710,7 @@ public class FakedTrackingVariable extends LocalDeclaration { do { flowInfo.markAsDefinitelyNonNull(current.binding); current.globalClosingState |= CLOSE_SEEN; - flowContext.markFinallyNullStatus(this.binding, FlowInfo.NON_NULL); + flowContext.markFinallyNullStatus(current.binding, FlowInfo.NON_NULL); current = current.innerTracker; } while (current != null); } @@ -739,44 +748,100 @@ public class FakedTrackingVariable extends LocalDeclaration { return flowInfo; } - /** - * Pick tracking variables from 'varsOfScope' to establish a proper order of processing: - * As much as possible pick wrapper resources before their inner resources. - * Also consider cases of wrappers and their inners being declared at different scopes. + /** + * Iterator for a set of FakedTrackingVariable, which dispenses the elements + * according to the priorities defined by enum {@link Stage}. + * Resources whose outer is owned by an enclosing scope are never answered, + * unless we are analysing on behalf of an exit (return/throw). */ - public static FakedTrackingVariable pickVarForReporting(Set varsOfScope, BlockScope scope, boolean atExit) { - if (varsOfScope.isEmpty()) return null; - FakedTrackingVariable trackingVar = (FakedTrackingVariable) varsOfScope.iterator().next(); - while (trackingVar.outerTracker != null) { - // resource is wrapped, is wrapper defined in this scope? - if (varsOfScope.contains(trackingVar.outerTracker)) { - // resource from same scope, travel up the wrapper chain - trackingVar = trackingVar.outerTracker; - } else if (atExit) { - // at an exit point we report against inner despite a wrapper that may/may not be closed later - break; - } else { - BlockScope outerTrackerScope = trackingVar.outerTracker.binding.declaringScope; - if (outerTrackerScope == scope) { - // outerTracker is from same scope and already processed -> pick trackingVar now - break; - } else { - // outer resource is from other (outer?) scope - Scope currentScope = scope; - while ((currentScope = currentScope.parent) instanceof BlockScope) { - if (outerTrackerScope == currentScope) { - // at end of block pass responsibility for inner resource to outer scope holding a wrapper - varsOfScope.remove(trackingVar); // drop this one - // pick a next candidate: - return pickVarForReporting(varsOfScope, scope, atExit); + public static class IteratorForReporting implements Iterator<FakedTrackingVariable> { + + private final Set<FakedTrackingVariable> varSet; + private final Scope scope; + private final boolean atExit; + + private Stage stage; + private Iterator<FakedTrackingVariable> iterator; + private FakedTrackingVariable next; + + enum Stage { + /** 1. prio: all top-level resources, ie., resources with no outer. */ + OuterLess, + /** 2. prio: resources whose outer has already been processed (element of the same varSet). */ + InnerOfProcessed, + /** 3. prio: resources whose outer is not owned by any enclosing scope. */ + InnerOfNotEnclosing, + /** 4. prio: when analysing on behalf of an exit point: anything not picked before. */ + AtExit + } + + public IteratorForReporting(List<FakedTrackingVariable> variables, Scope scope, boolean atExit) { + this.varSet = new HashSet<>(variables); + this.scope = scope; + this.atExit = atExit; + setUpForStage(Stage.OuterLess); + } + @Override + public boolean hasNext() { + FakedTrackingVariable trackingVar; + switch (this.stage) { + case OuterLess: + while (this.iterator.hasNext()) { + trackingVar = this.iterator.next(); + if (trackingVar.outerTracker == null) + return found(trackingVar); + } + setUpForStage(Stage.InnerOfProcessed); + //$FALL-THROUGH$ + case InnerOfProcessed: + while (this.iterator.hasNext()) { + trackingVar = this.iterator.next(); + FakedTrackingVariable outer = trackingVar.outerTracker; + if (outer.binding.declaringScope == this.scope && !this.varSet.contains(outer)) + return found(trackingVar); + } + setUpForStage(Stage.InnerOfNotEnclosing); + //$FALL-THROUGH$ + case InnerOfNotEnclosing: + searchAlien: while (this.iterator.hasNext()) { + trackingVar = this.iterator.next(); + FakedTrackingVariable outer = trackingVar.outerTracker; + if (!this.varSet.contains(outer)) { + Scope outerTrackerScope = outer.binding.declaringScope; + Scope currentScope = this.scope; + while ((currentScope = currentScope.parent) instanceof BlockScope) { + if (outerTrackerScope == currentScope) + break searchAlien; + } + return found(trackingVar); } } - break; // not parent owned -> pick this var - } + setUpForStage(Stage.AtExit); + //$FALL-THROUGH$ + case AtExit: + if (this.atExit && this.iterator.hasNext()) + return found(this.iterator.next()); + return false; + default: throw new IllegalStateException("Unexpected Stage "+this.stage); //$NON-NLS-1$ } } - varsOfScope.remove(trackingVar); - return trackingVar; + private boolean found(FakedTrackingVariable trackingVar) { + this.iterator.remove(); + this.next = trackingVar; + return true; + } + private void setUpForStage(Stage nextStage) { + this.iterator = this.varSet.iterator(); + this.stage = nextStage; + } + @Override + public FakedTrackingVariable next() { + return this.next; + } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } } /** @@ -824,6 +889,11 @@ public class FakedTrackingVariable extends LocalDeclaration { return false; } + public void withdraw() { + // must unregister at the declaringScope, note that twr resources are owned by the scope enclosing the twr + this.binding.declaringScope.removeTrackingVar(this); + } + public void recordErrorLocation(ASTNode location, int nullStatus) { if ((this.globalClosingState & OWNED_BY_OUTSIDE) != 0) { return; @@ -833,14 +903,20 @@ public class FakedTrackingVariable extends LocalDeclaration { this.recordedLocations.put(location, new Integer(nullStatus)); } - public boolean reportRecordedErrors(Scope scope, int mergedStatus) { + public boolean reportRecordedErrors(Scope scope, int mergedStatus, boolean atDeadEnd) { FakedTrackingVariable current = this; while (current.globalClosingState == 0) { current = current.innerTracker; if (current == null) { // no relevant state found -> report: - reportError(scope.problemReporter(), null, mergedStatus); - return true; + if (atDeadEnd && neverClosedAtLocations()) + mergedStatus = FlowInfo.NULL; + if ((mergedStatus & (FlowInfo.NULL|FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0) { + reportError(scope.problemReporter(), null, mergedStatus); + return true; + } else { + break; + } } } boolean hasReported = false; @@ -863,6 +939,15 @@ public class FakedTrackingVariable extends LocalDeclaration { return hasReported; } + private boolean neverClosedAtLocations() { + if (this.recordedLocations != null) { + for (Object value : this.recordedLocations.values()) + if (!value.equals(FlowInfo.NULL)) + return false; + } + return true; + } + public int reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) { if ((this.globalClosingState & OWNED_BY_OUTSIDE) != 0) { return 0; // TODO: should we still propagate some flags?? @@ -903,14 +988,6 @@ public class FakedTrackingVariable extends LocalDeclaration { } } - public void resetReportingBits() { - FakedTrackingVariable current = this; - do { - current.globalClosingState &= ~(REPORTED_POTENTIAL_LEAK|REPORTED_DEFINITIVE_LEAK); - current = current.innerTracker; - } while (current != null); - } - public String nameForReporting(ASTNode location, ReferenceContext referenceContext) { if (this.name == UNASSIGNED_CLOSEABLE_NAME) { if (location != null && referenceContext != null) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java index 3796302b1..3e72271f8 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Initializer.java @@ -1,15 +1,17 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2015 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: + *Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for + * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; +import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.*; @@ -24,6 +26,8 @@ public class Initializer extends FieldDeclaration { public int bodyStart; public int bodyEnd; + private MethodBinding methodBinding; + public Initializer(Block block, int modifiers) { this.block = block; this.modifiers = modifiers; @@ -126,6 +130,17 @@ public class Initializer extends FieldDeclaration { } } + /** Method used only by DOM to support bindings of initializers. */ + public MethodBinding getMethodBinding() { + if (this.methodBinding == null) { + Scope scope = this.block.scope; + this.methodBinding = isStatic() + ? new MethodBinding(ClassFileConstants.AccStatic, CharOperation.NO_CHAR, TypeBinding.VOID, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, scope.enclosingSourceType()) + : new MethodBinding(0, CharOperation.NO_CHAR, TypeBinding.VOID, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, scope.enclosingSourceType()); + } + return this.methodBinding; + } + public void traverse(ASTVisitor visitor, MethodScope scope) { if (visitor.visit(this, scope)) { if (this.block != null) this.block.traverse(visitor, scope); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java index fd8c73f25..1d7dbf489 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java @@ -52,6 +52,7 @@ * Bug 441734 - [1.8][inference] Generic method with nested parameterized type argument fails on method reference * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression * Bug 456487 - [1.8][null] @Nullable type variant of @NonNull-constrained type parameter causes grief + * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null * Jesper S Moller - Contributions for * Bug 378674 - "The method can be declared as static" is wrong * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for @@ -736,6 +737,8 @@ public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo f // SH} } public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { + if ((this.implicitConversion & TypeIds.BOXING) != 0) + return FlowInfo.NON_NULL; if (this.binding.isValidBinding()) { // try to retrieve null status of this message send from an annotation of the called method: long tagBits = this.binding.tagBits; @@ -1632,7 +1635,7 @@ public void traverse(ASTVisitor visitor, BlockScope blockScope) { visitor.endVisit(this, blockScope); } public boolean statementExpression() { - return true; + return ((this.bits & ASTNode.ParenthesizedMASK) == 0); } public boolean receiverIsImplicitThis() { return this.receiver.isImplicitThis(); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java index c090aaaa9..31ebefe7e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java @@ -53,6 +53,7 @@ import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier; import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; @@ -64,6 +65,7 @@ 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.TypeIds; +import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; import org.eclipse.objectteams.otdt.internal.core.compiler.ast.ConstructorDecapsulationException; import org.eclipse.objectteams.otdt.internal.core.compiler.ast.OTQualifiedAllocationExpression; import org.eclipse.objectteams.otdt.internal.core.compiler.control.Dependencies; @@ -361,9 +363,18 @@ public static abstract class AbstractQualifiedAllocationExpression extends Alloc TypeBinding result = resolveTypeForQualifiedAllocationExpression(scope); if (result != null && !result.isPolyType() && this.binding != null) { final CompilerOptions compilerOptions = scope.compilerOptions(); - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && (this.binding.tagBits & TagBits.IsNullnessKnown) == 0) { - new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations) - .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope); + if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { + if ((this.binding.tagBits & TagBits.IsNullnessKnown) == 0) { + new ImplicitNullAnnotationVerifier(scope.environment(), compilerOptions.inheritNullAnnotations) + .checkImplicitNullAnnotations(this.binding, null/*srcMethod*/, false, scope); + } + if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) { + if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) { + TypeVariableBinding[] typeVariables = this.binding.original().typeVariables(); + for (int i = 0; i < this.typeArguments.length; i++) + this.typeArguments[i].checkNullConstraints(scope, typeVariables, i); + } + } } } return result; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java index 96ebe04ae..281de66ff 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -17,6 +17,7 @@ * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis * Bug 411964 - [1.8][null] leverage null type annotation in foreach statement + * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -157,6 +158,8 @@ public FieldBinding lastFieldBinding() { } public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { + if ((this.implicitConversion & TypeIds.BOXING) != 0) + return FlowInfo.NON_NULL; FieldBinding fieldBinding = lastFieldBinding(); if (fieldBinding != null) { if (fieldBinding.isNonNull() || flowContext.isNullcheckedFieldAccess(this)) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java index a7adb889c..a4b0a2c6b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java @@ -34,6 +34,7 @@ * Bug 438945 - [1.8] NullPointerException InferenceContext18.checkExpression in java 8 with generics, primitives, and overloading * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression * Bug 448709 - [1.8][null] ensure we don't infer types that violate null constraints on a type parameter's bound + * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf() * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contribution for * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) *******************************************************************************/ @@ -57,6 +58,7 @@ import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; @@ -576,6 +578,7 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx scope.problemReporter().constructedArrayIncompatible(this, lhsType, this.descriptor.returnType); return this.resolvedType = null; } + checkNullAnnotations(scope); return this.resolvedType; } @@ -697,44 +700,7 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx } scope.problemReporter().unhandledException(methodExceptions[i], this); } - if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) { - if (this.expectedType == null || !NullAnnotationMatching.hasContradictions(this.expectedType)) { // otherwise assume it has been reported and we can do nothing here - // TODO: simplify by using this.freeParameters? - int len; - int expectedlen = this.binding.parameters.length; - int providedLen = this.descriptor.parameters.length; - if (this.receiverPrecedesParameters) - providedLen--; // one parameter is 'consumed' as the receiver - boolean isVarArgs = false; - if (this.binding.isVarargs()) { - isVarArgs = (providedLen == expectedlen) - ? !this.descriptor.parameters[expectedlen-1].isCompatibleWith(this.binding.parameters[expectedlen-1]) - : true; - len = providedLen; // binding parameters will be padded from InferenceContext18.getParameter() - } else { - len = Math.min(expectedlen, providedLen); - } - for (int i = 0; i < len; i++) { - TypeBinding descriptorParameter = this.descriptor.parameters[i + (this.receiverPrecedesParameters ? 1 : 0)]; - TypeBinding bindingParameter = InferenceContext18.getParameter(this.binding.parameters, i, isVarArgs); - NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(bindingParameter, descriptorParameter, FlowInfo.UNKNOWN); - if (annotationStatus.isAnyMismatch()) { - // immediate reporting: - scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, bindingParameter, descriptorParameter, this.descriptor, i, annotationStatus); - } - } - if (!this.binding.isConstructor() && (this.descriptor.returnType.tagBits & TagBits.AnnotationNonNull) != 0) { - // since constructors never return null we don't have to check those anyway. - if ((this.binding.returnType.tagBits & TagBits.AnnotationNonNull) == 0) { - char[][] providedAnnotationName = ((this.binding.returnType.tagBits & TagBits.AnnotationNullable) != 0) ? - scope.environment().getNullableAnnotationName() : null; - scope.problemReporter().illegalReturnRedefinition(this, this.descriptor, - scope.environment().getNonNullAnnotationName(), - providedAnnotationName, this.binding.returnType); - } - } - } - } + checkNullAnnotations(scope); this.freeParameters = null; // not used after method lookup if (checkInvocationArguments(scope, null, this.receiverType, this.binding, null, descriptorParameters, false, this)) @@ -771,6 +737,45 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx return this.resolvedType; // Phew ! } + protected void checkNullAnnotations(BlockScope scope) { + if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) { + if (this.expectedType == null || !NullAnnotationMatching.hasContradictions(this.expectedType)) { // otherwise assume it has been reported and we can do nothing here + // TODO: simplify by using this.freeParameters? + int len; + int expectedlen = this.binding.parameters.length; + int providedLen = this.descriptor.parameters.length; + if (this.receiverPrecedesParameters) + providedLen--; // one parameter is 'consumed' as the receiver + boolean isVarArgs = false; + if (this.binding.isVarargs()) { + isVarArgs = (providedLen == expectedlen) + ? !this.descriptor.parameters[expectedlen-1].isCompatibleWith(this.binding.parameters[expectedlen-1]) + : true; + len = providedLen; // binding parameters will be padded from InferenceContext18.getParameter() + } else { + len = Math.min(expectedlen, providedLen); + } + for (int i = 0; i < len; i++) { + TypeBinding descriptorParameter = this.descriptor.parameters[i + (this.receiverPrecedesParameters ? 1 : 0)]; + TypeBinding bindingParameter = InferenceContext18.getParameter(this.binding.parameters, i, isVarArgs); + NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(bindingParameter, descriptorParameter, FlowInfo.UNKNOWN); + if (annotationStatus.isAnyMismatch()) { + // immediate reporting: + scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, bindingParameter, descriptorParameter, this.descriptor, i, annotationStatus); + } + } + TypeBinding returnType = this.binding.returnType; + if (this.binding.isConstructor() || this.binding == scope.environment().arrayClone) { + returnType = scope.environment().createAnnotatedType(this.receiverType, new AnnotationBinding[]{ scope.environment().getNonNullAnnotation() }); + } + NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(this.descriptor.returnType, returnType, FlowInfo.UNKNOWN); + if (annotationStatus.isAnyMismatch()) { + scope.problemReporter().illegalReturnRedefinition(this, this.descriptor, annotationStatus.isUnchecked(), returnType); + } + } + } + } + private TypeBinding[] descriptorParametersAsArgumentExpressions() { if (this.descriptor == null || this.descriptor.parameters == null || this.descriptor.parameters.length == 0) @@ -950,7 +955,15 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx @Override public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) { - + + final boolean isConstructorRef = isConstructorReference(); + if (isConstructorRef && this.receiverType.isArrayType()) { + final TypeBinding leafComponentType = this.receiverType.leafComponentType(); + if (!leafComponentType.isReifiable()) { + return false; + } + } + // We get here only when the reference expression is NOT pertinent to applicability. if (!super.isPertinentToApplicability(targetType, null)) return true; @@ -980,14 +993,12 @@ public class ReferenceExpression extends FunctionalExpression implements IPolyEx } // 15.13.1 - final boolean isMethodReference = isMethodReference(); this.freeParameters = descriptorParameters; this.checkingPotentialCompatibility = true; try { - MethodBinding compileTimeDeclaration = - this.exactMethodBinding != null ? this.exactMethodBinding : - isMethodReference ? scope.getMethod(this.receiverType, this.selector, descriptorParameters, this) : - scope.getConstructor((ReferenceBinding) this.receiverType, descriptorParameters, this); + MethodBinding compileTimeDeclaration = this.exactMethodBinding != null ? this.exactMethodBinding : isConstructorRef + ? scope.getConstructor((ReferenceBinding) this.receiverType, descriptorParameters, this) + : scope.getMethod(this.receiverType, this.selector, descriptorParameters, this); if (compileTimeDeclaration != null && compileTimeDeclaration.isValidBinding()) // we have the mSMB. this.potentialMethods = new MethodBinding [] { compileTimeDeclaration }; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java index bd01f4043..89e198fec 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -324,6 +324,9 @@ public void resolve(BlockScope scope) { if (this.expression != null) { this.expression.setExpressionContext(ASSIGNMENT_CONTEXT); this.expression.setExpectedType(methodType); + if (lambda != null && lambda.argumentsTypeElided() && this.expression instanceof CastExpression) { + this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck; + } } if (methodType == TypeBinding.VOID) { @@ -370,9 +373,14 @@ public void resolve(BlockScope scope) { if (expressionType.needsUncheckedConversion(methodType)) { scope.problemReporter().unsafeTypeConversion(this.expression, expressionType, methodType); } - if (this.expression instanceof CastExpression - && (this.expression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { - CastExpression.checkNeedForAssignedCast(scope, methodType, (CastExpression) this.expression); + if (this.expression instanceof CastExpression) { + if ((this.expression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { + CastExpression.checkNeedForAssignedCast(scope, methodType, (CastExpression) this.expression); + } else if (lambda != null && lambda.argumentsTypeElided() && (this.expression.bits & ASTNode.UnnecessaryCast) != 0) { + if (TypeBinding.equalsEquals(((CastExpression)this.expression).expression.resolvedType, methodType)) { + scope.problemReporter().unnecessaryCast((CastExpression)this.expression); + } + } } return; } else if (isBoxingCompatible(expressionType, methodType, this.expression, scope)) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java index db38143a0..1950dde5f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java @@ -16,8 +16,9 @@ * bug 383368 - [compiler][null] syntactic null analysis for field references * Bug 412203 - [compiler] Internal compiler error: java.lang.IllegalArgumentException: info cannot be null * Bug 458396 - NPE in CodeStream.invoke() + * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null * Jesper S Moller - <jesper@selskabet.org> - Contributions for - * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment + * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment * bug 378674 - "The method can be declared as static" is wrong * bug 404657 - [1.8][compiler] Analysis for effectively final variables fails to consider loops *******************************************************************************/ @@ -901,6 +902,8 @@ public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotatio } public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { + if ((this.implicitConversion & TypeIds.BOXING) != 0) + return FlowInfo.NON_NULL; LocalVariableBinding local = localVariableBinding(); if (local != null) { return flowInfo.nullStatus(local); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java index 65c07a76b..6b1a1ecaa 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TryStatement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -22,6 +22,8 @@ * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check * bug 384380 - False positive on a ?? Potential null pointer access ?? after a continue * Bug 415790 - [compiler][resource]Incorrect potential resource leak warning in for loop with close in try/catch + * Bug 371614 - [compiler][resource] Wrong "resource leak" problem on return/throw inside while loop + * Bug 444964 - [1.7+][resource] False resource leak warning (try-with-resources for ByteArrayOutputStream - return inside for loop) * Jesper Steen Moller - Contributions for * bug 404146 - [1.7][compiler] nested try-catch-finally-blocks leads to unrunnable Java byte code * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for @@ -165,8 +167,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl resourceBinding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways. if (resourceBinding.closeTracker != null) { // this was false alarm, we don't need to track the resource - this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker); - // keep the tracking variable in the resourceBinding in order to prevent creating a new one while analyzing the try block + resourceBinding.closeTracker.withdraw(); + resourceBinding.closeTracker = null; } MethodBinding closeMethod = findCloseMethod(resource, resourceBinding); if (closeMethod != null && closeMethod.isValidBinding() && closeMethod.returnType.id == TypeIds.T_void) { @@ -279,7 +281,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl resourceBinding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways. if (resourceBinding.closeTracker != null) { // this was false alarm, we don't need to track the resource - this.tryBlock.scope.removeTrackingVar(resourceBinding.closeTracker); + resourceBinding.closeTracker.withdraw(); // keep the tracking variable in the resourceBinding in order to prevent creating a new one while analyzing the try block } MethodBinding closeMethod = findCloseMethod(resource, resourceBinding); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java index 27b11b37e..87e1254c2 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ExceptionHandlingFlowContext.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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,7 @@ * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check * Bug 453483 - [compiler][null][loop] Improve null analysis for loops + * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment *******************************************************************************/ package org.eclipse.jdt.internal.compiler.flow; @@ -83,6 +84,7 @@ public ExceptionHandlingFlowContext( UnconditionalFlowInfo unconditionalCopy = flowInfo.unconditionalCopy(); unconditionalCopy.iNBit = -1L; unconditionalCopy.iNNBit = -1L; + unconditionalCopy.tagBits |= FlowInfo.UNROOTED; this.initsOnFinally = unconditionalCopy; } ExceptionHandlingFlowContext( diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java index 7cecbc2b3..f1e5d4357 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -14,6 +14,7 @@ * bug 332637 - Dead Code detection removing code that isn't dead * bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional * Bug 411964 - [1.8][null] leverage null type annotation in foreach statement + * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment *******************************************************************************/ package org.eclipse.jdt.internal.compiler.flow; @@ -61,6 +62,8 @@ public abstract class FlowInfo { public final static int POTENTIALLY_NULL = 16; public final static int POTENTIALLY_NON_NULL = 32; + public final static int UNROOTED = 64; // marks a flowInfo that may be appended to another flowInfo (accepting incoming nulls/nonnulls, see UFI.iNBit/iNNBit). + public static final UnconditionalFlowInfo DEAD_END; // Represents a dead branch status of initialization static { DEAD_END = new UnconditionalFlowInfo(); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java index 210650cf7..3b49f1738 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LoopingFlowContext.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -23,6 +23,7 @@ * Bug 455557 - [jdt] NPE LoopingFlowContext.recordNullReference * Bug 455723 - Nonnull argument not correctly inferred in loop * Bug 415790 - [compiler][resource]Incorrect potential resource leak warning in for loop with close in try/catch + * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment * Jesper S Moller - contributions for * bug 404657 - [1.8][compiler] Analysis for effectively final variables fails to consider loops *******************************************************************************/ @@ -417,7 +418,7 @@ public void complainOnDeferredNullChecks(BlockScope scope, FlowInfo callerFlowIn } nullStatus = closeTracker.findMostSpecificStatus(flowInfo, scope, null); closeTracker.recordErrorLocation(this.nullReferences[i], nullStatus); - closeTracker.reportRecordedErrors(scope, nullStatus); + closeTracker.reportRecordedErrors(scope, nullStatus, flowInfo.reachMode() != FlowInfo.REACHABLE); this.nullReferences[i] = null; continue; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java index 8b68fd8ad..4e34ec5e8 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java @@ -21,6 +21,7 @@ * bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional * Bug 453483 - [compiler][null][loop] Improve null analysis for loops * Bug 454031 - [compiler][null][loop] bug in null analysis; wrong "dead code" detection + * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment *******************************************************************************/ package org.eclipse.jdt.internal.compiler.flow; @@ -440,10 +441,7 @@ public FlowInfo addPotentialInitializationsFrom(FlowInfo inits) { else if (otherInits.extra != null) { // no storage here, but other has extra storage. int otherLength = otherInits.extra[0].length; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[otherLength]; - } + createExtraSpace(otherLength); System.arraycopy(otherInits.extra[1], 0, this.extra[1], 0, otherLength); } @@ -528,10 +526,7 @@ public UnconditionalFlowInfo addPotentialNullInfoFrom( if (otherInits.extra != null) { int mergeLimit = 0, copyLimit = otherInits.extra[0].length; if (this.extra == null) { - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[copyLimit]; - } + createExtraSpace(copyLimit); if (COVERAGE_TEST_FLAG) { if (CoverageTestId == 11) { throw new AssertionFailedException("COVERAGE 11"); //$NON-NLS-1$ @@ -1188,10 +1183,7 @@ public void markAsComparedEqualToNonNull(LocalVariableBinding local) { int vectorIndex = (position / BitCacheSize) - 1; if (this.extra == null) { int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[length]; - } + createExtraSpace(length); if (COVERAGE_TEST_FLAG) { if (CoverageTestId == 16) { throw new AssertionFailedException("COVERAGE 16"); //$NON-NLS-1$ @@ -1287,10 +1279,7 @@ public void markAsComparedEqualToNull(LocalVariableBinding local) { mask = 1L << (position % BitCacheSize); if (this.extra == null) { int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[length ]; - } + createExtraSpace(length); if (COVERAGE_TEST_FLAG) { if(CoverageTestId == 20) { throw new AssertionFailedException("COVERAGE 20"); //$NON-NLS-1$ @@ -1355,10 +1344,7 @@ final private void markAsDefinitelyAssigned(int position) { int vectorIndex = (position / BitCacheSize) - 1; if (this.extra == null) { int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[length]; - } + createExtraSpace(length); } else { int oldLength; // might need to grow the arrays @@ -1416,10 +1402,7 @@ public void markAsDefinitelyNonNull(LocalVariableBinding local) { int vectorIndex = (position / BitCacheSize) - 1; if (this.extra == null) { int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[length]; - } + createExtraSpace(length); } else { int oldLength; // might need to grow the arrays @@ -1476,10 +1459,7 @@ public void markAsDefinitelyNull(LocalVariableBinding local) { int vectorIndex = (position / BitCacheSize) - 1; if (this.extra == null) { int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[length]; - } + createExtraSpace(length); } else { int oldLength; // might need to grow the arrays @@ -1543,10 +1523,7 @@ public void markAsDefinitelyUnknown(LocalVariableBinding local) { int vectorIndex = (position / BitCacheSize) - 1; if (this.extra == null) { int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[length]; - } + createExtraSpace(length); } else { int oldLength; // might need to grow the arrays @@ -1632,10 +1609,7 @@ public void markPotentiallyUnknownBit(LocalVariableBinding local) { int vectorIndex = (position / BitCacheSize) - 1; if (this.extra == null) { int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[length]; - } + createExtraSpace(length); } else { int oldLength; // might need to grow the arrays @@ -1682,10 +1656,7 @@ public void markPotentiallyNullBit(LocalVariableBinding local) { int vectorIndex = (position / BitCacheSize) - 1; if (this.extra == null) { int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[length]; - } + createExtraSpace(length); } else { int oldLength; // might need to grow the arrays @@ -1732,10 +1703,7 @@ public void markPotentiallyNonNullBit(LocalVariableBinding local) { int vectorIndex = (position / BitCacheSize) - 1; if (this.extra == null) { int length = vectorIndex + 1; - this.extra = new long[extraLength][]; - for (int j = 0; j < extraLength; j++) { - this.extra[j] = new long[length]; - } + createExtraSpace(length); } else { int oldLength; // might need to grow the arrays @@ -2055,6 +2023,7 @@ public UnconditionalFlowInfo nullInfoLessUnconditionalCopy() { copy.iNBit = -1L; copy.iNNBit = -1L; copy.tagBits = this.tagBits & ~NULL_FLAG_MASK; + copy.tagBits |= UNROOTED; copy.maxFieldCount = this.maxFieldCount; if (this.extra != null) { int length; @@ -2215,9 +2184,7 @@ public UnconditionalFlowInfo unconditionalFieldLessCopy() { } } else if (vectorIndex >= 0) { - for (int j = 0; j < extraLength; j++) { - copy.extra[j] = new long[length]; - } + copy.createExtraSpace(length); } if (vectorIndex >= 0) { mask = ~((1L << (limit % BitCacheSize))-1); @@ -2261,5 +2228,16 @@ public void resetAssignmentInfo(int position) { } } } + +private void createExtraSpace(int length) { + this.extra = new long[extraLength][]; + for (int j = 0; j < extraLength; j++) { + this.extra[j] = new long[length]; + } + if ((this.tagBits & UNROOTED) != 0) { + Arrays.fill(this.extra[IN], -1L); + Arrays.fill(this.extra[INN], -1L); + } +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java index a3bf693d8..29f431146 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Binding.java @@ -131,14 +131,14 @@ public abstract class Binding { public abstract int kind(); /* * Computes a key that uniquely identifies this binding. - * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding or a PackageBinding. + * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding, a LocalVariableBinding or a PackageBinding (i.e. an ImportBinding). */ public char[] computeUniqueKey() { return computeUniqueKey(true/*leaf*/); } /* * Computes a key that uniquely identifies this binding. Optionally include access flags. - * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding or a PackageBinding. + * Returns null if binding is not a TypeBinding, a MethodBinding, a FieldBinding, a LocalVariableBinding or a PackageBinding (i.e. an ImportBinding) */ public char[] computeUniqueKey(boolean isLeaf) { return null; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java index 68b171229..297d3f47a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BlockScope.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -20,6 +20,10 @@ * bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional * bug 404649 - [1.8][compiler] detect illegal reference to indirect or redundant super * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault + * Bug 371614 - [compiler][resource] Wrong "resource leak" problem on return/throw inside while loop + * Bug 421035 - [resource] False alarm of resource leak warning when casting a closeable in its assignment + * Bug 444964 - [1.7+][resource] False resource leak warning (try-with-resources for ByteArrayOutputStream - return inside for loop) + * Bug 396575 - [compiler][resources] Incorrect Errors/Warnings check for potential resource leak when surrounding with try-catch * Jesper S Moller <jesper@selskabet.org> - Contributions for * bug 378674 - "The method can be declared as static" is wrong * Keigo Imai - Contribution for bug 388903 - Cannot extend inner class as an anonymous class when it extends the outer class @@ -27,10 +31,9 @@ package org.eclipse.jdt.internal.compiler.lookup; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; -import java.util.Set; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.*; @@ -1212,7 +1215,7 @@ public int registerTrackingVariable(FakedTrackingVariable fakedTrackingVariable) /** When are no longer interested in this tracking variable - remove it. */ public void removeTrackingVar(FakedTrackingVariable trackingVariable) { if (trackingVariable.innerTracker != null) { - removeTrackingVar(trackingVariable.innerTracker); + trackingVariable.innerTracker.withdraw(); trackingVariable.innerTracker = null; } if (this.trackingVariables != null) @@ -1242,10 +1245,10 @@ public void checkUnclosedCloseables(FlowInfo flowInfo, FlowContext flowContext, FakedTrackingVariable returnVar = (location instanceof ReturnStatement) ? FakedTrackingVariable.getCloseTrackingVariable(((ReturnStatement)location).expression, flowInfo, flowContext) : null; - Set varSet = new HashSet(this.trackingVariables); - FakedTrackingVariable trackingVar; - // pick one outer-most variable from the set at a time - while ((trackingVar = FakedTrackingVariable.pickVarForReporting(varSet, this, location != null)) != null) { + // iterate variables according to the priorities defined in FakedTrackingVariable.IteratorForReporting.Stage + Iterator<FakedTrackingVariable> iterator = new FakedTrackingVariable.IteratorForReporting(this.trackingVariables, this, location != null); + while (iterator.hasNext()) { + FakedTrackingVariable trackingVar = iterator.next(); if (returnVar != null && trackingVar.isResourceBeingReturned(returnVar)) { continue; @@ -1270,7 +1273,7 @@ public void checkUnclosedCloseables(FlowInfo flowInfo, FlowContext flowContext, if (location == null) // at end of block and not definitely unclosed { // problems at specific locations: medium priority - if (trackingVar.reportRecordedErrors(this, status)) // ... report previously recorded errors + if (trackingVar.reportRecordedErrors(this, status, flowInfo.reachMode() != FlowInfo.REACHABLE)) // ... report previously recorded errors continue; } if (status == FlowInfo.POTENTIALLY_NULL) { @@ -1287,12 +1290,6 @@ public void checkUnclosedCloseables(FlowInfo flowInfo, FlowContext flowContext, for (int i=0; i<this.localIndex; i++) this.locals[i].closeTracker = null; this.trackingVariables = null; - } else { - int size = this.trackingVariables.size(); - for (int i=0; i<size; i++) { - FakedTrackingVariable tracker = (FakedTrackingVariable) this.trackingVariables.get(i); - tracker.resetReportingBits(); - } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java index 5e987f8ca..4ccb2663c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CaptureBinding.java @@ -14,6 +14,7 @@ * Bug 441797 - [1.8] synchronize type annotations on capture and its wildcard * Bug 456497 - [1.8][null] during inference nullness from target type is lost against weaker hint from applicability analysis * Bug 456924 - StackOverflowError during compilation + * Bug 462790 - [null] NPE in Expression.computeConversion() *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -49,6 +50,7 @@ public class CaptureBinding extends TypeVariableBinding { this.end = end; this.captureID = captureID; this.tagBits |= TagBits.HasCapturedWildcard; + this.cud = cud; if (wildcard.hasTypeAnnotations()) { // register an unannoted version before adding the annotated wildcard: CaptureBinding unannotated = (CaptureBinding) clone(null); @@ -64,7 +66,6 @@ public class CaptureBinding extends TypeVariableBinding { } else { computeId(this.environment); } - this.cud = cud; } // for subclass CaptureBinding18 @@ -440,6 +441,26 @@ public class CaptureBinding extends TypeVariableBinding { return this.wildcard; } + /* + * CaptureBinding needs even more propagation, because we are creating a naked type + * (during CaptureBinding(WildcardBinding,ReferenceBinding,int,int,ASTNode,int) + * that has no firstBound / superclass / superInterfaces set. + */ + @Override + protected TypeBinding[] getDerivedTypesForDeferredInitialization() { + TypeBinding[] derived = this.environment.typeSystem.getDerivedTypes(this); + if (derived.length > 0) { + int count = 0; + for (int i = 0; i < derived.length; i++) { + if (derived[i] != null && derived[i].id == this.id) + derived[count++] = derived[i]; + } + if (count < derived.length) + System.arraycopy(derived, 0, derived = new TypeBinding[count], 0, count); + } + return derived; + } + public String toString() { if (this.wildcard != null) { StringBuffer buffer = new StringBuffer(10); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java index 508c72d06..f76562d7f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -22,6 +22,7 @@ * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault * Bug 434570 - Generic type mismatch for parametrized class annotation attribute with inner class * Bug 444024 - [1.8][compiler][null] Type mismatch error in annotation generics assignment which happens "sometimes" + * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf() * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 415821 - [1.8][compiler] CLASS_EXTENDS target type annotation missing for anonymous classes * het@google.com - Bug 456986 - Bogus error when annotation processor generates annotation type @@ -617,6 +618,12 @@ public class ClassScope extends Scope { fields[i].modifiers |= ExtraCompilerModifiers.AccLocallyUsed; } } + if (isEnum && compilerOptions().isAnnotationBasedNullAnalysisEnabled) { + // mark return types of values & valueOf as nonnull (needed to wait till after setMethods() to avoid reentrance): + LookupEnvironment environment = this.environment(); + ((SyntheticMethodBinding)methodBindings[0]).markNonNull(environment); + ((SyntheticMethodBinding)methodBindings[1]).markNonNull(environment); + } } //{ObjectTeams: accessible to sub-class: diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java index ee19b24b8..1056a1c71 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java @@ -40,6 +40,7 @@ * Bug 446434 - [1.8][null] Enable interned captures also when analysing null type annotations * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations * Bug 456508 - Unexpected RHS PolyTypeBinding for: <code-snippet> + * Bug 390064 - [compiler][resource] Resource leak warning missing when extending parameterized class *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -102,6 +103,7 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi if (enclosingType != null && enclosingType.hasNullTypeAnnotations()) this.tagBits |= TagBits.HasNullTypeAnnotation; this.tagBits |= TagBits.HasUnresolvedTypeVariables; // cleared in resolve() + this.typeBits = type.typeBits; } /** diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java index 61007e115..e436088a1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -36,9 +36,12 @@ * Bug 440759 - [1.8][null] @NonNullByDefault should never affect wildcards and uses of a type variable * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression * Bug 446442 - [1.8] merge null annotations from super methods + * Bug 456532 - [1.8][null] ReferenceBinding.appendNullAnnotation() includes phantom annotations in error messages * Jesper S Moller - Contributions for * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression * bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable + * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for + * bug 386692 - Missing "unused" warning on "autowired" fields *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -1026,10 +1029,20 @@ public void computeId() { } break; case 6: - if (!CharOperation.equals(TypeConstants.JDT, this.compoundName[2]) || !CharOperation.equals(TypeConstants.ITYPEBINDING, this.compoundName[5])) - return; - if (CharOperation.equals(TypeConstants.ORG_ECLIPSE_JDT_CORE_DOM_ITYPEBINDING, this.compoundName)) - this.typeBits |= TypeIds.BitUninternedType; + if (CharOperation.equals(TypeConstants.ORG, this.compoundName[0])) { + if (CharOperation.equals(TypeConstants.SPRING, this.compoundName[1])) { + if (CharOperation.equals(TypeConstants.AUTOWIRED, this.compoundName[5])) { + if (CharOperation.equals(TypeConstants.ORG_SPRING_AUTOWIRED, this.compoundName)) { + this.id = TypeIds.T_OrgSpringframeworkBeansFactoryAnnotationAutowired; + } + } + return; + } + if (!CharOperation.equals(TypeConstants.JDT, this.compoundName[2]) || !CharOperation.equals(TypeConstants.ITYPEBINDING, this.compoundName[5])) + return; + if (CharOperation.equals(TypeConstants.ORG_ECLIPSE_JDT_CORE_DOM_ITYPEBINDING, this.compoundName)) + this.typeBits |= TypeIds.BitUninternedType; + } break; case 7 : if (!CharOperation.equals(TypeConstants.JDT, this.compoundName[2]) || !CharOperation.equals(TypeConstants.TYPEBINDING, this.compoundName[6])) @@ -2051,15 +2064,24 @@ public char[] readableName() /*java.lang.Object, p.X<T> */ { protected void appendNullAnnotation(StringBuffer nameBuffer, CompilerOptions options) { if (options.isAnnotationBasedNullAnalysisEnabled) { - // restore applied null annotation from tagBits: - if ((this.tagBits & TagBits.AnnotationNonNull) != 0) { - char[][] nonNullAnnotationName = options.nonNullAnnotationName; - nameBuffer.append('@').append(nonNullAnnotationName[nonNullAnnotationName.length-1]).append(' '); - } - if ((this.tagBits & TagBits.AnnotationNullable) != 0) { - char[][] nullableAnnotationName = options.nullableAnnotationName; - nameBuffer.append('@').append(nullableAnnotationName[nullableAnnotationName.length-1]).append(' '); - } + if (options.usesNullTypeAnnotations()) { + for (AnnotationBinding annotation : this.typeAnnotations) { + TypeBinding annotationType = annotation.getAnnotationType(); + if (annotationType.id == TypeIds.T_ConfiguredAnnotationNonNull || annotation.type.id == TypeIds.T_ConfiguredAnnotationNullable) { + nameBuffer.append('@').append(annotationType.shortReadableName()).append(' '); + } + } + } else { + // restore applied null annotation from tagBits: + if ((this.tagBits & TagBits.AnnotationNonNull) != 0) { + char[][] nonNullAnnotationName = options.nonNullAnnotationName; + nameBuffer.append('@').append(nonNullAnnotationName[nonNullAnnotationName.length-1]).append(' '); + } + if ((this.tagBits & TagBits.AnnotationNullable) != 0) { + char[][] nullableAnnotationName = options.nullableAnnotationName; + nameBuffer.append('@').append(nullableAnnotationName[nullableAnnotationName.length-1]).append(' '); + } + } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java index 032efd519..51b02a788 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java @@ -1713,13 +1713,13 @@ public abstract class Scope { ObjectVector found = new ObjectVector(3); CompilationUnitScope unitScope = compilationUnitScope(); unitScope.recordTypeReferences(argumentTypes); - + List<TypeBinding> visitedTypes = new ArrayList<TypeBinding>(); if (receiverTypeIsInterface) { unitScope.recordTypeReference(receiverType); MethodBinding[] receiverMethods = receiverType.getMethods(selector, argumentTypes.length); if (receiverMethods.length > 0) found.addAll(receiverMethods); - findMethodInSuperInterfaces(receiverType, selector, found, null, invocationSite); + findMethodInSuperInterfaces(receiverType, selector, found, visitedTypes, invocationSite); //{ObjectTeams: confined types don't proceed to java.lang.Object: if (!(TypeAnalyzer.isConfined(receiverType))) // SH} diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java index c108d8b57..c1c2ede8c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java @@ -26,6 +26,7 @@ * bug 391376 - [1.8] check interaction of default methods with bridge methods and generics * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 + * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations
* Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled * Bug 416172 - [1.8][compiler][null] null type annotation not evaluated on method return type * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. @@ -1158,16 +1159,27 @@ public char[] computeUniqueKey(boolean isLeaf) { return uniqueKey; } -//{ObjectTeams: allow access from Dependencies: -public -// SH} -void faultInTypesForFieldsAndMethods() { - if (!isPrototype()) throw new IllegalStateException(); +private void checkAnnotationsInType() { // check @Deprecated annotation getAnnotationTagBits(); // marks as deprecated by side effect ReferenceBinding enclosingType = enclosingType(); if (enclosingType != null && enclosingType.isViewedAsDeprecated() && !isDeprecated()) this.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly; + + for (int i = 0, length = this.memberTypes.length; i < length; i++) + ((SourceTypeBinding) this.memberTypes[i]).checkAnnotationsInType(); +} + +//{ObjectTeams: allow access from Dependencies: +public +// SH} +void faultInTypesForFieldsAndMethods() { + if (!isPrototype()) throw new IllegalStateException(); + checkAnnotationsInType(); + internalFaultInTypeForFieldsAndMethods(); +} + +private void internalFaultInTypeForFieldsAndMethods() { fields(); methods(); @@ -1180,7 +1192,7 @@ void faultInTypesForFieldsAndMethods() { for (int i = 0; i < this.memberTypes.length; i++) if (!this.memberTypes[i].isBinaryBinding()) // roles could be binary contained in source //carp} - ((SourceTypeBinding) this.memberTypes[i]).faultInTypesForFieldsAndMethods(); + ((SourceTypeBinding) this.memberTypes[i]).internalFaultInTypeForFieldsAndMethods(); } // NOTE: the type of each field of a source type is resolved when needed public FieldBinding[] fields() { @@ -2519,7 +2531,7 @@ public MethodBinding resolveTypesFor(MethodBinding method, boolean fromSynthetic arg.type.resolvedType : arg.type.resolveType(methodDecl.scope, true /* check bounds*/); // orig: -// parameterType = arg.type.resolveType(methodDecl.scope, true /* check bounds*/); +// parameterType = arg.type.resolveType(methodDecl.scope, true /* check bounds*/); } finally { if (deferRawTypeCheck) { arg.type.bits &= ~ASTNode.IgnoreRawTypeCheck; @@ -2755,8 +2767,7 @@ private void createArgumentBindings(MethodBinding method, CompilerOptions compil methodDecl.createArgumentBindings(); // add implicit annotations (inherited(?) & default): if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { - new ImplicitNullAnnotationVerifier(this.scope.environment(), compilerOptions.inheritNullAnnotations) - .checkImplicitNullAnnotations(method, methodDecl, true, this.scope); + new ImplicitNullAnnotationVerifier(this.scope.environment()).checkImplicitNullAnnotations(method, methodDecl, true, this.scope);
} } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java index 73a188d34..133ff4313 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SyntheticMethodBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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,7 @@ * Technical University Berlin - extended API and implementation * Stephan Herrmann - Contribution for * bug 400710 - [1.8][compiler] synthetic access to default method generates wrong code + * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf() * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas *******************************************************************************/ @@ -458,6 +459,14 @@ public class SyntheticMethodBinding extends MethodBinding { this.modifiers = ClassFileConstants.AccSynthetic | ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic; this.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); this.returnType = arrayType; + LookupEnvironment environment = declaringClass.environment; + if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { + // mark X[]::new and X[]::clone as returning 'X @NonNull' (don't wait (cf. markNonNull()), because we're called as late as codeGen): + if (environment.usesNullTypeAnnotations()) + this.returnType = environment.createAnnotatedType(this.returnType, new AnnotationBinding[]{ environment.getNonNullAnnotation() }); + else + this.tagBits |= TagBits.AnnotationNonNull; + } this.parameters = new TypeBinding[] { purpose == SyntheticMethodBinding.ArrayConstructor ? TypeBinding.INT : (TypeBinding) arrayType}; this.thrownExceptions = Binding.NO_EXCEPTIONS; this.purpose = purpose; @@ -673,4 +682,27 @@ public class SyntheticMethodBinding extends MethodBinding { public LambdaExpression sourceLambda() { return this.lambda; } + + public void markNonNull(LookupEnvironment environment) { + // deferred update of the return type + switch (this.purpose) { + case EnumValues: + if (environment.usesNullTypeAnnotations()) { + TypeBinding elementType = ((ArrayBinding)this.returnType).leafComponentType(); + AnnotationBinding nonNullAnnotation = environment.getNonNullAnnotation(); + elementType = environment.createAnnotatedType(elementType, new AnnotationBinding[]{ environment.getNonNullAnnotation() }); + this.returnType = environment.createArrayType(elementType, 1, new AnnotationBinding[]{ nonNullAnnotation, null }); + } else { + this.tagBits |= TagBits.AnnotationNonNull; + } + return; + case EnumValueOf: + if (environment.usesNullTypeAnnotations()) { + this.returnType = environment.createAnnotatedType(this.returnType, new AnnotationBinding[]{ environment.getNonNullAnnotation() }); + } else { + this.tagBits |= TagBits.AnnotationNonNull; + } + return; + } + } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java index c9611a285..0284bd1c6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -22,6 +22,8 @@ * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas + * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for + * bug 386692 - Missing "unused" warning on "autowired" fields *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -119,6 +121,7 @@ public interface TypeConstants { char[] TYPEBINDING = "TypeBinding".toCharArray(); //$NON-NLS-1$ char[] DOM = "dom".toCharArray(); //$NON-NLS-1$ char[] ITYPEBINDING = "ITypeBinding".toCharArray(); //$NON-NLS-1$ + char[] SPRING = "springframework".toCharArray(); //$NON-NLS-1$ // Constant compound names char[][] JAVA_LANG = {JAVA, LANG}; @@ -330,6 +333,13 @@ public interface TypeConstants { // detail for the above: char[] OPTIONAL = "optional".toCharArray(); //$NON-NLS-1$ + // Spring @Autowired annotation + char [] AUTOWIRED = "Autowired".toCharArray(); //$NON-NLS-1$ + char [] BEANS = "beans".toCharArray(); //$NON-NLS-1$ + char [] FACTORY = "factory".toCharArray(); //$NON-NLS-1$ + char[][] ORG_SPRING_AUTOWIRED = new char[][] {ORG, SPRING, BEANS, FACTORY, ANNOTATION, AUTOWIRED}; + char[] REQUIRED = "required".toCharArray(); //$NON-NLS-1$ + // Constraints for generic type argument inference int CONSTRAINT_EQUAL = 0; // Actual = Formal int CONSTRAINT_EXTENDS = 1; // Actual << Formal diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java index cc7114813..1693a6587 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -16,6 +16,8 @@ * bug 382069 - [null] Make the null analysis consider JUnit's assertNotNull similarly to assertions * Jesper S Moller <jesper@selskabet.org> - Contributions for * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable + * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for + * bug 386692 - Missing "unused" warning on "autowired" fields *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -127,11 +129,16 @@ public interface TypeIds { // new in 3.9 to identify known @Inject annotations final int T_JavaxInjectInject = 80; final int T_ComGoogleInjectInject = 81; + + // @Autowired + final int T_OrgSpringframeworkBeansFactoryAnnotationAutowired = 82; + // Java 8 - JEP 120 final int T_JavaLangAnnotationRepeatable = 90; // If you add new type id, make sure to bump up T_LastWellKnownTypeId if there is a cross over. final int T_LastWellKnownTypeId = 128; + final int NoId = Integer.MAX_VALUE; public static final int IMPLICIT_CONVERSION_MASK = 0xFF; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java index c1abf5241..df7902024 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java @@ -33,6 +33,8 @@ * Bug 456497 - [1.8][null] during inference nullness from target type is lost against weaker hint from applicability analysis * Bug 456459 - Discrepancy between Eclipse compiler and javac - Enums, interfaces, and generics * Bug 456487 - [1.8][null] @Nullable type variant of @NonNull-constrained type parameter causes grief + * Bug 462790 - [null] NPE in Expression.computeConversion() + * Bug 456532 - [1.8][null] ReferenceBinding.appendNullAnnotation() includes phantom annotations in error messages *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -944,6 +946,27 @@ public class TypeVariableBinding extends ReferenceBinding { return readableName; } + protected void appendNullAnnotation(StringBuffer nameBuffer, CompilerOptions options) { + int oldSize = nameBuffer.length(); + super.appendNullAnnotation(nameBuffer, options); + if (oldSize == nameBuffer.length()) { // nothing appended in super.appendNullAnnotation()? + if (hasNullTypeAnnotations()) { + // see if the prototype has null type annotations: + TypeVariableBinding[] typeVariables = null; + if (this.declaringElement instanceof ReferenceBinding) { + typeVariables = ((ReferenceBinding) this.declaringElement).typeVariables(); + } else if (this.declaringElement instanceof MethodBinding) { + typeVariables = ((MethodBinding) this.declaringElement).typeVariables(); + } + if (typeVariables != null && typeVariables.length > this.rank) { + TypeVariableBinding prototype = typeVariables[this.rank]; + if (prototype != this)//$IDENTITY-COMPARISON$ + prototype.appendNullAnnotation(nameBuffer, options); + } + } + } + } + public TypeBinding unannotated() { return this.hasTypeAnnotations() ? this.environment.getUnannotatedType(this) : this; } @@ -1032,10 +1055,11 @@ public class TypeVariableBinding extends ReferenceBinding { public TypeBinding setFirstBound(TypeBinding firstBound) { this.firstBound = firstBound; if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { - TypeBinding [] annotatedTypes = this.environment.getAnnotatedTypes(this); + TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization(); for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i]; - annotatedType.firstBound = firstBound; + if (annotatedType.firstBound == null) + annotatedType.firstBound = firstBound; } } if (firstBound != null && firstBound.hasNullTypeAnnotations()) @@ -1048,10 +1072,11 @@ public class TypeVariableBinding extends ReferenceBinding { public ReferenceBinding setSuperClass(ReferenceBinding superclass) { this.superclass = superclass; if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { - TypeBinding [] annotatedTypes = this.environment.getAnnotatedTypes(this); + TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization(); for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i]; - annotatedType.superclass = superclass; + if (annotatedType.superclass == null) + annotatedType.superclass = superclass; } } return superclass; @@ -1062,15 +1087,20 @@ public class TypeVariableBinding extends ReferenceBinding { public ReferenceBinding [] setSuperInterfaces(ReferenceBinding[] superInterfaces) { this.superInterfaces = superInterfaces; if ((this.tagBits & TagBits.HasAnnotatedVariants) != 0) { - TypeBinding [] annotatedTypes = this.environment.getAnnotatedTypes(this); + TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization(); for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) { TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i]; - annotatedType.superInterfaces = superInterfaces; + if (annotatedType.superInterfaces == null) + annotatedType.superInterfaces = superInterfaces; } } return superInterfaces; } + protected TypeBinding[] getDerivedTypesForDeferredInitialization() { + return this.environment.getAnnotatedTypes(this); + } + public TypeBinding combineTypeAnnotations(TypeBinding substitute) { if (hasTypeAnnotations()) { // may need to merge annotations from the original variable and from substitution: diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java index fd36d240f..689813bb3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java @@ -59,6 +59,8 @@ * Bug 446442 - [1.8] merge null annotations from super methods * Bug 455723 - Nonnull argument not correctly inferred in loop * Bug 458361 - [1.8][null] reconciler throws NPE in ProblemReporter.illegalReturnRedefinition() + * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf() + * Bug 461878 - [1.7][1.8][compiler][null] ECJ compiler does not allow to use null annotations on annotations * Jesper S Moller <jesper@selskabet.org> - Contributions for * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment @@ -68,6 +70,8 @@ * bug 419209 - [1.8] Repeating container annotations should be rejected in the presence of annotation it contains * Bug 429384 - [1.8][null] implement conformance rules for null-annotated lower / upper type bounds * Bug 416182 - [1.8][compiler][null] Contradictory null annotations not rejected + * Ulrich Grave <ulrich.grave@gmx.de> - Contributions for + * bug 386692 - Missing "unused" warning on "autowired" fields ********************************************************************************/ package org.eclipse.jdt.internal.compiler.problem; @@ -6366,8 +6370,15 @@ public void nullAnnotationUnsupportedLocation(Annotation annotation) { String[] shortArguments = new String[] { String.valueOf(annotation.resolvedType.shortReadableName()) }; + int severity = ProblemSeverities.Error | ProblemSeverities.Fatal; + if (annotation.recipient instanceof ReferenceBinding) { + if (((ReferenceBinding) annotation.recipient).isAnnotationType()) + severity = ProblemSeverities.Warning; // special case for https://bugs.eclipse.org/461878 + } handle(IProblem.NullAnnotationUnsupportedLocation, - arguments, shortArguments, annotation.sourceStart, annotation.sourceEnd); + arguments, shortArguments, + severity, + annotation.sourceStart, annotation.sourceEnd); } public void nullAnnotationUnsupportedLocation(TypeReference type) { int sourceEnd = type.sourceEnd; @@ -9527,6 +9538,7 @@ private boolean excludeDueToAnnotation(Annotation[] annotations, int problemId) break; case TypeIds.T_JavaxInjectInject: case TypeIds.T_ComGoogleInjectInject: + case TypeIds.T_OrgSpringframeworkBeansFactoryAnnotationAutowired: if (problemId != IProblem.UnusedPrivateField) return true; // @Inject on method/ctor does constitute a relevant use, just on fields it doesn't break; @@ -13802,8 +13814,7 @@ public void referenceExpressionArgumentNullityMismatch(ReferenceExpression locat location.sourceEnd); } public void illegalReturnRedefinition(ASTNode location, MethodBinding descriptorMethod, - char[][] nonNullAnnotationName, - char/*@Nullable*/[][] providedAnnotationName, TypeBinding providedType) { + boolean isUnchecked, TypeBinding providedType) { StringBuffer methodSignature = new StringBuffer() .append(descriptorMethod.declaringClass.readableName()) .append('.') @@ -13812,22 +13823,16 @@ public void illegalReturnRedefinition(ASTNode location, MethodBinding descriptor .append(descriptorMethod.declaringClass.shortReadableName()) .append('.') .append(descriptorMethod.shortReadableName()); - StringBuffer providedPrefix = new StringBuffer(); - StringBuffer providedShortPrefix = new StringBuffer(); - if (providedAnnotationName != null) { - providedPrefix.append('@').append(CharOperation.toString(providedAnnotationName)).append(' '); - providedShortPrefix.append('@').append(providedAnnotationName[providedAnnotationName.length-1]).append(' '); - } this.handle( - providedAnnotationName == null + isUnchecked ? IProblem.ReferenceExpressionReturnNullRedefUnchecked : IProblem.ReferenceExpressionReturnNullRedef, new String[] { methodSignature.toString(), - CharOperation.toString(nonNullAnnotationName), String.valueOf(descriptorMethod.returnType.readableName()), - providedPrefix.toString(), String.valueOf(providedType.readableName())}, + String.valueOf(descriptorMethod.returnType.nullAnnotatedReadableName(this.options, false)), + String.valueOf(providedType.nullAnnotatedReadableName(this.options, false))}, new String[] { shortSignature.toString(), - String.valueOf(nonNullAnnotationName[nonNullAnnotationName.length-1]), String.valueOf(descriptorMethod.returnType.shortReadableName()), - providedShortPrefix.toString(), String.valueOf(providedType.shortReadableName())}, + String.valueOf(descriptorMethod.returnType.nullAnnotatedReadableName(this.options, true)), + String.valueOf(providedType.nullAnnotatedReadableName(this.options, true))}, location.sourceStart, location.sourceEnd); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties index c8fe88603..c1fdaa424 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties @@ -817,8 +817,8 @@ 956 = Null type safety (type annotations): The expression of type ''{1}'' needs unchecked conversion to conform to ''{0}'', corresponding supertype is ''{2}'' 957 = Null type mismatch at parameter {0}: required ''{1}'' but provided ''{2}'' via method descriptor {3} 958 = Null type safety: parameter {0} provided via method descriptor {3} needs unchecked conversion to conform to ''{1}'' -959 = Null type mismatch at method return type: Method descriptor {0} promises ''@{1} {2}'' but referenced method provides ''{3}{4}'' -960 = Null type safety at method return type: Method descriptor {0} promises ''@{1} {2}'' but referenced method provides ''{3}{4}'' +959 = Null type mismatch at method return type: Method descriptor {0} promises ''{1}'' but referenced method provides ''{2}'' +960 = Null type safety at method return type: Method descriptor {0} promises ''{1}'' but referenced method provides ''{2}'' 961 = Redundant null check: comparing ''{0}'' against null 962 = The nullness annotation ''{0}'' is not applicable at this location 963 = Nullness annotations are not applicable at this location diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java index 151d5da00..74844ebf7 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. + * Copyright (c) 2000, 2015 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 @@ -1115,7 +1115,14 @@ public class Util implements SuffixConstants { } } } else if (typeBinding.isNestedType()) { - classFile.recordInnerClasses(typeBinding); + TypeBinding enclosingType = typeBinding; + do { + if (!enclosingType.canBeSeenBy(classFile.referenceBinding.scope)) + break; + enclosingType = enclosingType.enclosingType(); + } while (enclosingType != null); + if (enclosingType == null) + classFile.recordInnerClasses(typeBinding); } } /* |