diff options
author | Stephan Herrmann | 2011-10-25 16:30:31 +0000 |
---|---|---|
committer | Stephan Herrmann | 2011-10-25 16:30:31 +0000 |
commit | 6dcbb38068eee59acb310076b78bc9a8183f88b8 (patch) | |
tree | 5970dc8f2ddd2fddbec81152e18faccb2710d493 /org.eclipse.jdt.core | |
parent | 608b50502644f795c100c2571772d0519a266d4a (diff) | |
download | org.eclipse.objectteams-6dcbb38068eee59acb310076b78bc9a8183f88b8.tar.gz org.eclipse.objectteams-6dcbb38068eee59acb310076b78bc9a8183f88b8.tar.xz org.eclipse.objectteams-6dcbb38068eee59acb310076b78bc9a8183f88b8.zip |
update sources to v_C18, build config to v_C17 (no build containing C18 is available at this point)
Diffstat (limited to 'org.eclipse.jdt.core')
101 files changed, 2591 insertions, 305 deletions
diff --git a/org.eclipse.jdt.core/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.jdt.core/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 000000000..5a0ad22d2 --- /dev/null +++ b/org.eclipse.jdt.core/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java index 47bf67c78..58ed763ed 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java @@ -10,8 +10,10 @@ * Tom Tromey - Contribution for bug 125961 * Tom Tromey - Contribution for bug 159641 * Benjamin Muskalla - Contribution for bug 239066 - * Stephan Herrmann - Contribution for bug 236385 - * Stephan Herrmann - Contribution for bug 295551 + * Stephan Herrmann - Contributions for + * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used + * bug 295551 - Add option to automatically promote all warnings to errors + * bug 359721 - [options] add command line option for new warning token "resource" * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -2243,7 +2245,7 @@ public void configure(String[] argv) { this.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$ } if (currentArg.startsWith("-nowarn")) { //$NON-NLS-1$ - disableWarnings(); + disableAll(ProblemSeverities.Warning); mode = DEFAULT; continue; } @@ -2252,7 +2254,7 @@ public void configure(String[] argv) { String warningOption = currentArg; int length = currentArg.length(); if (length == 10 && warningOption.equals("-warn:" + NONE)) { //$NON-NLS-1$ - disableWarnings(); + disableAll(ProblemSeverities.Warning); continue; } if (length <= 6) { @@ -2260,23 +2262,20 @@ public void configure(String[] argv) { this.bind("configure.invalidWarningConfiguration", warningOption)); //$NON-NLS-1$ } int warnTokenStart; - boolean isEnabling, allowPlusOrMinus; + boolean isEnabling; switch (warningOption.charAt(6)) { case '+' : warnTokenStart = 7; isEnabling = true; - allowPlusOrMinus = true; break; case '-' : warnTokenStart = 7; isEnabling = false; // specified warnings are disabled - allowPlusOrMinus = true; break; default: - disableWarnings(); + disableAll(ProblemSeverities.Warning); warnTokenStart = 6; isEnabling = true; - allowPlusOrMinus = false; } StringTokenizer tokenizer = @@ -2292,22 +2291,12 @@ public void configure(String[] argv) { tokenCounter++; switch(token.charAt(0)) { case '+' : - if (allowPlusOrMinus) { - isEnabling = true; - token = token.substring(1); - } else { - throw new IllegalArgumentException( - this.bind("configure.invalidUsageOfPlusOption", token)); //$NON-NLS-1$ - } + isEnabling = true; + token = token.substring(1); break; case '-' : - if (allowPlusOrMinus) { - isEnabling = false; - token = token.substring(1); - } else { - throw new IllegalArgumentException( - this.bind("configure.invalidUsageOfMinusOption", token)); //$NON-NLS-1$ - } + isEnabling = false; + token = token.substring(1); } handleWarningToken(token, isEnabling); } @@ -2326,23 +2315,20 @@ public void configure(String[] argv) { this.bind("configure.invalidErrorConfiguration", errorOption)); //$NON-NLS-1$ } int errorTokenStart; - boolean isEnabling, allowPlusOrMinus; + boolean isEnabling; switch (errorOption.charAt(5)) { case '+' : errorTokenStart = 6; isEnabling = true; - allowPlusOrMinus = true; break; case '-' : errorTokenStart = 6; isEnabling = false; // specified errors are disabled - allowPlusOrMinus = true; break; default: - disableErrors(); + disableAll(ProblemSeverities.Error); errorTokenStart = 5; isEnabling = true; - allowPlusOrMinus = false; } StringTokenizer tokenizer = @@ -2354,22 +2340,12 @@ public void configure(String[] argv) { tokenCounter++; switch(token.charAt(0)) { case '+' : - if (allowPlusOrMinus) { - isEnabling = true; - token = token.substring(1); - } else { - throw new IllegalArgumentException( - this.bind("configure.invalidUsageOfPlusOption", token)); //$NON-NLS-1$ - } + isEnabling = true; + token = token.substring(1); break; case '-' : - if (allowPlusOrMinus) { - isEnabling = false; - token = token.substring(1); - } else { - throw new IllegalArgumentException( - this.bind("configure.invalidUsageOfMinusOption", token)); //$NON-NLS-1$ - } + isEnabling = false; + token = token.substring(1); break; } handleErrorToken(token, isEnabling); @@ -2901,7 +2877,16 @@ private void initializeWarnings(String propertiesFile) { // SH} } } -protected void disableWarnings() { +protected void enableAll(int severity) { + String newValue = null; + switch(severity) { + case ProblemSeverities.Error : + newValue = CompilerOptions.ERROR; + break; + case ProblemSeverities.Warning : + newValue = CompilerOptions.WARNING; + break; + } Object[] entries = this.options.entrySet().toArray(); for (int i = 0, max = entries.length; i < max; i++) { Map.Entry entry = (Map.Entry) entries[i]; @@ -2909,13 +2894,22 @@ protected void disableWarnings() { continue; if (!(entry.getValue() instanceof String)) continue; - if (((String) entry.getValue()).equals(CompilerOptions.WARNING)) { - this.options.put(entry.getKey(), CompilerOptions.IGNORE); + if (((String) entry.getValue()).equals(CompilerOptions.IGNORE)) { + this.options.put(entry.getKey(), newValue); } } this.options.put(CompilerOptions.OPTION_TaskTags, Util.EMPTY_STRING); } -protected void disableErrors() { +protected void disableAll(int severity) { + String checkedValue = null; + switch(severity) { + case ProblemSeverities.Error : + checkedValue = CompilerOptions.ERROR; + break; + case ProblemSeverities.Warning : + checkedValue = CompilerOptions.WARNING; + break; + } Object[] entries = this.options.entrySet().toArray(); for (int i = 0, max = entries.length; i < max; i++) { Map.Entry entry = (Map.Entry) entries[i]; @@ -2923,7 +2917,7 @@ protected void disableErrors() { continue; if (!(entry.getValue() instanceof String)) continue; - if (((String) entry.getValue()).equals(CompilerOptions.ERROR)) { + if (((String) entry.getValue()).equals(checkedValue)) { this.options.put(entry.getKey(), CompilerOptions.IGNORE); } } @@ -3334,6 +3328,13 @@ private void handleErrorOrWarningToken(String token, boolean isEnabling, int sev setSeverity(CompilerOptions.OPTION_ReportMethodCanBeStatic, severity, isEnabling); setSeverity(CompilerOptions.OPTION_ReportMethodCanBePotentiallyStatic, severity, isEnabling); return; + } else if (token.equals("all")) { //$NON-NLS-1$ + if (isEnabling) { + enableAll(severity); + } else { + disableAll(severity); + } + return; //{ObjectTeams: } else if (token.equals("ambiguousbinding")) { //$NON-NLS-1$ setSeverity(CompilerOptions.OPTION_ReportPotentialAmbiguousPlayedby, severity, isEnabling); @@ -3578,6 +3579,11 @@ private void handleErrorOrWarningToken(String token, boolean isEnabling, int sev } else if (/*token.equals("intfRedundant") ||*/ token.equals("redundantSuperinterface")) { //$NON-NLS-1$ setSeverity(CompilerOptions.OPTION_ReportRedundantSuperinterface, severity, isEnabling); return; + } else if (token.equals("resource")) { //$NON-NLS-1$ + setSeverity(CompilerOptions.OPTION_ReportUnclosedCloseable, severity, isEnabling); + setSeverity(CompilerOptions.OPTION_ReportPotentiallyUnclosedCloseable, severity, isEnabling); + setSeverity(CompilerOptions.OPTION_ReportExplicitlyClosedAutoCloseable, severity, isEnabling); + return; //{ObjectTeams: } else if (token.equals("roleinstantiation")) { //$NON-NLS-1$ setSeverity(CompilerOptions.OPTION_ReportUnsafeRoleInstantiation, severity, isEnabling); diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties index ec64bbe12..8a658edfe 100644 --- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties +++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/messages.properties @@ -1,12 +1,30 @@ +############################################################################### +# Copyright (c) 2000, 2011 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Benjamin Muskalla - Contribution for bug 239066 +# Stephan Herrmann - Contributions for +# bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used +# bug 295551 - Add option to automatically promote all warnings to errors +# bug 359721 - [options] add command line option for new warning token "resource" +############################################################################### +### JavaBatchCompiler messages. + +### compiler #Format: compiler.name = word1 word2 word3 compiler.name = Eclipse Compiler for Java(TM) #Format: compiler.version = 0.XXX[, other words (don't forget the comma if adding other words)] -compiler.version = 0.C10, 3.8.0 M2 +compiler.version = 0.C18, 3.8.0 M3 compiler.copyright = Copyright IBM Corp 2000, 2011. All rights reserved. ###{ObjectTeams: otdtc.name = Extension for Object Teams -otdtc.version = 2.1.0 M2 $LastChangedRevision$ $LastChangedDate$ +otdtc.version = 2.1.0 M3 $LastChangedRevision$ $LastChangedDate$ otdtc.copyright = Copyright by TU Berlin, Fraunhofer FIRST and others, 2004, 2011. ### SH} ### progress @@ -57,8 +75,6 @@ configure.maxProblems = max problems must be a positive integer: {0} configure.invalidErrorConfiguration = invalid error configuration: ''{0}'' configure.invalidError = invalid error token: ''{0}''. Ignoring this error token and compiling configure.invalidErrorOption = invalid error option: ''{0}''. Must specify an error token -configure.invalidUsageOfPlusOption=usage of ''+'' for ''{0}'' is illegal there -configure.invalidUsageOfMinusOption=usage of ''-'' for ''{0}'' is illegal there ## configure.directoryNotExist = directory does not exist: {0} configure.unrecognizedOption = Unrecognized option : {0} @@ -262,6 +278,7 @@ misc.usage.warn = {1} {2}\n\ \ -warn:-<warnings separated by ,> disable specific warnings\n\ \ abstractrelevantrole + abstract relevant role (OTJLD 2.5(b))\n\ \ adaptDeprecated + adapting a deprecated type/method\n\ +\ all enable all warnings\n\ \ allDeadCode dead code including trivial if(DEBUG) check\n\ \ allDeprecation deprecation including inside deprecated code\n\ \ allJavadoc invalid or missing javadoc\n\ @@ -323,6 +340,7 @@ misc.usage.warn = {1} {2}\n\ \ paramAssign assignment to a parameter\n\ \ pkgDefaultMethod + attempt to override package-default method\n\ \ raw + usage of raw type\n\ +\ resource + (pot.) unsafe usage of resource of type Closeable\n\ \ roleinstantiation + unsafe instantiation of a role\n\ \ (OTJLD 2.4.1(c), 2.4.3)\n\ \ roletypesyntax + old style syntax for role types (dependent types)\n\ diff --git a/org.eclipse.jdt.core/buildnotes_jdt-core.html b/org.eclipse.jdt.core/buildnotes_jdt-core.html index f1baf89d6..9d3e66f4b 100644 --- a/org.eclipse.jdt.core/buildnotes_jdt-core.html +++ b/org.eclipse.jdt.core/buildnotes_jdt-core.html @@ -42,6 +42,393 @@ </td> </tr> </table> +<a name="v_C18"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - October 25, 2011 - 3.8.0 M3 +<br>Project org.eclipse.jdt.core v_C18 +(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_C18">cvs</a>). +<h2>What's new in this drop</h2> + +<h3>Problem Reports Fixed</h3> + +<a name="v_C17"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - October 20, 2011 +<br>Project org.eclipse.jdt.core v_C17 +(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_C17">cvs</a>). +<h2>What's new in this drop</h2> +<ul> +<li>Added a new API OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=287164">287164</a> for details): +<pre> +/** + * Status constant indicating that the default or specific output folder is overlapping + * with another source location. + * @since 3.8 + */ +public static final int OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE = 1013; +</pre> +</li> + +<li>Added a new option CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE to report an output location overlapping another source location(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=287164">287164</a> for details): +<pre> +/** + * Core option ID: Reporting an output location overlapping another source location. + * Indicate the severity of the problem reported when a source entry's output location overlaps another + * source entry. + * + * Option id:"org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource" + * Possible values:{ "error", "warning", "ignore" } + * Default:"error" + * + * @since 3.8 + */ +public static final String CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE = PLUGIN_ID + ".classpath.outputOverlappingAnotherSource"; +</pre> +</li> +</ul> +<h3>Problem Reports Fixed</h3> +<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=287164">287164</a> +Report build path error if source folder has other source folder as output folder +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359721">359721</a> +[options] add command line option for new warning token "resource" +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=343480">343480</a> +[compiler] Incorrect/confusing error message on inner class static field declaration +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=318401">318401</a> +FUP of 317858: Clarify eclipse compiler behavior on imports & shadowing +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=360317">360317</a> +[compiler] report switch over enum in 1.4- mode +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=360164">360164</a> +Compile error in XSDImpl +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359727">359727</a> +[1.7][doc] Update doc for new resource leak warnings + +<a name="v_C16"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - October 18, 2011 +<br>Project org.eclipse.jdt.core v_C16 +(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_C16">cvs</a>). +<h2>What's new in this drop</h2> +<ul> +<li>Added a new API IBootstrapMethodsEntry to describe the bootstrap method table entry(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> +/** + * Description of a bootstrap method table entry as specified in the JVM specifications. + * + * This interface may be implemented by clients. + * + * @since 3.8 + */ +public interface IBootstrapMethodsEntry; +</pre> +</li> + +<li>Added a new API IBootstrapMethodsAttribute to describe the bootstrap method attribute(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> +/** + * Description of a bootstrap methods attribute as described in the JVM specifications. + * + * This interface may be implemented by clients. + * + * @since 3.8 + */ +public interface IBootstrapMethodsAttribute +</pre> +</li> + +<li>Added a new API in IBootstrapMethodsAttribute to obtain the number of bootstrap methods of this entry(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> +/** + * Answer back the number of bootstrap methods of this entry as specified in + * the JVM specifications. + * + * @return the number of bootstrap methods of this entry as specified in + * the JVM specifications + */ +int getBootstrapMethodsLength(); +</pre> +</li> + +<li>Added a new API in IBootstrapMethodsAttribute to obtain the bootstrap methods table of this entry(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> +/** + * Answer back the bootstrap methods table of this entry as specified in + * the JVM specifications. Answer an empty array if none. + * + * @return the bootstrap methods table of this entry as specified in + * the JVM specifications. Answer an empty array if none + */ +IBootstrapMethodsEntry[] getBootstrapMethods(); +</pre> +</li> + +<li>Added IConstantPoolEntry2 to describe the new constant pool entry from Java 7 onwards(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> +/** + * Description of the new constant pool entry as described in the JVM specifications + * added for Java 7 support. + * Its contents is initialized according to its kind. + * + * This interface may be implemented by clients. + * + * @since 3.8 + */ +public interface IConstantPoolEntry2 +</pre> +</li> + +<li>Added new API in IConstantPoolEntry2 to return the descriptor index for MethodType entry(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> +/** + * Returns the descriptor index. This value is set only when decoding a MethodType entry. + * The value is unspecified otherwise. The corresponding UTF8 value can be retrieved by using + * {@link #getMethodDescriptor()}. + * + * @return the descriptor index. This value is set only when decoding a MethodType entry. + * @see IConstantPoolConstant#CONSTANT_MethodType + */ +int getDescriptorIndex(); +</pre> +</li> + +<li>Added new API in IConstantPoolEntry2 to return the reference kind for MethodHandle entry(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> +/** + * Returns the reference kind. This value is set only when decoding a MethodHandle entry. + * The value is unspecified otherwise. + * + * @return the reference kind. This value is set only when decoding a MethodHandle entry. + * @see IConstantPoolConstant#CONSTANT_MethodHandle + */ +int getReferenceKind(); +</pre> +</li> + +<li>Added new API in IConstantPoolEntry2 to return the reference index for MethodHandle entry(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> +/** + * Returns the reference index. This value is set only when decoding a MethodHandle entry. + * The value is unspecified otherwise. + * + * @return the reference kind. This value is set only when decoding a MethodHandle entry. + * @see IConstantPoolConstant#CONSTANT_MethodHandle + */ +int getReferenceIndex(); +</pre> +</li> + +<li>Added new API in IConstantPoolEntry2 to return the bootstrap method attribute index(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> +/** + * Returns the bootstrap method attribute index. This value is set only when decoding a InvokeDynamic entry. + * The value is unspecified otherwise. + * + * @return the reference kind. This value is set only when decoding a MethodHandle entry. + * @see IConstantPoolConstant#CONSTANT_InvokeDynamic + */ +int getBootstrapMethodAttributeIndex(); +</pre> +</li> + +<li>Added new API in IByteCodeVisitor(see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> for details): +<pre> + /** + * @since 3.8 + */ + void _invokedynamic( + int pc, + int index, + IConstantPoolEntry invokeDynamic); +</pre> +<p> +This has been added in place of the deprecated API +<pre> + void _invokedynamic( + int pc, + int index, + IConstantPoolEntry nameEntry, + IConstantPoolEntry descriptorEntry); +</pre> +</li> +</ul> +<h3>Problem Reports Fixed</h3> +<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359943">359943</a> +invokedynamic in generated class file is not correctly recognized by the eclipse compiler +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=360644">360644</a> +Scope.isDefinedInSameUnit(ReferenceBinding) fails for a ParameterizedTypeBinding +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=358762">358762</a> +NPE in JDT compiler +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=360328">360328</a> +[compiler][null] detect null problems in nested code (local class inside a loop) + +<a name="v_C15"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - October 11, 2011 +<br>Project org.eclipse.jdt.core v_C15 +(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_C15">cvs</a>). +<h2>What's new in this drop</h2> + +<h3>Problem Reports Fixed</h3> +<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=350285">350285</a> +ASTRewrite destroys formatting on CatchClause#setBody(copyTarget) +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=353474">353474</a> +type converters should include more annotations + +<a name="v_C14"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - October 5, 2011 +<br>Project org.eclipse.jdt.core v_C14 +(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_C14">cvs</a>). +<h2>What's new in this drop</h2> + +<h3>Problem Reports Fixed</h3> +<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=354181">354181</a> +migrate jdt.core to git +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359831">359831</a> +Fix messages for "new warning for missing try-with-resources" + +<a name="v_C13"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - October 3, 2011 +<br>Project org.eclipse.jdt.core v_C13 +(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_C13">cvs</a>). +<h2>What's new in this drop</h2> +<ul> +<li>New Javacore option org.eclipse.jdt.core.JavaCore.COMPILER_PB_UNCLOSED_CLOSEABLE to raise a warning or error + when a resource of type Closeable or AutoCloseable is not closed locally. +(see details in bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=349326">349326</a>): +<pre> + /** + * Compiler option ID: Reporting a resource that is not closed properly. + * + * When enabled, the compiler will issue an error or a warning if + * a local variable holds a value of type <code>java.lang.AutoCloseable</code> (compliance>=1.7) + * or a value of type <code>java.io.Closeable</code> (compliance<=1.6) and if + * flow analysis shows that the method <code>close()</code> is not invoked locally on that value. + * + * Option id: <code>"org.eclipse.jdt.core.compiler.problem.reportUnclosedCloseable"</code> + * Possible values: <code>{ "error", "warning", "ignore" }</code> + * Default: <code>"warning"</code> + * + * @since 3.8 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_UNCLOSED_CLOSEABLE = PLUGIN_ID + ".compiler.problem.unclosedCloseable"; //$NON-NLS-1$ +</pre> +</li> +<li>New Javacore option org.eclipse.jdt.core.JavaCore.COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE to raise a warning or error + when a resource of type Closeable or AutoCloseable is not definitely closed locally. +(see details in bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=349326">349326</a>): +<pre> + /** + * Compiler option ID: Reporting a resource that may not be closed properly. + * + * When enabled, the compiler will issue an error or a warning if + * a local variable holds a value of type <code>java.lang.AutoCloseable</code> (compliance>=1.7) + * or a value of type <code>java.io.Closeable</code> (compliance<=1.6) and if + * flow analysis shows that the method <code>close()</code> is + * not invoked locally on that value for all execution paths. + * + * Option id: <code>"org.eclipse.jdt.core.compiler.problem.reportPotentiallyUnclosedCloseable"</code> + * Possible values: <code>{ "error", "warning", "ignore" }</code> + * Default: <code>"ignore"</code> + * + * @since 3.8 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE = PLUGIN_ID + ".compiler.problem.potentiallyUnclosedCloseable"; //$NON-NLS-1$ +</pre> +</li> +<li>New Javacore option org.eclipse.jdt.core.JavaCore.COMPILER_PB_EXPLICITLY_CLOSED_AUTOCLOSEABLE to raise a warning or error + when a resource of type AutoCloseable is closed explicitly rather than using a try-with-resources block. +(see details in bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=349326">349326</a>): +<pre> + /** + * Compiler option ID: Reporting a resource that is not managed by try-with-resources. + * + * When enabled, the compiler will issue an error or a warning if a local variable + * holds a value of type <code>java.lang.AutoCloseable</code>, and if the method + * <code>close()</code> is explicitly invoked on that resource, but the resource is + * not managed by a try-with-resources block. + * + * Option id: <code>"org.eclipse.jdt.core.compiler.problem.reportPotentiallyUnclosedCloseable"</code> + * Possible values: <code>{ "error", "warning", "ignore" }</code> + * Default: <code>"ignore"</code> + * + * @since 3.8 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_EXPLICITLY_CLOSED_AUTOCLOSEABLE = PLUGIN_ID + ".compiler.problem.explicitlyClosedAutoCloseable"; //$NON-NLS-1$ +</pre> +</li> +</ul> + +<h3>Problem Reports Fixed</h3> +<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359495">359495</a> +[1.7][compiler] VerifyError in try-finally block with lock encompassing for-each block and unlock in finally clause +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=161129">161129</a> +[batch][compiler] Add -warn:all to report all warnings +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359646">359646</a> +Formatter fails silently if Java source contains 0x8000000000000000L +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=256796">256796</a> +[compiler] dead code detection: "if (DEBUG) return;" should also be trivial IF stmt +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359334">359334</a> +Analysis for resource leak warnings does not consider exceptions as method exit points +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=359362">359362</a> +FUP of bug 349326: Resource leak on non-Closeable resource. +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=348186">348186</a> +[compiler] Improve wording for the warning for masked/hidden catch block +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=355838">355838</a> +[compiler] ecj compiles the code that javac6 rejects +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=349326">349326</a> +[1.7] new warning for missing try-with-resources +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=354502">354502</a> +Incorrect Compiler Warning: "Method can be declared as static" +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=241834">241834</a> +[search] ClassCastException during move class refactoring +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=358827">358827</a> +[1.7] exception analysis for t-w-r spoils null analysis + +<a name="v_C12"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - September 23, 2011 +<br>Project org.eclipse.jdt.core v_C12 +(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_C12">cvs</a>). +<h2>What's new in this drop</h2> +<ul> +<li>Tagging to prepare for the git migration</li> +</ul> + +<h3>Problem Reports Fixed</h3> + +<a name="v_C11"></a> +<hr><h1> +Eclipse Platform Build Notes<br> +Java development tools core</h1> +Eclipse SDK 3.8.0 - September 20, 2011 +<br>Project org.eclipse.jdt.core v_C11 +(<a href="http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.jdt.core/?only_with_tag=v_C11">cvs</a>). +<h2>What's new in this drop</h2> + +<h3>Problem Reports Fixed</h3> +<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=357110">357110</a> +Problem with inner classes referenced from jars or class folders: "The type ... cannot be resolved" +<br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=357471">357471</a> +ASTParser cannot resolve binding of PackageDeclaration if class name is equal to the first segment of the package name + <a name="v_C10"></a> <hr><h1> Eclipse Platform Build Notes<br> @@ -66,7 +453,7 @@ Eclipse SDK 3.8.0 - September 9, 2011 <h3>Problem Reports Fixed</h3> <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=354332">354332</a> -DeltaProcessor exhibits O(N∧2) behavior +DeltaProcessor exhibits O(N^2) behavior <br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=355605">355605</a> NPE in HierarchyResolver <br><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=347396">347396</a> @@ -244,7 +631,7 @@ Eclipse SDK 3.8.0 - July 27, 2011 <li>Added a new API in CompletionProposal to tell whether it diamond operator can be used (see bug <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=351444">351444</a> for details): <pre> /** - * Returns whether it is safe to use the '<>' (diamond) operator in place of explicitly specifying + * Returns whether it is safe to use the '<>' (diamond) operator in place of explicitly specifying * type arguments for this proposal. * * This is only relevant for source level 1.7 or greater. @@ -263,7 +650,7 @@ usage of type arguments when diamond operator can be used instead. (see details /** * Compiler option ID: Reporting redundant specification of type arguments in class instance creation expressions. * When enabled, the compiler will issue an error or a warning if type arguments are used in a class instance creation, - * when the '<>' operator can be used instead. + * when the '<>' operator can be used instead. * * This option only has an effect if the compiler compliance is 1.7 or greater. * diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java index fd46fdb80..dd7a81c0a 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java @@ -117,7 +117,12 @@ * Benjamin Muskalla - added the following constants * MissingSynchronizedModifierInInheritedMethod * Stephan Herrmann - added the following constants - * UnusedObjectAllocation + * UnusedObjectAllocation + * PotentiallyUnclosedCloseable + * PotentiallyUnclosedCloseableAtExit + * UnclosedCloseable + * UnclosedCloseableAtExit + * ExplicitlyClosedAutoCloseable * * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation @@ -1400,6 +1405,18 @@ void setSourceStart(int sourceStart); int DiamondNotBelow17 = TypeRelated + 883; /** @since 3.7.1 */ int RedundantSpecificationOfTypeArguments = TypeRelated + 884; + /** @since 3.8 */ + int PotentiallyUnclosedCloseable = Internal + 885; + /** @since 3.8 */ + int PotentiallyUnclosedCloseableAtExit = Internal + 886; + /** @since 3.8 */ + int UnclosedCloseable = Internal + 887; + /** @since 3.8 */ + int UnclosedCloseableAtExit = Internal + 888; + /** @since 3.8 */ + int ExplicitlyClosedAutoCloseable = Internal + 889; + /** @since 3.8 */ + int SwitchOnEnumNotBelow15 = TypeRelated + 890; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=360317 /** * External problems -- These are problems defined by other plugins */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java index 4d03cf3ea..e4d93c8b6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java @@ -16,8 +16,6 @@ import java.util.List; import org.eclipse.jdt.core.compiler.*; import org.eclipse.jdt.internal.compiler.*; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext; import org.eclipse.jdt.internal.compiler.impl.*; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.*; @@ -211,8 +209,6 @@ public abstract class AbstractMethodDeclaration } } - public abstract void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo info); - /** * Bind and add argument's binding into the scope of the method */ 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 0469e159b..8bd0d348e 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 @@ -10,6 +10,7 @@ * Stephan Herrmann - Contributions for * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -81,6 +82,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl // process arguments if (this.arguments != null) { for (int i = 0, count = this.arguments.length; i < count; i++) { + // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) + flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo); flowInfo = this.arguments[i] .analyseCode(currentScope, flowContext, flowInfo) diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java index ebad17f3b..9b1210481 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 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 95d873c10..d874749d0 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 @@ -12,6 +12,7 @@ * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE * bug 292478 - Report potentially null across variable assignment * bug 335093 - [compiler][null] minimal hook for future null annotation support + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -78,6 +79,16 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl flowInfo = ((Reference) this.lhs) .analyseAssignment(currentScope, flowContext, flowInfo, this, false) .unconditionalInits(); + if (local != null) { + LocalVariableBinding previousTrackerBinding = null; + if (local.closeTracker != null) { + // Assigning to a variable already holding an AutoCloseable, has it been closed before? + previousTrackerBinding = local.closeTracker.binding; + if (!flowInfo.isDefinitelyNull(local)) // only if previous value may be non-null + local.closeTracker.recordErrorLocation(this, flowInfo.nullStatus(previousTrackerBinding)); + } + FakedTrackingVariable.handleResourceAssignment(flowInfo, this, this.expression, local, previousTrackerBinding); + } int nullStatus = this.expression.nullStatus(flowInfo); if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { if (nullStatus == FlowInfo.NULL) { 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 92c1e5dd3..28fd5abc3 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -8,6 +8,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -45,10 +46,12 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; for (int i = 0, max = this.statements.length; i < max; i++) { Statement stat = this.statements[i]; - if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { + if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) { flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo); } } + if (this.explicitDeclarations > 0) // if block has its own scope analyze tracking vars now: + this.scope.checkUnclosedCloseables(flowInfo, null, null); return flowInfo; } /** diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java index 3c5991878..cc390d333 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -72,7 +72,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl targetContext.recordBreakFrom(flowInfo); break; } - } while ((traversedContext = traversedContext.parent) != null); + } while ((traversedContext = traversedContext.getLocalParent()) != null); // resize subroutines if (subCount != this.subroutines.length) { 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 cf4ba6101..30f8d24be 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 @@ -13,6 +13,7 @@ * bug 292478 - Report potentially null across variable assignment * bug 324178 - [null] ConditionalExpression.nullStatus(..) doesn't take into account the analysis of condition itself * bug 354554 - [null] conditional with redundant condition yields weak error message + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -75,7 +76,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); } if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) { - this.valueIfTrue.complainIfUnreachable(trueFlowInfo, currentScope, initialComplaintLevel); + this.valueIfTrue.complainIfUnreachable(trueFlowInfo, currentScope, initialComplaintLevel, false); } } this.trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo); @@ -88,7 +89,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); } if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) { - this.valueIfFalse.complainIfUnreachable(falseFlowInfo, currentScope, initialComplaintLevel); + this.valueIfFalse.complainIfUnreachable(falseFlowInfo, currentScope, initialComplaintLevel, true); } } this.falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo); 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 75a1d9e41..cf7c99194 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 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for Bug 343713 - [compiler] bogus line number in constructor of inner class in 1.5 compliance + * Stephan Herrmann - Contributions for + * bug 343713 - [compiler] bogus line number in constructor of inner class in 1.5 compliance + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -79,18 +81,9 @@ public class ConstructorDeclaration extends AbstractMethodDeclaration { public ConstructorDeclaration(CompilationResult compilationResult){ super(compilationResult); } - -/** - * @see org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration#analyseCode(org.eclipse.jdt.internal.compiler.lookup.ClassScope, org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext, org.eclipse.jdt.internal.compiler.flow.FlowInfo) - * @deprecated use instead {@link #analyseCode(ClassScope, InitializationFlowContext, FlowInfo, int)} - */ -public void analyseCode(ClassScope classScope, InitializationFlowContext initializerFlowContext, FlowInfo flowInfo) { - analyseCode(classScope, initializerFlowContext, flowInfo, FlowInfo.REACHABLE); -} - /** * The flowInfo corresponds to non-static field initialization infos. It may be unreachable (155423), but still the explicit constructor call must be - * analysed as reachable, since it will be generated in the end. + * analyzed as reachable, since it will be generated in the end. */ public void analyseCode(ClassScope classScope, InitializationFlowContext initializerFlowContext, FlowInfo flowInfo, int initialReachMode) { if (this.ignoreFurtherInvestigation) @@ -130,7 +123,7 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial // force called constructor to be analyzed: MethodBinding selfCall = this.constructorCall.binding; if (selfCall.declaringClass == this.binding.declaringClass) - selfCall.sourceMethod().analyseCode(classScope, initializerFlowContext, flowInfo.copy()); + ((ConstructorDeclaration)selfCall.sourceMethod()).analyseCode(classScope, initializerFlowContext, flowInfo.copy(), flowInfo.reachMode()); boolean calledHere = MethodModel.callsBaseCtor(this.binding); boolean calledIndirectly = MethodModel.callsBaseCtor(selfCall); @@ -276,7 +269,7 @@ public void analyseCode(ClassScope classScope, InitializationFlowContext initial int complaintLevel = (nonStaticFieldInfoReachMode & FlowInfo.UNREACHABLE) == 0 ? Statement.NOT_COMPLAINED : Statement.COMPLAINED_FAKE_REACHABLE; for (int i = 0, count = this.statements.length; i < count; i++) { Statement stat = this.statements[i]; - if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { + if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) { flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo); } } @@ -663,6 +656,7 @@ public boolean isRecursive(ArrayList visited) { ConstructorDeclaration targetConstructor = ((ConstructorDeclaration)this.scope.referenceType().declarationOf(this.constructorCall.binding.original())); + if (targetConstructor == null) return false; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=358762 if (this == targetConstructor) return true; // direct case if (visited == null) { // lazy allocation diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java index 1641bc5a9..475fef21f 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -75,7 +75,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl targetContext.recordContinueFrom(flowContext, flowInfo); break; } - } while ((traversedContext = traversedContext.parent) != null); + } while ((traversedContext = traversedContext.getLocalParent()) != null); // resize subroutines if (subCount != this.subroutines.length) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java index d6cbd10ca..904e56406 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -29,12 +30,12 @@ public class EmptyStatement extends Statement { } // Report an error if necessary - public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int complaintLevel) { + public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int complaintLevel, boolean endOfBlock) { // before 1.4, empty statements are tolerated anywhere if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_4) { return complaintLevel; } - return super.complainIfUnreachable(flowInfo, scope, complaintLevel); + return super.complainIfUnreachable(flowInfo, scope, complaintLevel, endOfBlock); } public void generateCode(BlockScope currentScope, CodeStream codeStream){ 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 new file mode 100644 index 000000000..ee1304749 --- /dev/null +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright (c) 2011 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Stephan Herrmann - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.ast; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.lookup.Binding; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; +import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; +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.TypeBinding; +import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; +import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; + +/** + * A faked local variable declaration used for keeping track of data flows of a + * special variable. Certain events will be recorded by changing the null info + * for this variable. + * + * See bug 349326 - [1.7] new warning for missing try-with-resources + */ +public class FakedTrackingVariable extends LocalDeclaration { + + // a call to close() was seen at least on one path: + private static final int CLOSE_SEEN = 1; + // the resource was passed to outside code (arg in method/ctor call or as a return value from this method): + private static final int PASSED_TO_OUTSIDE = 2; + // If close() is invoked from a nested method (inside a local type) report remaining problems only as potential: + private static final int CLOSED_IN_NESTED_METHOD = 4; + // a location independent issue has been reported already against this resource: + private static final int REPORTED = 8; + + /** + * Bitset of {@link #CLOSE_SEEN}, {@link #PASSED_TO_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD} and {@link #REPORTED}. + */ + private int globalClosingState = 0; + + MethodScope methodScope; // designates the method declaring this variable + + public LocalVariableBinding originalBinding; // the real local being tracked + + HashMap recordedLocations; // initially null, ASTNode -> Integer + + + public FakedTrackingVariable(LocalVariableBinding original, Statement location) { + super(original.name, location.sourceStart, location.sourceEnd); + this.type = new SingleTypeReference( + TypeConstants.OBJECT, + ((long)this.sourceStart <<32)+this.sourceEnd); + this.methodScope = original.declaringScope.methodScope(); + this.originalBinding = original; + resolve(original.declaringScope); + } + + public void generateCode(BlockScope currentScope, CodeStream codeStream) + { /* NOP - this variable is completely dummy, ie. for analysis only. */ } + + public void resolve (BlockScope scope) { + // only need the binding, which is used as reference in FlowInfo methods. + this.binding = new LocalVariableBinding( + this.name, + scope.getJavaLangObject(), // dummy, just needs to be a reference type + 0, + false); + this.binding.setConstant(Constant.NotAConstant); + this.binding.useFlag = LocalVariableBinding.USED; + // use a free slot without assigning it: + this.binding.id = scope.registerTrackingVariable(this); + } + + /** + * If expression resolves to a local variable binding of type AutoCloseable, + * answer the variable that tracks closing of that local, creating it if needed. + * @param expression + * @return a new {@link FakedTrackingVariable} or null. + */ + public static FakedTrackingVariable getCloseTrackingVariable(Expression expression) { + if (expression instanceof SingleNameReference) { + SingleNameReference name = (SingleNameReference) expression; + if (name.binding instanceof LocalVariableBinding) { + LocalVariableBinding local = (LocalVariableBinding)name.binding; + if (local.closeTracker != null) + return local.closeTracker; + if (local.isParameter() || !isAutoCloseable(expression.resolvedType)) + 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; + return local.closeTracker = new FakedTrackingVariable(local, location); + } + } + return null; + } + + /** if 'invocationSite' is a call to close() that has a registered tracking variable, answer that variable's binding. */ + public static LocalVariableBinding getTrackerForCloseCall(ASTNode invocationSite) { + if (invocationSite instanceof MessageSend) { + MessageSend send = (MessageSend) invocationSite; + if (CharOperation.equals(TypeConstants.CLOSE, send.selector) && send.receiver instanceof SingleNameReference) { + Binding receiverBinding = ((SingleNameReference)send.receiver).binding; + if (receiverBinding instanceof LocalVariableBinding) { + FakedTrackingVariable trackingVariable = ((LocalVariableBinding)receiverBinding).closeTracker; + if (trackingVariable != null) + return trackingVariable.binding; + } + } + } + return null; + } + + /** + * Check if the rhs of an assignment or local declaration is an (Auto)Closeable. + * If so create or re-use a tracking variable, and wire and initialize everything. + */ + public static void handleResourceAssignment(FlowInfo flowInfo, Statement location, Expression rhs, LocalVariableBinding local, + LocalVariableBinding previousTrackerBinding) + { + if (isAutoCloseable(rhs.resolvedType)) { + // new value is AutoCloseable, start tracking, possibly re-using existing tracker var: + + FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable(rhs); + if (rhsTrackVar != null) { // 1. share tracking variable with RHS? + local.closeTracker = rhsTrackVar; + // keep null-status unchanged across this assignment + } else if (previousTrackerBinding != null) { // 2. re-use tracking variable from the LHS? + // re-assigning from a fresh, mark as not-closed again: + flowInfo.markAsDefinitelyNull(previousTrackerBinding); + } else { // 3. no re-use, create a fresh tracking variable: + local.closeTracker = new FakedTrackingVariable(local, location); + // a fresh resource, mark as not-closed: + flowInfo.markAsDefinitelyNull(local.closeTracker.binding); +// TODO(stephan): this might be useful, but I could not find a test case for it: +// if (flowContext.initsOnFinally != null) +// flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding); + } + } + } + + /** Answer wither the given type binding is a subtype of java.lang.AutoCloseable. */ + public static boolean isAutoCloseable(TypeBinding typeBinding) { + return typeBinding instanceof ReferenceBinding + && ((ReferenceBinding)typeBinding).hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable); + } + + /** Mark that this resource is closed locally. */ + public void markClose(FlowInfo flowInfo, FlowContext flowContext) { + flowInfo.markAsDefinitelyNonNull(this.binding); + this.globalClosingState |= CLOSE_SEEN; +//TODO(stephan): this might be useful, but I could not find a test case for it: +// if (flowContext.initsOnFinally != null) +// flowContext.initsOnFinally.markAsDefinitelyNonNull(this.binding); + } + + /** Mark that this resource is closed from a nested method (inside a local class). */ + public void markClosedInNestedMethod() { + this.globalClosingState |= CLOSED_IN_NESTED_METHOD; + } + + /** + * Mark that this resource is passed to some outside code + * (as argument to a method/ctor call or as a return value from the current method), + * and thus should be considered as potentially closed. + */ + public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo) { + FakedTrackingVariable trackVar = getCloseTrackingVariable(expression); + if (trackVar != null) { + trackVar.globalClosingState |= PASSED_TO_OUTSIDE; + if (scope.methodScope() != trackVar.methodScope) + trackVar.globalClosingState |= CLOSED_IN_NESTED_METHOD; + // insert info that the tracked resource *may* be closed (by the target method, i.e.) + FlowInfo infoResourceIsClosed = flowInfo.copy(); + infoResourceIsClosed.markAsDefinitelyNonNull(trackVar.binding); + return FlowInfo.conditional(flowInfo, infoResourceIsClosed); + } + return flowInfo; + } + + public void recordErrorLocation(ASTNode location, int nullStatus) { + if (this.recordedLocations == null) + this.recordedLocations = new HashMap(); + this.recordedLocations.put(location, new Integer(nullStatus)); + } + + public boolean reportRecordedErrors(Scope scope) { + if (this.globalClosingState == 0) { + reportError(scope.problemReporter(), null, FlowInfo.NULL); + return true; + } + boolean hasReported = false; + if (this.recordedLocations != null) { + Iterator locations = this.recordedLocations.entrySet().iterator(); + while (locations.hasNext()) { + Map.Entry entry = (Entry) locations.next(); + reportError(scope.problemReporter(), (ASTNode)entry.getKey(), ((Integer)entry.getValue()).intValue()); + hasReported = true; + } + } + return hasReported; + } + + public void reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) { + if (nullStatus == FlowInfo.NULL) { + if ((this.globalClosingState & CLOSED_IN_NESTED_METHOD) != 0) + problemReporter.potentiallyUnclosedCloseable(this, location); + else + problemReporter.unclosedCloseable(this, location); + } else if (nullStatus == FlowInfo.POTENTIALLY_NULL) { + problemReporter.potentiallyUnclosedCloseable(this, location); + } + } + + public void reportExplicitClosing(ProblemReporter problemReporter) { + if ((this.globalClosingState & REPORTED) == 0) { + this.globalClosingState |= REPORTED; + problemReporter.explicitlyClosedAutoCloseable(this); + } + } +} diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java index 7f0b9b154..961180d42 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForStatement.java @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 349326 - [1.7] new warning for missing try-with-resources * Technical University Berlin - extended API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -139,7 +141,7 @@ public class ForStatement extends Statement { actionInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); } } - if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { + if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) { actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalInits(); } @@ -216,6 +218,17 @@ public class ForStatement extends Statement { exitBranch, isConditionOptimizedFalse, !isConditionTrue /*for(;;){}while(true); unreachable(); */); + // Variables initialized only for the purpose of the for loop can be removed for further flow info + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=359495 + if (this.initializations != null) { + for (int i = 0; i < this.initializations.length; i++) { + Statement init = this.initializations[i]; + if (init instanceof LocalDeclaration) { + LocalVariableBinding binding = ((LocalDeclaration) init).binding; + mergedInfo.resetAssignmentInfo(binding); + } + } + } this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); return mergedInfo; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java index 3a7b16c20..e2f171173 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Technical University Berlin - extended API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -112,13 +113,13 @@ public class ForeachStatement extends Statement { if (!(this.action == null || (this.action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) { - if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { + if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) { actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalCopy(); } // code generation can be optimized when no need to continue in the loop exitBranch = flowInfo.unconditionalCopy(). - addInitializationsFrom(condInfo.initsWhenFalse()); + addNullInfoFrom(condInfo.initsWhenFalse()); // TODO (maxime) no need to test when false: can optimize (same for action being unreachable above) if ((actionInfo.tagBits & loopingContext.initsOnContinue.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java index 7d0788e38..4cb445da4 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/IfStatement.java @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 349326 - [1.7] new warning for missing try-with-resources *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -84,12 +86,13 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl // No need if the whole if-else construct itself lies in unreachable code this.bits |= ASTNode.IsElseStatementUnreachable; } + boolean reportDeadCodeForKnownPattern = !isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement; if (this.thenStatement != null) { // Save info for code gen this.thenInitStateIndex = currentScope.methodScope().recordInitializationStates(thenFlowInfo); if (isConditionOptimizedFalse || ((this.bits & ASTNode.IsThenStatementUnreachable) != 0)) { - if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) { - this.thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, initialComplaintLevel); + if (reportDeadCodeForKnownPattern) { + this.thenStatement.complainIfUnreachable(thenFlowInfo, currentScope, initialComplaintLevel, false); } else { // its a known coding pattern which should be tolerated by dead code analysis // according to isKnowDeadCodePattern() @@ -117,8 +120,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl // Save info for code gen this.elseInitStateIndex = currentScope.methodScope().recordInitializationStates(elseFlowInfo); if (isConditionOptimizedTrue || ((this.bits & ASTNode.IsElseStatementUnreachable) != 0)) { - if (!isKnowDeadCodePattern(this.condition) || currentScope.compilerOptions().reportDeadCodeInTrivialIfStatement) { - this.elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, initialComplaintLevel); + if (reportDeadCodeForKnownPattern) { + this.elseStatement.complainIfUnreachable(elseFlowInfo, currentScope, initialComplaintLevel, false); } else { // its a known coding pattern which should be tolerated by dead code analysis // according to isKnowDeadCodePattern() @@ -127,6 +130,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); } + // process AutoCloseable resources closed in only one branch: + currentScope.correlateTrackingVarsIfElse(thenFlowInfo, elseFlowInfo); // merge THEN & ELSE initializations FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranchesIfElse( thenFlowInfo, @@ -135,7 +140,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl isConditionOptimizedFalse, true /*if(true){ return; } fake-reachable(); */, flowInfo, - this); + this, + reportDeadCodeForKnownPattern); this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); return mergedInfo; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java index 2ea75004c..18990568b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java @@ -12,6 +12,7 @@ * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE * bug 292478 - Report potentially null across variable assignment * bug 335093 - [compiler][null] minimal hook for future null annotation support + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -120,6 +121,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl this.initialization .analyseCode(currentScope, flowContext, flowInfo) .unconditionalInits(); + FakedTrackingVariable.handleResourceAssignment(flowInfo, this, this.initialization, this.binding, null); int nullStatus = this.initialization.nullStatus(flowInfo); if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes this.bits |= FirstAssignmentToLocal; 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 f201f4a0b..8a9a9194f 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 @@ -9,7 +9,9 @@ * Contributors: * IBM Corporation - initial API and implementation * Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752) - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -47,6 +49,7 @@ import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; 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.jdt.internal.compiler.problem.ProblemSeverities; @@ -147,6 +150,18 @@ public class MessageSend extends Expression implements InvocationSite { public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { boolean nonStatic = !this.binding.isStatic(); flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits(); + // recording the closing of AutoCloseable resources: + if (CharOperation.equals(TypeConstants.CLOSE, this.selector)) + { + FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.receiver); + if (trackingVariable != null) { // null happens if receiver is not a local variable or not an AutoCloseable + if (trackingVariable.methodScope == currentScope.methodScope()) { + trackingVariable.markClose(flowInfo, flowContext); + } else { + trackingVariable.markClosedInNestedMethod(); + } + } + } if (nonStatic) { this.receiver.checkNPE(currentScope, flowContext, flowInfo); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318682 @@ -167,6 +182,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); } + // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) + flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo); flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java index 85cb80304..2f9645090 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java @@ -8,6 +8,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -21,8 +22,8 @@ import org.eclipse.jdt.internal.compiler.ASTVisitor; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; @@ -77,7 +78,7 @@ public class MethodDeclaration extends AbstractMethodDeclaration { super(compilationResult); } - public void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo flowInfo) { + public void analyseCode(ClassScope classScope, FlowContext flowContext, FlowInfo flowInfo) { // starting of the code analysis for methods if (this.ignoreFurtherInvestigation) return; @@ -121,7 +122,7 @@ public class MethodDeclaration extends AbstractMethodDeclaration { ExceptionHandlingFlowContext methodContext = new ExceptionHandlingFlowContext( - initializationContext, + flowContext, this, this.binding.thrownExceptions, null, @@ -150,7 +151,7 @@ public class MethodDeclaration extends AbstractMethodDeclaration { int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) == 0 ? Statement.NOT_COMPLAINED : Statement.COMPLAINED_FAKE_REACHABLE; for (int i = 0, count = this.statements.length; i < count; i++) { Statement stat = this.statements[i]; - if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { + if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) { flowInfo = stat.analyseCode(this.scope, methodContext, flowInfo); } } @@ -187,6 +188,7 @@ public class MethodDeclaration extends AbstractMethodDeclaration { } } + this.scope.checkUnclosedCloseables(flowInfo, null/*don't report against a specific location*/, null); } catch (AbortMethod e) { this.ignoreFurtherInvestigation = true; } 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 c9e36db40..f376efead 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 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -128,6 +130,11 @@ public static abstract class AbstractQualifiedAllocationExpression extends Alloc // analyse the enclosing instance if (this.enclosingInstance != null) { flowInfo = this.enclosingInstance.analyseCode(currentScope, flowContext, flowInfo); + } else { + if (this.binding.declaringClass.superclass().isMemberType() && !this.binding.declaringClass.superclass().isStatic()) { + // creating an anonymous type of a non-static member type without an enclosing instance of parent type + currentScope.resetEnclosingMethodStaticFlag(); + } } // check captured variables are initialized in current context (26134) @@ -141,6 +148,8 @@ public static abstract class AbstractQualifiedAllocationExpression extends Alloc // process arguments if (this.arguments != null) { for (int i = 0, count = this.arguments.length; i < count; i++) { + // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) + flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.arguments[i], flowInfo); flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo); if ((this.arguments[i].implicitConversion & TypeIds.UNBOXING) != 0) { this.arguments[i].checkNPE(currentScope, flowContext, flowInfo); 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 8d97f740f..b8f74828b 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 @@ -7,7 +7,10 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 349326 - [1.7] new warning for missing try-with-resources + * bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop) * Technical University Berlin - extended API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -41,14 +44,23 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl // lookup the label, this should answer the returnContext + MethodScope methodScope = currentScope.methodScope(); if (this.expression != null) { flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { this.expression.checkNPE(currentScope, flowContext, flowInfo); } + FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.expression); + if (trackingVariable != null) { + if (methodScope != trackingVariable.methodScope) + trackingVariable.markClosedInNestedMethod(); + // don't report issues concerning this local, since by returning + // the method passes the responsibility to the caller: + currentScope.removeTrackingVar(trackingVariable); + } } this.initStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); + methodScope.recordInitializationStates(flowInfo); // compute the return sequence (running the finally blocks) FlowContext traversedContext = flowContext; int subCount = 0; @@ -85,14 +97,14 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl } saveValueNeeded = true; this.initStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); + methodScope.recordInitializationStates(flowInfo); } } } else if (traversedContext instanceof InitializationFlowContext) { currentScope.problemReporter().cannotReturnInInitializer(this); return FlowInfo.DEAD_END; } - } while ((traversedContext = traversedContext.parent) != null); + } while ((traversedContext = traversedContext.getLocalParent()) != null); // resize subroutines if ((this.subroutines != null) && (subCount != this.subroutines.length)) { @@ -110,6 +122,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl this.expression.bits |= ASTNode.IsReturnedValue; } } + currentScope.checkUnclosedCloseables(flowInfo, this, currentScope); return FlowInfo.DEAD_END; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java index 5a3bc4c2a..a45b8447e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java @@ -8,7 +8,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 335093 - [compiler][null] minimal hook for future null annotation support + * Stephan Herrmann - Contributions for + * bug 335093 - [compiler][null] minimal hook for future null annotation support + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -82,7 +84,7 @@ public void branchChainTo(BranchLabel label) { // Report an error if necessary (if even more unreachable than previously reported // complaintLevel = 0 if was reachable up until now, 1 if fake reachable (deadcode), 2 if fatal unreachable (error) -public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int previousComplaintLevel) { +public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int previousComplaintLevel, boolean endOfBlock) { if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0) { if ((flowInfo.reachMode() & FlowInfo.UNREACHABLE_OR_DEAD) != 0) this.bits &= ~ASTNode.IsReachable; @@ -104,6 +106,8 @@ public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int previo if (previousComplaintLevel < COMPLAINED_UNREACHABLE) { /* OT: */ if (shouldReport) scope.problemReporter().unreachableCode(this); + if (endOfBlock) + scope.checkUnclosedCloseables(flowInfo, null, null); } return COMPLAINED_UNREACHABLE; } else { @@ -111,6 +115,8 @@ public int complainIfUnreachable(FlowInfo flowInfo, BlockScope scope, int previo /* OT: */ if (shouldReport) // SH} scope.problemReporter().fakeReachable(this); + if (endOfBlock) + scope.checkUnclosedCloseables(flowInfo, null, null); } return COMPLAINED_FAKE_REACHABLE; } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java index 5b171fc00..03c6e80ba 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 349326 - [1.7] new warning for missing try-with-resources *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -99,7 +101,7 @@ public class SwitchStatement extends Statement { } else { fallThroughState = FALLTHROUGH; // reset below if needed } - if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel)) < Statement.COMPLAINED_UNREACHABLE) { + if ((complaintLevel = statement.complainIfUnreachable(caseInits, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) { caseInits = statement.analyseCode(this.scope, switchContext, caseInits); if (caseInits == FlowInfo.DEAD_END) { fallThroughState = ESCAPING; @@ -461,6 +463,9 @@ public class SwitchStatement extends Statement { break checkType; } else if (expressionType.isEnum()) { isEnumSwitch = true; + if (upperScope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_5) { + upperScope.problemReporter().incorrectSwitchType(this.expression, expressionType); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=360317 + } break checkType; } else if (upperScope.isBoxingCompatibleWith(expressionType, TypeBinding.INT)) { this.expression.computeConversion(upperScope, TypeBinding.INT, expressionType); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java index 89b1b5f6e..252962940 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -8,6 +8,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -46,6 +47,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl this.exception.checkNPE(currentScope, flowContext, flowInfo); // need to check that exception thrown is actually caught somewhere flowContext.checkExceptionHandlers(this.exceptionType, this, flowInfo, currentScope); + currentScope.checkUnclosedCloseables(flowInfo, this, currentScope); return FlowInfo.DEAD_END; } 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 5944bb3f0..0e761c37f 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 @@ -7,7 +7,11 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 332637 - Dead Code detection removing code that isn't dead + * Stephan Herrmann - Contributions for + * bug 332637 - Dead Code detection removing code that isn't dead + * bug 358827 - [1.7] exception analysis for t-w-r spoils null analysis + * bug 349326 - [1.7] new warning for missing try-with-resources + * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -138,8 +142,14 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl for (int i = 0; i < resourcesLength; i++) { flowInfo = this.resources[i].analyseCode(currentScope, handlingContext, flowInfo.copy()); this.postResourcesInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(flowInfo); - this.resources[i].binding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways. - TypeBinding type = this.resources[i].binding.type; + LocalVariableBinding resourceBinding = this.resources[i].binding; + 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 = null; + } + TypeBinding type = resourceBinding.type; if (type != null && type.isValidBinding()) { ReferenceBinding binding = (ReferenceBinding) type; MethodBinding closeMethod = binding.getExactMethod(ConstantPool.Close, new TypeBinding [0], this.scope.compilationUnitScope()); // scope needs to be tighter @@ -243,6 +253,14 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl if (subInfo == FlowInfo.DEAD_END) { this.bits |= ASTNode.IsSubRoutineEscaping; this.scope.problemReporter().finallyMustCompleteNormally(this.finallyBlock); + } else { + // for resource analysis we need the finallyInfo in these nested scopes: + FlowInfo finallyInfo = subInfo.copy(); + this.tryBlock.scope.finallyInfo = finallyInfo; + if (this.catchBlocks != null) { + for (int i = 0; i < this.catchBlocks.length; i++) + this.catchBlocks[i].scope.finallyInfo = finallyInfo; + } } this.subRoutineInits = subInfo; // process the try block in a context handling the local exceptions. @@ -264,15 +282,21 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl for (int i = 0; i < resourcesLength; i++) { flowInfo = this.resources[i].analyseCode(currentScope, handlingContext, flowInfo.copy()); this.postResourcesInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(flowInfo); - this.resources[i].binding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways. - TypeBinding type = this.resources[i].binding.type; + LocalVariableBinding resourceBinding = this.resources[i].binding; + 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 = null; + } + TypeBinding type = resourceBinding.type; if (type != null && type.isValidBinding()) { ReferenceBinding binding = (ReferenceBinding) type; MethodBinding closeMethod = binding.getExactMethod(ConstantPool.Close, new TypeBinding [0], this.scope.compilationUnitScope()); // scope needs to be tighter if (closeMethod != null && closeMethod.returnType.id == TypeIds.T_void) { ReferenceBinding[] thrownExceptions = closeMethod.thrownExceptions; for (int j = 0, length = thrownExceptions.length; j < length; j++) { - handlingContext.checkExceptionHandlers(thrownExceptions[j], this.resources[j], flowInfo, currentScope); + handlingContext.checkExceptionHandlers(thrownExceptions[j], this.resources[i], flowInfo, currentScope, true); } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java index 816e5adf4..bf4634e42 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java @@ -8,6 +8,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for Bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop) * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -1178,7 +1179,11 @@ private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) { this.scope.problemReporter().unusedPrivateType(this); } } - InitializationFlowContext initializerContext = new InitializationFlowContext(null, this, flowInfo, flowContext, this.initializerScope); + // for local classes we use the flowContext as our parent, but never use an initialization context for this purpose + // see Bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop) + FlowContext parentContext = (flowContext instanceof InitializationFlowContext) ? null : flowContext; + InitializationFlowContext initializerContext = new InitializationFlowContext(parentContext, this, flowInfo, flowContext, this.initializerScope); + // no static initializer in local classes, thus no need to set parent: InitializationFlowContext staticInitializerContext = new InitializationFlowContext(null, this, flowInfo, flowContext, this.staticInitializerScope); FlowInfo nonStaticFieldInfo = flowInfo.unconditionalFieldLessCopy(); FlowInfo staticFieldInfo = flowInfo.unconditionalFieldLessCopy(); @@ -1252,8 +1257,9 @@ private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) { continue; // SH} if (method.isInitializationMethod()) { + // pass down the appropriate initializerContext: if (method.isStatic()) { // <clinit> - method.analyseCode( + ((Clinit)method).analyseCode( this.scope, staticInitializerContext, staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo)); @@ -1261,7 +1267,8 @@ private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) { ((ConstructorDeclaration)method).analyseCode(this.scope, initializerContext, constructorInfo.copy(), flowInfo.reachMode()); } } else { // regular method - method.analyseCode(this.scope, null, flowInfo.copy()); + // pass down the parentContext (NOT an initializer context, see above): + ((MethodDeclaration)method).analyseCode(this.scope, parentContext, flowInfo.copy()); } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java index c51042e38..e35ea9c0b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * Stephan Herrmann - Contributions for + * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE + * bug 349326 - [1.7] new warning for missing try-with-resources *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; @@ -113,7 +115,7 @@ public class WhileStatement extends Statement { currentScope.methodScope().recordInitializationStates( condInfo.initsWhenTrue()); - if (this.action.complainIfUnreachable(actionInfo, currentScope, initialComplaintLevel) < Statement.COMPLAINED_UNREACHABLE) { + if (this.action.complainIfUnreachable(actionInfo, currentScope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) { actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java index 6d9a4e611..ba8c821f6 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -79,6 +79,9 @@ public interface ClassFileConstants { int MethodRefTag = 10; int InterfaceMethodRefTag = 11; int NameAndTypeTag = 12; + int MethodHandleTag = 15; + int MethodTypeTag = 16; + int InvokeDynamicTag = 18; int ConstantMethodRefFixedSize = 5; int ConstantClassFixedSize = 3; @@ -91,6 +94,9 @@ public interface ClassFileConstants { int ConstantStringFixedSize = 3; int ConstantUtf8FixedSize = 3; int ConstantNameAndTypeFixedSize = 5; + int ConstantMethodHandleFixedSize = 4; + int ConstantMethodTypeFixedSize = 3; + int ConstantInvokeDynamicFixedSize = 5; int MAJOR_VERSION_1_1 = 45; int MAJOR_VERSION_1_2 = 46; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java index 3a9e1630c..d274fc676 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -247,6 +247,19 @@ public ClassFileReader(byte[] classFileBytes, char[] fileName, boolean fullyInit case ClassFileConstants.NameAndTypeTag : this.constantPoolOffsets[i] = readOffset; readOffset += ClassFileConstants.ConstantNameAndTypeFixedSize; + break; + case ClassFileConstants.MethodHandleTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ClassFileConstants.ConstantMethodHandleFixedSize; + break; + case ClassFileConstants.MethodTypeTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ClassFileConstants.ConstantMethodTypeFixedSize; + break; + case ClassFileConstants.InvokeDynamicTag : + this.constantPoolOffsets[i] = readOffset; + readOffset += ClassFileConstants.ConstantInvokeDynamicFixedSize; + break; } } //{ObjectTeams: store offset diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java index c137b4276..5cb416656 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java @@ -252,4 +252,9 @@ public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding lo return (this.initsWhenTrue.isMarkedAsNullOrNonNullInAssertExpression(local) || this.initsWhenFalse.isMarkedAsNullOrNonNullInAssertExpression(local)); } + +public void resetAssignmentInfo(LocalVariableBinding local) { + this.initsWhenTrue.resetAssignmentInfo(local); + this.initsWhenFalse.resetAssignmentInfo(local); +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java index 059058378..7f7638d01 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FinallyFlowContext.java @@ -70,12 +70,12 @@ public void complainOnDeferredChecks(FlowInfo flowInfo, BlockScope scope) { // any reference reported at this level is removed from the parent context // where it could also be reported again if (complained) { - FlowContext currentContext = this.parent; + FlowContext currentContext = this.getLocalParent(); while (currentContext != null) { //if (currentContext.isSubRoutine()) { currentContext.removeFinalAssignmentIfAny(this.finalAssignments[i]); //} - currentContext = currentContext.parent; + currentContext = currentContext.getLocalParent(); } } } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java index e768ff0da..ccb5fb62b 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java @@ -7,13 +7,15 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 358827 - [1.7] exception analysis for t-w-r spoils null analysis *******************************************************************************/ package org.eclipse.jdt.internal.compiler.flow; import java.util.ArrayList; + import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.LabeledStatement; import org.eclipse.jdt.internal.compiler.ast.Reference; @@ -197,14 +199,16 @@ public void checkExceptionHandlers(TypeBinding raisedException, ASTNode location traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); - if (traversedContext instanceof InsideSubRoutineFlowContext) { - ASTNode node = traversedContext.associatedNode; - if (node instanceof TryStatement) { - TryStatement tryStatement = (TryStatement) node; - flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + if (!isExceptionOnAutoClose) { + if (traversedContext instanceof InsideSubRoutineFlowContext) { + ASTNode node = traversedContext.associatedNode; + if (node instanceof TryStatement) { + TryStatement tryStatement = (TryStatement) node; + flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits + } } } - traversedContext = traversedContext.parent; + traversedContext = traversedContext.getLocalParent(); } // if reaches this point, then there are some remaining unhandled exception types. if (isExceptionOnAutoClose) { @@ -350,7 +354,7 @@ public void checkExceptionHandlers(TypeBinding[] raisedExceptions, ASTNode locat flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits } } - traversedContext = traversedContext.parent; + traversedContext = traversedContext.getLocalParent(); } // if reaches this point, then there are some remaining unhandled exception types. nextReport: for (int i = 0; i < raisedCount; i++) { @@ -382,9 +386,9 @@ public FlowInfo getInitsForFinalBlankInitializationCheck(TypeBinding declaringTy current = initializationContext.initializationParent; } else if (current instanceof ExceptionHandlingFlowContext) { ExceptionHandlingFlowContext exceptionContext = (ExceptionHandlingFlowContext) current; - current = exceptionContext.initializationParent == null ? exceptionContext.parent : exceptionContext.initializationParent; + current = exceptionContext.initializationParent == null ? exceptionContext.getLocalParent() : exceptionContext.initializationParent; } else { - current = current.parent; + current = current.getLocalParent(); } } while (current != null); // not found @@ -408,7 +412,7 @@ public FlowContext getTargetContextForBreakLabel(char[] labelName) { return current; return lastNonReturningSubRoutine; } - current = current.parent; + current = current.getLocalParent(); } // not found return null; @@ -445,7 +449,7 @@ public FlowContext getTargetContextForContinueLabel(char[] labelName) { // label is found, but not a continuable location return FlowContext.NotContinuableContext; } - current = current.parent; + current = current.getLocalParent(); } // not found return null; @@ -464,7 +468,7 @@ public FlowContext getTargetContextForDefaultBreak() { if (lastNonReturningSubRoutine == null) return current; return lastNonReturningSubRoutine; } - current = current.parent; + current = current.getLocalParent(); } // not found return null; @@ -484,12 +488,22 @@ public FlowContext getTargetContextForDefaultContinue() { return current; return lastNonReturningSubRoutine; } - current = current.parent; + current = current.getLocalParent(); } // not found return null; } +/** + * Answer the parent flow context but be careful not to cross the boundary of a nested type, + * or null if no such parent exists. + */ +public FlowContext getLocalParent() { + if (this.associatedNode instanceof AbstractMethodDeclaration || this.associatedNode instanceof TypeDeclaration) + return null; + return this.parent; +} + public String individualToString() { return "Flow context"; //$NON-NLS-1$ } @@ -567,7 +581,7 @@ public void recordSettingFinal(VariableBinding variable, Reference finalReferenc if (!context.recordFinalAssignment(variable, finalReference)) { break; // no need to keep going } - context = context.parent; + context = context.getLocalParent(); } } } 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 fbd9d11f5..177ceaf3b 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 @@ -417,12 +417,28 @@ public static UnconditionalFlowInfo mergedOptimizedBranches( public static UnconditionalFlowInfo mergedOptimizedBranchesIfElse( FlowInfo initsWhenTrue, boolean isOptimizedTrue, FlowInfo initsWhenFalse, boolean isOptimizedFalse, - boolean allowFakeDeadBranch, FlowInfo flowInfo, IfStatement ifStatement) { + boolean allowFakeDeadBranch, FlowInfo flowInfo, IfStatement ifStatement, + boolean reportDeadCodeInKnownPattern) { UnconditionalFlowInfo mergedInfo; if (isOptimizedTrue){ if (initsWhenTrue == FlowInfo.DEAD_END && allowFakeDeadBranch) { - mergedInfo = initsWhenFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD). - unconditionalInits(); + if (!reportDeadCodeInKnownPattern) { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=256796 + // do not report code even after if-else as dead as a consequence of analysis done in known dead code pattern + // when the CompilerOptions$reportDeadCodeInTrivialIfStatement option is disabled + if (ifStatement.elseStatement == null) { + mergedInfo = flowInfo.unconditionalInits(); + } else { + mergedInfo = initsWhenFalse.unconditionalInits(); + if (initsWhenFalse != FlowInfo.DEAD_END) { + // let the definitely true status of known dead code pattern not affect the reachability + mergedInfo.setReachMode(flowInfo.reachMode()); + } + } + } else { + mergedInfo = initsWhenFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD). + unconditionalInits(); + } } else { mergedInfo = @@ -433,8 +449,23 @@ public static UnconditionalFlowInfo mergedOptimizedBranchesIfElse( } else if (isOptimizedFalse) { if (initsWhenFalse == FlowInfo.DEAD_END && allowFakeDeadBranch) { - mergedInfo = initsWhenTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD). - unconditionalInits(); + if (!reportDeadCodeInKnownPattern) { + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=256796 + // do not report code even after if-else as dead as a consequence of analysis done in known dead code pattern + // when the CompilerOptions$reportDeadCodeInTrivialIfStatement option is disabled + if (ifStatement.thenStatement == null) { + mergedInfo = flowInfo.unconditionalInits(); + } else { + mergedInfo = initsWhenTrue.unconditionalInits(); + if (initsWhenTrue != FlowInfo.DEAD_END) { + // let the definitely false status of known dead code pattern not affect the reachability + mergedInfo.setReachMode(flowInfo.reachMode()); + } + } + } else { + mergedInfo = initsWhenTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD). + unconditionalInits(); + } } else { mergedInfo = @@ -591,6 +622,12 @@ abstract public void markedAsNullOrNonNullInAssertExpression(LocalVariableBindin //https://bugs.eclipse.org/bugs/show_bug.cgi?id=303448 abstract public boolean isMarkedAsNullOrNonNullInAssertExpression(LocalVariableBinding local); +/** + * Resets the definite and potential initialization info for the given local variable + * @param local + */ +abstract public void resetAssignmentInfo(LocalVariableBinding local); + //{ObjectTeams: public boolean isDefinitelyAssigned(BaseCallTrackingVariable baseCallTrackingVariable) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java index 33743133f..88ca4e766 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/LabelFlowContext.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -31,14 +31,14 @@ public LabelFlowContext(FlowContext parent, ASTNode associatedNode, char[] label void checkLabelValidity(BlockScope scope) { // check if label was already defined above - FlowContext current = this.parent; + FlowContext current = this.getLocalParent(); while (current != null) { char[] currentLabelName; if (((currentLabelName = current.labelName()) != null) && CharOperation.equals(currentLabelName, this.labelName)) { scope.problemReporter().alreadyDefinedLabel(this.labelName, this.associatedNode); } - current = current.parent; + current = current.getLocalParent(); } } 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 886fea6ef..919bb4c2e 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 @@ -112,10 +112,10 @@ public void complainOnDeferredFinalChecks(BlockScope scope, FlowInfo flowInfo) { // any reference reported at this level is removed from the parent context where it // could also be reported again if (complained) { - FlowContext context = this.parent; + FlowContext context = this.getLocalParent(); while (context != null) { context.removeFinalAssignmentIfAny(this.finalAssignments[i]); - context = context.parent; + context = context.getLocalParent(); } } } @@ -396,6 +396,7 @@ public void recordContinueFrom(FlowContext innerFlowContext, FlowInfo flowInfo) FlowContext inner = innerFlowContext; while (inner != this && !(inner instanceof LoopingFlowContext)) { inner = inner.parent; + // we know that inner is reachable from this without crossing a type boundary } if (inner == this) { this.upstreamNullFlowInfo. 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 2e2fef88e..5bc2d8565 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 @@ -14,6 +14,7 @@ * bug 292478 - Report potentially null across variable assignment * bug 332637 - Dead Code detection removing code that isn't dead * bug 341499 - [compiler][null] allocate extra bits in all methods of UnconditionalFlowInfo + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -785,7 +786,7 @@ final public boolean isDefinitelyNonNull(LocalVariableBinding local) { } int vectorIndex; if ((vectorIndex = (position / BitCacheSize) - 1) - >= this.extra[0].length) { + >= this.extra[2].length) { return false; // if not enough room in vector, then not initialized } return ((this.extra[2][vectorIndex] & this.extra[4][vectorIndex] @@ -812,7 +813,7 @@ final public boolean isDefinitelyNull(LocalVariableBinding local) { } int vectorIndex; if ((vectorIndex = (position / BitCacheSize) - 1) >= - this.extra[0].length) { + this.extra[2].length) { return false; // if not enough room in vector, then not initialized } return ((this.extra[2][vectorIndex] & this.extra[3][vectorIndex] @@ -837,7 +838,7 @@ final public boolean isDefinitelyUnknown(LocalVariableBinding local) { } int vectorIndex; if ((vectorIndex = (position / BitCacheSize) - 1) >= - this.extra[0].length) { + this.extra[2].length) { return false; // if not enough room in vector, then not initialized } return ((this.extra[2][vectorIndex] & this.extra[5][vectorIndex] @@ -904,7 +905,7 @@ final public boolean isPotentiallyNonNull(LocalVariableBinding local) { } int vectorIndex; if ((vectorIndex = (position / BitCacheSize) - 1) >= - this.extra[0].length) { + this.extra[2].length) { return false; // if not enough room in vector, then not initialized } return ((this.extra[4][vectorIndex] @@ -930,7 +931,7 @@ final public boolean isPotentiallyNull(LocalVariableBinding local) { } int vectorIndex; if ((vectorIndex = (position / BitCacheSize) - 1) >= - this.extra[0].length) { + this.extra[2].length) { return false; // if not enough room in vector, then not initialized } return ((this.extra[3][vectorIndex] @@ -956,7 +957,7 @@ final public boolean isPotentiallyUnknown(LocalVariableBinding local) { } int vectorIndex; if ((vectorIndex = (position / BitCacheSize) - 1) >= - this.extra[0].length) { + this.extra[2].length) { return false; // if not enough room in vector, then not initialized } return (this.extra[5][vectorIndex] @@ -2152,5 +2153,29 @@ private void combineNullStatusChangeInAssertInfo(UnconditionalFlowInfo otherInit } } } + +public void resetAssignmentInfo(LocalVariableBinding local) { + resetAssignmentInfo(local.id + this.maxFieldCount); +} + +public void resetAssignmentInfo(int position) { + if (this != DEAD_END) { + // position is zero-based + if (position < BitCacheSize) { + // use bits + long mask; + this.definiteInits &= (mask = ~(1L << position)); + this.potentialInits &= mask; + } else { + // use extra vector + int vectorIndex = (position / BitCacheSize) - 1; + if (this.extra == null || vectorIndex >= this.extra[0].length) return; // variable doesnt exist in flow info + long mask; + this.extra[0][vectorIndex] &= + (mask = ~(1L << (position % BitCacheSize))); + this.extra[1][vectorIndex] &= mask; + } + } +} } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java index 621321775..3bcb529ca 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java @@ -8,8 +8,10 @@ * Contributors: * IBM Corporation - initial API and implementation * Benjamin Muskalla - Contribution for bug 239066 - * Stephan Herrmann - Contribution for bug 236385 - * Stephan Herrmann - Contribution for bug 295551 + * Stephan Herrmann - Contributions for + * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used + * bug 295551 - Add option to automatically promote all warnings to errors + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -146,6 +148,9 @@ public class CompilerOptions { public static final String OPTION_ReportMethodCanBeStatic = "org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic"; //$NON-NLS-1$ public static final String OPTION_ReportMethodCanBePotentiallyStatic = "org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic"; //$NON-NLS-1$ public static final String OPTION_ReportRedundantSpecificationOfTypeArguments = "org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments"; //$NON-NLS-1$ + public static final String OPTION_ReportUnclosedCloseable = "org.eclipse.jdt.core.compiler.problem.unclosedCloseable"; //$NON-NLS-1$ + public static final String OPTION_ReportPotentiallyUnclosedCloseable = "org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable"; //$NON-NLS-1$ + public static final String OPTION_ReportExplicitlyClosedAutoCloseable = "org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable"; //$NON-NLS-1$ //{ObjectTeams: sync with constants in OTDTPlugin: public static final String OPTION_ReportNotExactlyOneBasecall = @@ -317,6 +322,10 @@ public class CompilerOptions { public static final int MethodCanBeStatic = IrritantSet.GROUP2 | ASTNode.Bit5; public static final int MethodCanBePotentiallyStatic = IrritantSet.GROUP2 | ASTNode.Bit6; public static final int RedundantSpecificationOfTypeArguments = IrritantSet.GROUP2 | ASTNode.Bit7; + // bits 8-10 reserved for https://bugs.eclipse.org/bugs/show_bug.cgi?id=186342 + public static final int UnclosedCloseable = IrritantSet.GROUP2 | ASTNode.Bit11; + public static final int PotentiallyUnclosedCloseable = IrritantSet.GROUP2 | ASTNode.Bit12; + public static final int ExplicitlyClosedAutoCloseable = IrritantSet.GROUP2 | ASTNode.Bit13; //{ObjectTeams: OT/J specific problems/irritants: public static final int OTJFlag = IrritantSet.GROUP3; @@ -487,8 +496,9 @@ public class CompilerOptions { "javadoc", //$NON-NLS-1$ "nls", //$NON-NLS-1$ "null", //$NON-NLS-1$ - "restriction", //$NON-NLS-1$ "rawtypes", //$NON-NLS-1$ + "resource", //$NON-NLS-1$ + "restriction", //$NON-NLS-1$ "serial", //$NON-NLS-1$ "static-access", //$NON-NLS-1$ "static-method", //$NON-NLS-1$ @@ -682,6 +692,12 @@ public class CompilerOptions { return OPTION_ReportMethodCanBePotentiallyStatic; case RedundantSpecificationOfTypeArguments : return OPTION_ReportRedundantSpecificationOfTypeArguments; + case UnclosedCloseable : + return OPTION_ReportUnclosedCloseable; + case PotentiallyUnclosedCloseable : + return OPTION_ReportPotentiallyUnclosedCloseable; + case ExplicitlyClosedAutoCloseable : + return OPTION_ReportExplicitlyClosedAutoCloseable; //{ObjectTeams: case NotExactlyOneBasecall : return OPTION_ReportNotExactlyOneBasecall; @@ -891,6 +907,9 @@ public class CompilerOptions { OPTION_ReportUnusedTypeArgumentsForMethodInvocation, OPTION_ReportUnusedWarningToken, OPTION_ReportVarargsArgumentNeedCast, + OPTION_ReportUnclosedCloseable, + OPTION_ReportPotentiallyUnclosedCloseable, + OPTION_ReportExplicitlyClosedAutoCloseable, //{ObjectTeams: OPTION_ReportNotExactlyOneBasecall, OPTION_ReportBaseclassCycle, @@ -984,6 +1003,10 @@ public class CompilerOptions { case MethodCanBeStatic : case MethodCanBePotentiallyStatic : return "static-method"; //$NON-NLS-1$ + case PotentiallyUnclosedCloseable: + case UnclosedCloseable: + case ExplicitlyClosedAutoCloseable: + return "resource"; //$NON-NLS-1$ case InvalidJavadoc : case MissingJavadocComments : case MissingJavadocTags: @@ -1082,6 +1105,8 @@ public class CompilerOptions { case 'r' : if ("rawtypes".equals(warningToken)) //$NON-NLS-1$ return IrritantSet.RAW; + if ("resource".equals(warningToken)) //$NON-NLS-1$ + return IrritantSet.RESOURCE; if ("restriction".equals(warningToken)) //$NON-NLS-1$ return IrritantSet.RESTRICTION; break; @@ -1282,6 +1307,9 @@ public class CompilerOptions { optionsMap.put(OPTION_ReportMethodCanBeStatic, getSeverityString(MethodCanBeStatic)); optionsMap.put(OPTION_ReportMethodCanBePotentiallyStatic, getSeverityString(MethodCanBePotentiallyStatic)); optionsMap.put(OPTION_ReportRedundantSpecificationOfTypeArguments, getSeverityString(RedundantSpecificationOfTypeArguments)); + optionsMap.put(OPTION_ReportUnclosedCloseable, getSeverityString(UnclosedCloseable)); + optionsMap.put(OPTION_ReportPotentiallyUnclosedCloseable, getSeverityString(PotentiallyUnclosedCloseable)); + optionsMap.put(OPTION_ReportExplicitlyClosedAutoCloseable, getSeverityString(ExplicitlyClosedAutoCloseable)); //{ObjectTeams: optionsMap.put(OPTION_Decapsulation, this.decapsulation); @@ -1744,6 +1772,9 @@ public class CompilerOptions { if ((optionValue = optionsMap.get(OPTION_ReportMethodCanBeStatic)) != null) updateSeverity(MethodCanBeStatic, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportMethodCanBePotentiallyStatic)) != null) updateSeverity(MethodCanBePotentiallyStatic, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportRedundantSpecificationOfTypeArguments)) != null) updateSeverity(RedundantSpecificationOfTypeArguments, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportUnclosedCloseable)) != null) updateSeverity(UnclosedCloseable, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportPotentiallyUnclosedCloseable)) != null) updateSeverity(PotentiallyUnclosedCloseable, optionValue); + if ((optionValue = optionsMap.get(OPTION_ReportExplicitlyClosedAutoCloseable)) != null) updateSeverity(ExplicitlyClosedAutoCloseable, optionValue); //{ObjectTeams: if ((optionValue = optionsMap.get(OPTION_ReportNotExactlyOneBasecall)) != null) updateSeverity(NotExactlyOneBasecall, optionValue); if ((optionValue = optionsMap.get(OPTION_ReportBaseclassCycle)) != null) updateSeverity(BaseclassCycle, optionValue); @@ -2005,6 +2036,9 @@ public class CompilerOptions { buf.append("\n\t- method can be static: ").append(getSeverityString(MethodCanBeStatic)); //$NON-NLS-1$ buf.append("\n\t- method can be potentially static: ").append(getSeverityString(MethodCanBePotentiallyStatic)); //$NON-NLS-1$ buf.append("\n\t- redundant specification of type arguments: ").append(getSeverityString(RedundantSpecificationOfTypeArguments)); //$NON-NLS-1$ + buf.append("\n\t- resource is not closed: ").append(getSeverityString(UnclosedCloseable)); //$NON-NLS-1$ + buf.append("\n\t- resource may not be closed: ").append(getSeverityString(PotentiallyUnclosedCloseable)); //$NON-NLS-1$ + buf.append("\n\t- resource should be handled by try-with-resources: ").append(getSeverityString(ExplicitlyClosedAutoCloseable)); //$NON-NLS-1$ //{ObjectTeams buf.append("\n\t- decapsulation : ").append(this.decapsulation); //$NON-NLS-1$ buf.append("\n\t- report if not exactly one basecall in callin method : ").append(getSeverityString(NotExactlyOneBasecall)); //$NON-NLS-1$ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java index 38e7b0672..f10e7ce16 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -68,6 +69,7 @@ public class IrritantSet { public static final IrritantSet UNUSED = new IrritantSet(CompilerOptions.UnusedLocalVariable); public static final IrritantSet UNCHECKED = new IrritantSet(CompilerOptions.UncheckedTypeOperation); public static final IrritantSet UNQUALIFIED_FIELD_ACCESS = new IrritantSet(CompilerOptions.UnqualifiedFieldAccess); + public static final IrritantSet RESOURCE = new IrritantSet(CompilerOptions.UnclosedCloseable); public static final IrritantSet JAVADOC = new IrritantSet(CompilerOptions.InvalidJavadoc); public static final IrritantSet COMPILER_DEFAULT_ERRORS = new IrritantSet(0); // no optional error by default @@ -174,7 +176,8 @@ public class IrritantSet { // group-2 warnings enabled by default .set( CompilerOptions.DeadCode - |CompilerOptions.Tasks); + |CompilerOptions.Tasks + |CompilerOptions.UnclosedCloseable); ALL.setAll(); HIDING @@ -199,6 +202,9 @@ public class IrritantSet { .set(CompilerOptions.RedundantSpecificationOfTypeArguments); STATIC_METHOD .set(CompilerOptions.MethodCanBePotentiallyStatic); + RESOURCE + .set(CompilerOptions.PotentiallyUnclosedCloseable) + .set(CompilerOptions.ExplicitlyClosedAutoCloseable); String suppressRawWhenUnchecked = System.getProperty("suppressRawWhenUnchecked"); //$NON-NLS-1$ if (suppressRawWhenUnchecked != null && "true".equalsIgnoreCase(suppressRawWhenUnchecked)) { //$NON-NLS-1$ UNCHECKED.set(CompilerOptions.RawTypeReference); diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java index c2d4e4f8b..c0defeaa3 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -1356,6 +1357,18 @@ public TypeVariableBinding getTypeVariable(char[] variableName) { variable.resolve(); return variable; } +public boolean hasTypeBit(int bit) { + // ensure hierarchy is resolved, which will propagate bits down to us + boolean wasToleratingMissingTypeProcessingAnnotations = this.environment.mayTolerateMissingType; + this.environment.mayTolerateMissingType = true; + try { + superclass(); + superInterfaces(); + } finally { + this.environment.mayTolerateMissingType = wasToleratingMissingTypeProcessingAnnotations; + } + return (this.typeBits & bit) != 0; +} private void initializeTypeVariable(TypeVariableBinding variable, TypeVariableBinding[] existingVariables, SignatureWrapper wrapper, char[][][] missingTypeNames) { // ParameterSignature = Identifier ':' TypeSignature // or Identifier ':' TypeSignature(optional) InterfaceBound(s) @@ -1561,8 +1574,20 @@ public ReferenceBinding superclass() { // finish resolving the type this.superclass = (ReferenceBinding) resolveType(this.superclass, this.environment, true /* raw conversion */); this.tagBits &= ~TagBits.HasUnresolvedSuperclass; - if (this.superclass.problemId() == ProblemReasons.NotFound) + if (this.superclass.problemId() == ProblemReasons.NotFound) { this.tagBits |= TagBits.HierarchyHasProblems; // propagate type inconsistency + } else { + // make super-type resolving recursive for propagating typeBits downwards + boolean wasToleratingMissingTypeProcessingAnnotations = this.environment.mayTolerateMissingType; + this.environment.mayTolerateMissingType = true; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=360164 + try { + this.superclass.superclass(); + this.superclass.superInterfaces(); + } finally { + this.environment.mayTolerateMissingType = wasToleratingMissingTypeProcessingAnnotations; + } + } + this.typeBits |= this.superclass.typeBits; return this.superclass; } //{ObjectTeams: @@ -1589,8 +1614,20 @@ public ReferenceBinding[] superInterfaces() { for (int i = this.superInterfaces.length; --i >= 0;) { this.superInterfaces[i] = (ReferenceBinding) resolveType(this.superInterfaces[i], this.environment, true /* raw conversion */); - if (this.superInterfaces[i].problemId() == ProblemReasons.NotFound) + if (this.superInterfaces[i].problemId() == ProblemReasons.NotFound) { this.tagBits |= TagBits.HierarchyHasProblems; // propagate type inconsistency + } else { + // make super-type resolving recursive for propagating typeBits downwards + boolean wasToleratingMissingTypeProcessingAnnotations = this.environment.mayTolerateMissingType; + this.environment.mayTolerateMissingType = true; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=360164 + try { + this.superInterfaces[i].superclass(); + this.superInterfaces[i].superInterfaces(); + } finally { + this.environment.mayTolerateMissingType = wasToleratingMissingTypeProcessingAnnotations; + } + } + this.typeBits |= this.superInterfaces[i].typeBits; } this.tagBits &= ~TagBits.HasUnresolvedSuperinterfaces; return this.superInterfaces; 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 d5c5e9687..4a2041888 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 @@ -8,18 +8,24 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contributions for + * bug 349326 - [1.7] new warning for missing try-with-resources + * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; +import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.*; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.WrapperKind; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.codegen.CodeStream; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; import org.eclipse.objectteams.otdt.core.compiler.IOTConstants; @@ -31,7 +37,7 @@ import org.eclipse.objectteams.otdt.internal.core.compiler.util.TypeAnalyzer; /** * OTDT changes: * - * What: retreive all local types of this scope (identified by their ClassScope) + * What: retrieve all local types of this scope (identified by their ClassScope) * * What: Record referenced teams in getBinding(..) * @@ -1113,4 +1119,170 @@ public void resetEnclosingMethodStaticFlag() { } } } + +private List trackingVariables; // can be null if no resources are tracked +/** Used only during analyseCode and only for checking if a resource was closed in a finallyBlock. */ +public FlowInfo finallyInfo; +/** + * Register a tracking variable and compute its id. + */ +public int registerTrackingVariable(FakedTrackingVariable fakedTrackingVariable) { + if (this.trackingVariables == null) + this.trackingVariables = new ArrayList(3); + this.trackingVariables.add(fakedTrackingVariable); + MethodScope outerMethodScope = outerMostMethodScope(); + return outerMethodScope.analysisIndex + (outerMethodScope.trackVarCount++); + +} +/** When are no longer interested in this tracking variable - remove it. */ +public void removeTrackingVar(FakedTrackingVariable trackingVariable) { + if (this.trackingVariables != null) + if (this.trackingVariables.remove(trackingVariable)) + return; + if (this.parent instanceof BlockScope) + ((BlockScope)this.parent).removeTrackingVar(trackingVariable); +} +/** + * At the end of a block check the closing-status of all tracked closeables that are declared in this block. + * Also invoked when entering unreachable code. + */ +public void checkUnclosedCloseables(FlowInfo flowInfo, ASTNode location, BlockScope locationScope) { + if (this.trackingVariables == null) { + // at a method return we also consider enclosing scopes + if (location != null && this.parent instanceof BlockScope) + ((BlockScope) this.parent).checkUnclosedCloseables(flowInfo, location, locationScope); + return; + } + if (location != null && flowInfo.reachMode() != 0) return; + for (int i=0; i<this.trackingVariables.size(); i++) { + FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i); + if (location != null && trackingVar.originalBinding != null && flowInfo.isDefinitelyNull(trackingVar.originalBinding)) + continue; // reporting against a specific location, resource is null at this flow, don't complain + int status = getNullStatusAggressively(trackingVar.binding, flowInfo); + // try to improve info if a close() inside finally was observed: + if (locationScope != null) // only check at method exit points + status = locationScope.mergeCloseStatus(status, trackingVar.binding, this); + if (status == FlowInfo.NULL) { + // definitely unclosed: highest priority + reportResourceLeak(trackingVar, location, status); + continue; + } + if (location == null) // at end of block and not definitely unclosed + { + // problems at specific locations: medium priority + if (trackingVar.reportRecordedErrors(this)) // ... report previously recorded errors + continue; + } + if (status == FlowInfo.POTENTIALLY_NULL) { + // potentially unclosed: lower priority + reportResourceLeak(trackingVar, location, status); + } else if (status == FlowInfo.NON_NULL) { + // properly closed but not managed by t-w-r: lowest priority + if (environment().globalOptions.complianceLevel >= ClassFileConstants.JDK1_7) + trackingVar.reportExplicitClosing(problemReporter()); + } + } + if (location == null) { + // when leaving this block dispose off all tracking variables: + for (int i=0; i<this.localIndex; i++) + this.locals[i].closeTracker = null; + this.trackingVariables = null; + } +} + +private int mergeCloseStatus(int status, LocalVariableBinding binding, BlockScope outerScope) { + // get the most suitable null status representing whether resource 'binding' has been closed + // start at this scope and potentially travel out until 'outerScope' + // at each scope consult any recorded 'finallyInfo'. + if (status != FlowInfo.NON_NULL) { + if (this.finallyInfo != null) { + int finallyStatus = this.finallyInfo.nullStatus(binding); + if (finallyStatus == FlowInfo.NON_NULL) + return finallyStatus; + if (finallyStatus != FlowInfo.NULL) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL + status = FlowInfo.POTENTIALLY_NULL; + } + if (this != outerScope && this.parent instanceof BlockScope) + return ((BlockScope) this.parent).mergeCloseStatus(status, binding, outerScope); + } + return status; +} + +private void reportResourceLeak(FakedTrackingVariable trackingVar, ASTNode location, int nullStatus) { + if (location != null) + trackingVar.recordErrorLocation(location, nullStatus); + else + trackingVar.reportError(problemReporter(), null, nullStatus); +} + +/** + * If one branch of an if-else closes any AutoCloseable resource, and if the same + * resource is known to be null on the other branch mark it as closed, too, + * so that merging both branches indicates that the resource is always closed. + * Example: + * FileReader fr1 = null; + * try {\n" + + * fr1 = new FileReader(someFile);" + + * fr1.read(buf);\n" + + * } finally {\n" + + * if (fr1 != null)\n" + + * try {\n" + + * fr1.close();\n" + + * } catch (IOException e) { + * // do nothing + * } + * // after this if statement fr1 is definitely not leaked + * } + */ +public void correlateTrackingVarsIfElse(FlowInfo thenFlowInfo, FlowInfo elseFlowInfo) { + if (this.trackingVariables != null) { + for (int i=0; i<this.trackingVariables.size(); i++) { + FakedTrackingVariable trackingVar = (FakedTrackingVariable) this.trackingVariables.get(i); + if ( thenFlowInfo.isDefinitelyNonNull(trackingVar.binding) // closed in then branch + && elseFlowInfo.isDefinitelyNull(trackingVar.originalBinding)) // null in else branch + { + elseFlowInfo.markAsDefinitelyNonNull(trackingVar.binding); // -> always closed + } + else if ( elseFlowInfo.isDefinitelyNonNull(trackingVar.binding) // closed in else branch + && thenFlowInfo.isDefinitelyNull(trackingVar.originalBinding)) // null in then branch + { + thenFlowInfo.markAsDefinitelyNonNull(trackingVar.binding); // -> always closed + } + } + } + if (this.parent instanceof BlockScope) + ((BlockScope) this.parent).correlateTrackingVarsIfElse(thenFlowInfo, elseFlowInfo); +} + +/** + * Get the null status looking even into unreachable flows + * @param local + * @param flowInfo + * @return one of the constants FlowInfo.{NULL,POTENTIALLY_NULL,POTENTIALLY_NON_NULL,NON_NULL}. + */ +private int getNullStatusAggressively(LocalVariableBinding local, FlowInfo flowInfo) { + int reachMode = flowInfo.reachMode(); + int status = 0; + try { + // unreachable flowInfo is too shy in reporting null-issues, temporarily forget reachability: + if (reachMode != FlowInfo.REACHABLE) + flowInfo.tagBits &= ~FlowInfo.UNREACHABLE; + status = flowInfo.nullStatus(local); + } finally { + // reset + flowInfo.tagBits |= reachMode; + } + // at this point some combinations are not useful so flatten to a single bit: + if ((status & FlowInfo.NULL) != 0) { + if ((status & (FlowInfo.NON_NULL | FlowInfo.POTENTIALLY_NON_NULL)) != 0) + return FlowInfo.POTENTIALLY_NULL; // null + doubt = pot null + return FlowInfo.NULL; + } else if ((status & FlowInfo.NON_NULL) != 0) { + if ((status & FlowInfo.POTENTIALLY_NULL) != 0) + return FlowInfo.POTENTIALLY_NULL; // non-null + doubt = pot null + return FlowInfo.NON_NULL; + } else if ((status & FlowInfo.POTENTIALLY_NULL) != 0) + return FlowInfo.POTENTIALLY_NULL; + return status; +} } 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 1a401d8b3..58e6dc532 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 @@ -11,6 +11,7 @@ * Bug 328281 - visibility leaks not detected when analyzing unused field in private class * Bug 300576 - NPE Computing type hierarchy when compliance doesn't match libraries * Bug 354536 - compiling package-info.java still depends on the order of compilation units + * Bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -1568,6 +1569,7 @@ public class ClassScope extends Scope { } else { // only want to reach here when no errors are reported sourceType.superclass = superclass; + sourceType.typeBits |= superclass.typeBits; return true; } } @@ -2039,6 +2041,7 @@ public class ClassScope extends Scope { noProblems &= superInterfaceRef.resolvedType.isValidBinding(); } // only want to reach here when no errors are reported + sourceType.typeBits |= superInterface.typeBits; interfaceBindings[count++] = superInterface; } // hold onto all correctly resolved superinterfaces diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java index b7e7794ee..6e54bfb0c 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LocalVariableBinding.java @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 185682 - Increment/decrement operators mark local variables as read + * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for + * bug 185682 - Increment/decrement operators mark local variables as read + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -17,6 +19,7 @@ import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.FakedTrackingVariable; import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; import org.eclipse.jdt.internal.compiler.impl.Constant; @@ -47,6 +50,8 @@ public class LocalVariableBinding extends VariableBinding { public int[] initializationPCs; public int initializationCount = 0; + public FakedTrackingVariable closeTracker; // track closing of instances of type AutoCloseable, maybe null + // for synthetic local variables // if declaration slot is not positionned, the variable will not be listed in attribute // note that the name of a variable should be chosen so as not to conflict with user ones (usually starting with a space char is all needed) diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java index dfe33bc69..3550f2815 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java @@ -127,6 +127,7 @@ public class LookupEnvironment implements ProblemReasons, TypeConstants { private ArrayList missingTypes; Set typesBeingConnected; public boolean isProcessingAnnotations = false; + public boolean mayTolerateMissingType = false; final static int BUILD_FIELDS_AND_METHODS = 4; final static int BUILD_TYPE_HIERARCHY = 1; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java index becddb09f..b37dcf7ad 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodScope.java @@ -8,6 +8,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -76,6 +77,9 @@ public class MethodScope extends BlockScope { // inner-emulation public SyntheticArgumentBinding[] extraSyntheticArguments; + // count number of tracking variables, see FakedTrackingVariable + int trackVarCount = 0; + public MethodScope(ClassScope parent, ReferenceContext context, boolean isStatic) { super(METHOD_SCOPE, parent); this.locals = new LocalVariableBinding[5]; 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 79979dfea..82dbcf6eb 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 @@ -8,6 +8,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -672,6 +673,13 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi return this.type.hasMemberTypes(); } + public boolean hasTypeBit(int bit) { + TypeBinding erasure = erasure(); + if (erasure instanceof ReferenceBinding) + return ((ReferenceBinding) erasure).hasTypeBit(bit); + return false; + } + /** * @see org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding#implementsMethod(MethodBinding) */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java index f97d9451d..1211cc1b8 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ProblemReferenceBinding.java @@ -8,6 +8,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -65,6 +66,12 @@ public ReferenceBinding closestReferenceMatch() { return this.closestMatch; } +public boolean hasTypeBit(int bit) { + if (this.closestMatch != null) + return this.closestMatch.hasTypeBit(bit); + return false; +} + /* API * Answer the problem id associated with the receiver. * NoError if the receiver is a valid binding. 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 a427a235c..b64379739 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -90,7 +91,11 @@ abstract public class ReferenceBinding extends AbstractOTReferenceBinding { private SimpleLookupTable compatibleCache; - public static final ReferenceBinding LUB_GENERIC = new ReferenceBinding() { /* used for lub computation */}; + int typeBits; // additional bits characterizing this type + + public static final ReferenceBinding LUB_GENERIC = new ReferenceBinding() { /* used for lub computation */ + public boolean hasTypeBit(int bit) { return false; } + }; private static final Comparator FIELD_COMPARATOR = new Comparator() { public int compare(Object o1, Object o2) { @@ -570,6 +575,10 @@ public void computeId() { case 'i' : if (CharOperation.equals(packageName, TypeConstants.IO)) { switch (typeName[0]) { + case 'C' : + if (CharOperation.equals(typeName, TypeConstants.JAVA_IO_CLOSEABLE[2])) + this.typeBits |= TypeIds.BitCloseable; // don't assign id, only typeBit (for analysis of resource leaks) + return; case 'E' : if (CharOperation.equals(typeName, TypeConstants.JAVA_IO_EXTERNALIZABLE[2])) this.id = TypeIds.T_JavaIoExternalizable; @@ -616,8 +625,10 @@ public void computeId() { case 'A' : switch(typeName.length) { case 13 : - if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_AUTOCLOSEABLE[2])) + if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_AUTOCLOSEABLE[2])) { this.id = TypeIds.T_JavaLangAutoCloseable; + this.typeBits |= TypeIds.BitAutoCloseable; + } return; case 14: if (CharOperation.equals(typeName, TypeConstants.JAVA_LANG_ASSERTIONERROR[2])) @@ -1026,6 +1037,8 @@ public FieldBinding getField(char[] fieldName, boolean needResolve) { public char[] getFileName() { return this.fileName; } +/** Answer an additional bit characterizing this type, like {@link TypeIds#BitAutoCloseable}. */ +abstract public boolean hasTypeBit(int bit); public ReferenceBinding getMemberType(char[] typeName) { ReferenceBinding[] memberTypes = memberTypes(); 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 424f75176..e7b4226e4 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 @@ -2719,6 +2719,40 @@ public abstract class Scope { return new ProblemReferenceBinding(compoundName, null /* no closest match since search for pkg*/, ProblemReasons.NotFound); } + /* Answer the package from the compoundName or null if it begins with a type. + * Intended to be used while resolving a package name only. + * + * Internal use only + */ + public final Binding getOnlyPackage(char[][] compoundName) { + compilationUnitScope().recordQualifiedReference(compoundName); + Binding binding = getTypeOrPackage(compoundName[0], Binding.PACKAGE, true); + if (binding == null || !binding.isValidBinding()) { + char[][] qName = new char[][] { compoundName[0] }; + return new ProblemReferenceBinding(qName, null /* no closest match since search for pkg*/, ProblemReasons.NotFound); + } + if (!(binding instanceof PackageBinding)) { + return null; // compoundName does not start with a package + } + + int currentIndex = 1, length = compoundName.length; + PackageBinding packageBinding = (PackageBinding) binding; + while (currentIndex < length) { + binding = packageBinding.getPackage(compoundName[currentIndex++]); + if (binding == null) { + return new ProblemReferenceBinding(CharOperation.subarray(compoundName, 0, currentIndex), null /* no closest match since search for pkg*/, ProblemReasons.NotFound); + } + if (!binding.isValidBinding()) { + return new ProblemReferenceBinding( + CharOperation.subarray(compoundName, 0, currentIndex), + binding instanceof ReferenceBinding ? (ReferenceBinding)((ReferenceBinding)binding).closestMatch() : null, + binding.problemId()); + } + packageBinding = (PackageBinding) binding; + } + return packageBinding; + } + /* Answer the type binding that corresponds the given name, starting the lookup in the receiver. * The name provided is a simple source name (e.g., "Object" , "Point", ...) */ @@ -3064,7 +3098,53 @@ public abstract class Scope { } } } - + // walk single static imports. A type found here will shadow types with same name in other CU's, or types coming + // from on-demand imports. JLS 7.5.3 + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318401 + if (imports != null) { + ReferenceBinding type = null; + nextImport : for (int i = 0, length = imports.length; i < length; i++) { + ImportBinding importBinding = imports[i]; + if (importBinding.isStatic()) { + ReferenceBinding temp = null; + if (CharOperation.equals(importBinding.compoundName[importBinding.compoundName.length - 1], name)) { + Binding resolvedImport = importBinding.resolvedImport; + if (resolvedImport == null) continue nextImport; + if (resolvedImport instanceof MethodBinding || resolvedImport instanceof FieldBinding) { + // check to see if there are also member types with the same name + // must find the importRef's type again since the method/field can be from an inherited type + // see StaticImportTest#test084 for more clarity + char[][] importName = importBinding.reference.tokens; + TypeBinding referencedType = getType(importName, importName.length - 1); + if (referencedType != null && referencedType instanceof ReferenceBinding) { + temp = findMemberType(name, (ReferenceBinding) referencedType); + } + } + if (temp != null && temp.isStatic() && temp != type) { + if (temp.isValidBinding()) { + if (!temp.canBeSeenBy(unitScope.fPackage)) { + // Answer error binding - type is not visible + foundType = new ProblemReferenceBinding(new char[][]{name}, type, ProblemReasons.NotVisible); + } else { + ImportReference importReference = importBinding.reference; + if (importReference != null) { + importReference.bits |= ASTNode.Used; + } + type = temp; + } + } else if (foundType == null) { + foundType = temp; + } + } + } + } + } + if (type != null) { + if (typeOrPackageCache != null) + typeOrPackageCache.put(name, type); + return type; + } + } // check if the name is in the current package, skip it if its a sub-package PackageBinding currentPackage = unitScope.fPackage; unitScope.recordReference(currentPackage.compoundName, name); @@ -3409,7 +3489,7 @@ public abstract class Scope { // test that the enclosingType is not part of the compilation unit SourceTypeBinding[] topLevelTypes = ((CompilationUnitScope) unitScope).topLevelTypes; for (int i = topLevelTypes.length; --i >= 0;) - if (topLevelTypes[i] == enclosingType) + if (topLevelTypes[i] == enclosingType.original()) return true; return false; } 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 e6b95e8df..f482f099a 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 @@ -7,7 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 328281 - visibility leaks not detected when analyzing unused field in private class + * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for + * bug 328281 - visibility leaks not detected when analyzing unused field in private class + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -1621,6 +1623,11 @@ public SyntheticMethodBinding getSyntheticBridgeMethod(MethodBinding inheritedMe return accessors[1]; } +public boolean hasTypeBit(int bit) { + // source types initialize type bits during connectSuperclass/interfaces() + return (this.typeBits & bit) != 0; +} + /** * @see org.eclipse.jdt.internal.compiler.lookup.Binding#initializeDeprecatedAnnotationTagBits() */ @@ -1815,8 +1822,16 @@ public MethodBinding[] methods() { int index = pLength; // is erasure of signature of m2 same as signature of m1? for (; --index >= 0;) { - if (params1[index] != params2[index].erasure()) - break; + if (params1[index] != params2[index].erasure()) { + // If one of them is a raw type + if (params1[index] instanceof RawTypeBinding) { + if (params2[index].erasure() != ((RawTypeBinding)params1[index]).actualType()) { + break; + } + } else { + break; + } + } if (params1[index] == params2[index]) { TypeBinding type = params1[index].leafComponentType(); if (type instanceof SourceTypeBinding && type.typeVariables() != Binding.NO_TYPE_VARIABLES) { @@ -1828,8 +1843,16 @@ public MethodBinding[] methods() { if (index >= 0 && index < pLength) { // is erasure of signature of m1 same as signature of m2? for (index = pLength; --index >= 0;) - if (params1[index].erasure() != params2[index]) - break; + if (params1[index].erasure() != params2[index]) { + // If one of them is a raw type + if (params2[index] instanceof RawTypeBinding) { + if (params1[index].erasure() != ((RawTypeBinding)params2[index]).actualType()) { + break; + } + } else { + break; + } + } } if (index >= 0) { 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 9a62cc02d..0bbef47eb 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -123,6 +124,7 @@ public interface TypeConstants { char[][] JAVA_LANG_ANNOTATION_ELEMENTTYPE = {JAVA, LANG, ANNOTATION, "ElementType".toCharArray()}; //$NON-NLS-1$ char[][] JAVA_LANG_REFLECT_FIELD = new char[][] {JAVA, LANG, REFLECT, "Field".toCharArray()}; //$NON-NLS-1$ char[][] JAVA_LANG_REFLECT_METHOD = new char[][] {JAVA, LANG, REFLECT, "Method".toCharArray()}; //$NON-NLS-1$ + char[][] JAVA_IO_CLOSEABLE = new char[][] { JAVA, IO, "Closeable".toCharArray()};//$NON-NLS-1$ char[][] JAVA_IO_OBJECTSTREAMEXCEPTION = new char[][] { JAVA, IO, "ObjectStreamException".toCharArray()};//$NON-NLS-1$ char[][] JAVA_IO_EXTERNALIZABLE = {JAVA, IO, "Externalizable".toCharArray()}; //$NON-NLS-1$ char[][] JAVA_IO_IOEXCEPTION = new char[][] { JAVA, IO, "IOException".toCharArray()};//$NON-NLS-1$ @@ -151,6 +153,7 @@ public interface TypeConstants { "MethodHandle$PolymorphicSignature".toCharArray() //$NON-NLS-1$ }; char[][] JAVA_LANG_AUTOCLOSEABLE = {JAVA, LANG, "AutoCloseable".toCharArray()}; //$NON-NLS-1$ + char[] CLOSE = "close".toCharArray(); //$NON-NLS-1$ // Constraints for generic type argument inference int CONSTRAINT_EQUAL = 0; // 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 8e3a647d5..115bf8339 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 @@ -7,6 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contributions for + * bug 349326 - [1.7] new warning for missing try-with-resources + * bug 359362 - FUP of bug 349326: Resource leak on non-Closeable resource *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -182,4 +185,20 @@ public interface TypeIds { final int Object2boolean = T_JavaLangObject + (T_boolean << 4); final int BOXING = 0x200; final int UNBOXING = 0x400; + + /** + * Marks a type whose type bits have not yet been initialized. + * @see ReferenceBinding#hasTypeBit(int) + */ + final int BitUninitialized = 0x8000000; + /** + * Marks all sub-types of java.lang.AutoCloseable. + * @see ReferenceBinding#hasTypeBit(int) + */ + final int BitAutoCloseable = 1; + /** + * Marks all sub-types of java.io.Closeable. + * @see ReferenceBinding#hasTypeBit(int) + */ + final int BitCloseable = 2; } 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 31433515b..29dc53f0b 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -7,7 +7,10 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 282152 - [1.5][compiler] Generics code rejected by Eclipse but accepted by javac + * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for + * bug 282152 - [1.5][compiler] Generics code rejected by Eclipse but accepted by javac + * bug 349326 - [1.7] new warning for missing try-with-resources + * bug 359362 - FUP of bug 349326: Resource leak on non-Closeable resource * Technical University Berlin - extended API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -53,6 +56,7 @@ public class TypeVariableBinding extends ReferenceBinding { this.modifiers = ClassFileConstants.AccPublic | ExtraCompilerModifiers.AccGenericSignature; // treat type var as public this.tagBits |= TagBits.HasTypeVariable; this.environment = environment; + this.typeBits = TypeIds.BitUninitialized; } /** @@ -389,6 +393,20 @@ public class TypeVariableBinding extends ReferenceBinding { return true; } + public boolean hasTypeBit(int bit) { + if (this.typeBits == TypeIds.BitUninitialized) { + // initialize from bounds + this.typeBits = 0; + if (this.superclass != null && this.superclass.hasTypeBit(~TypeIds.BitUninitialized)) + this.typeBits |= this.superclass.typeBits; + if (this.superInterfaces != null) + for (int i = 0, l = this.superInterfaces.length; i < l; i++) + if (this.superInterfaces[i].hasTypeBit(~TypeIds.BitUninitialized)) + this.typeBits |= this.superInterfaces[i].typeBits; + } + return (this.typeBits & bit) != 0; + } + /** * Returns true if the type variable is directly bound to a given type */ diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java index f29aa59ab..1683193f1 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/UnresolvedReferenceBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -8,6 +8,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -47,6 +48,10 @@ void addWrapper(TypeBinding wrapper, LookupEnvironment environment) { public String debugName() { return toString(); } +public boolean hasTypeBit(int bit) { + // shouldn't happen since we are not called before analyseCode(), but play safe: + return false; +} //{ObjectTeams: changed to public (was default-vis) public ReferenceBinding resolve(LookupEnvironment environment, boolean convertGenericToRawType) { // SH} @@ -58,7 +63,7 @@ public ReferenceBinding resolve(LookupEnvironment environment, boolean convertGe } if (targetType == null || targetType == this) { // could not resolve any better, error was already reported against it // report the missing class file first - only if not resolving a previously missing type - if ((this.tagBits & TagBits.HasMissingType) == 0) { + if ((this.tagBits & TagBits.HasMissingType) == 0 && !environment.mayTolerateMissingType) { environment.problemReporter.isClassPathCorrect( this.compoundName, environment.unitBeingCompleted, diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java index a95cd85e0..a0fec342d 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2009 IBM Corporation and others. + * Copyright (c) 2005, 2011 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 @@ -7,6 +7,9 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Stephan Herrmann - Contribution for + * bug 349326 - [1.7] new warning for missing try-with-resources + * bug 359362 - FUP of bug 349326: Resource leak on non-Closeable resource * Technical University Berlin - extended API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.compiler.lookup; @@ -58,6 +61,7 @@ public class WildcardBinding extends ReferenceBinding { if (bound instanceof UnresolvedReferenceBinding) ((UnresolvedReferenceBinding) bound).addWrapper(this, environment); this.tagBits |= TagBits.HasUnresolvedTypeVariables; // cleared in resolve() + this.typeBits = TypeIds.BitUninitialized; } //{ObjectTeams: role wrapping? @@ -434,6 +438,20 @@ public class WildcardBinding extends ReferenceBinding { return this.genericType.hashCode(); } + public boolean hasTypeBit(int bit) { + if (this.typeBits == TypeIds.BitUninitialized) { + // initialize from upper bounds + this.typeBits = 0; + if (this.superclass != null && this.superclass.hasTypeBit(~TypeIds.BitUninitialized)) + this.typeBits |= this.superclass.typeBits; + if (this.superInterfaces != null) + for (int i = 0, l = this.superInterfaces.length; i < l; i++) + if (this.superInterfaces[i].hasTypeBit(~TypeIds.BitUninitialized)) + this.typeBits |= this.superInterfaces[i].typeBits; + } + return (this.typeBits & bit) != 0; + } + void initialize(ReferenceBinding someGenericType, TypeBinding someBound, TypeBinding[] someOtherBounds) { this.genericType = someGenericType; this.bound = someBound; 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 206854e7d..618e416f3 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 @@ -10,8 +10,9 @@ * IBM Corporation - initial API and implementation * Benjamin Muskalla - Contribution for bug 239066 * Stephan Herrmann - Contributions for - * bug 236385 - [compiler] Warn for potential programming problem if an object is created but not used + * bug 236385 - * bug 338303 - Warning about Redundant assignment conflicts with definite assignment + * bug 349326 - [1.7] new warning for missing try-with-resources * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -59,6 +60,7 @@ import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FakedTrackingVariable; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.ImportReference; @@ -487,7 +489,16 @@ public static int getIrritant(int problemID) { case IProblem.MethodCanBePotentiallyStatic: return CompilerOptions.MethodCanBePotentiallyStatic; - + + case IProblem.UnclosedCloseable: + case IProblem.UnclosedCloseableAtExit: + return CompilerOptions.UnclosedCloseable; + case IProblem.PotentiallyUnclosedCloseable: + case IProblem.PotentiallyUnclosedCloseableAtExit: + return CompilerOptions.PotentiallyUnclosedCloseable; + case IProblem.ExplicitlyClosedAutoCloseable: + return CompilerOptions.ExplicitlyClosedAutoCloseable; + case IProblem.RedundantSpecificationOfTypeArguments: return CompilerOptions.RedundantSpecificationOfTypeArguments; //{ObjectTeams: @@ -620,6 +631,7 @@ public static int getProblemCategory(int severity, int problemID) { case CompilerOptions.ParameterAssignment : case CompilerOptions.MethodCanBeStatic : case CompilerOptions.MethodCanBePotentiallyStatic : + case CompilerOptions.ExplicitlyClosedAutoCloseable : return CategorizedProblem.CAT_CODE_STYLE; case CompilerOptions.MaskedCatchBlock : @@ -641,6 +653,8 @@ public static int getProblemCategory(int severity, int problemID) { case CompilerOptions.ShouldImplementHashcode : case CompilerOptions.DeadCode : case CompilerOptions.UnusedObjectAllocation : + case CompilerOptions.UnclosedCloseable : + case CompilerOptions.PotentiallyUnclosedCloseable : return CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM; case CompilerOptions.OverriddenPackageDefaultMethod : @@ -3153,12 +3167,21 @@ public void incorrectSwitchType(Expression expression, TypeBinding testType) { expression.sourceStart, expression.sourceEnd); } else { - this.handle( - IProblem.IncorrectSwitchType, - new String[] {new String(testType.readableName())}, - new String[] {new String(testType.shortReadableName())}, - expression.sourceStart, - expression.sourceEnd); + if (this.options.sourceLevel < ClassFileConstants.JDK1_5 && testType.isEnum()) { + this.handle( + IProblem.SwitchOnEnumNotBelow15, + new String[] {new String(testType.readableName())}, + new String[] {new String(testType.shortReadableName())}, + expression.sourceStart, + expression.sourceEnd); + } else { + this.handle( + IProblem.IncorrectSwitchType, + new String[] {new String(testType.readableName())}, + new String[] {new String(testType.shortReadableName())}, + expression.sourceStart, + expression.sourceEnd); + } } } else { this.handle( @@ -8087,6 +8110,51 @@ public void unsafeRawInvocation(ASTNode location, MethodBinding rawMethod) { location.sourceEnd); } } +public void potentiallyUnclosedCloseable(FakedTrackingVariable trackVar, ASTNode location) { + String[] args = { String.valueOf(trackVar.name) }; + if (location == null) { + this.handle( + IProblem.PotentiallyUnclosedCloseable, + args, + args, + trackVar.sourceStart, + trackVar.sourceEnd); + } else { + this.handle( + IProblem.PotentiallyUnclosedCloseableAtExit, + args, + args, + location.sourceStart, + location.sourceEnd); + } +} +public void unclosedCloseable(FakedTrackingVariable trackVar, ASTNode location) { + String[] args = { String.valueOf(trackVar.name) }; + if (location == null) { + this.handle( + IProblem.UnclosedCloseable, + args, + args, + trackVar.sourceStart, + trackVar.sourceEnd); + } else { + this.handle( + IProblem.UnclosedCloseableAtExit, + args, + args, + location.sourceStart, + location.sourceEnd); + } +} +public void explicitlyClosedAutoCloseable(FakedTrackingVariable trackVar) { + String[] args = { String.valueOf(trackVar.name) }; + this.handle( + IProblem.ExplicitlyClosedAutoCloseable, + args, + args, + trackVar.sourceStart, + trackVar.sourceEnd); +} public void unsafeReturnTypeOverride(MethodBinding currentMethod, MethodBinding inheritedMethod, SourceTypeBinding type) { if (this.options.sourceLevel < ClassFileConstants.JDK1_5) { return; 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 787214954..1ae059427 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 @@ -8,7 +8,9 @@ # Contributors: # IBM Corporation - initial API and implementation # Benjamin Muskalla - Contribution for bug 239066 -# Stephan Herrmann <stephan@cs.tu-berlin.de> - Contribution for bug 185682 - Increment/decrement operators mark local variables as read +# Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for +# bug 185682 - Increment/decrement operators mark local variables as read +# bug 349326 - [1.7] new warning for missing try-with-resources # Fraunhofer FIRST - extended API and implementation # Technical University Berlin - extended API and implementation ############################################################################### @@ -145,7 +147,7 @@ 162 = Cannot return from within an initializer 163 = Initializer does not complete normally 164 = Expression must return a value -165 = Unreachable catch block for {0}. Only more specific exceptions are thrown and handled by previous catch block(s). +165 = Unreachable catch block for {0}. Only more specific exceptions are thrown and they are handled by previous catch block(s). 166 = The default case is already defined 167 = Unreachable catch block for {0}. This exception is never thrown from the try statement body 168 = Unhandled exception type {0} @@ -289,7 +291,7 @@ 343 = Illegal modifier for the interface field {0}.{1}; only public, static & final are permitted 344 = The field {0} can only set one of public / protected / private 345 = The field {0} can be either final or volatile, not both -346 = The field {0} cannot be declared static; static fields can only be declared in static or top level types +346 = The field {0} cannot be declared static in a non-static inner type, unless initialized with a constant expression ###[obsolete] 350 = {2} cannot be resolved (or is not a valid type) for the field {1}.{0} ###[obsolete] 351 = The type {2} is not visible for the field {1}.{0} @@ -646,6 +648,12 @@ 882 = Unhandled exception type {0} thrown by automatic close() invocation on {1} 883 = '<>' operator is not allowed for source level below 1.7 884 = Redundant specification of type arguments <{0}> +885 = Potential resource leak: ''{0}'' may not be closed +886 = Potential resource leak: ''{0}'' may not be closed at this location +887 = Resource leak: ''{0}'' is never closed +888 = Resource leak: ''{0}'' is not closed at this location +889 = Resource ''{0}'' should be managed by try-with-resource +890 = Cannot switch on an enum value for source level below 1.5. Only convertible int values are permitted ### ELABORATIONS ## Access restrictions diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/RoleMigrationImplementor.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/RoleMigrationImplementor.java index bfddb7c4c..6f87fe689 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/RoleMigrationImplementor.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/RoleMigrationImplementor.java @@ -21,13 +21,33 @@ import static org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.AccS import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ClassFile; -import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeParameter; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; import org.eclipse.jdt.internal.compiler.codegen.CodeStream; import org.eclipse.jdt.internal.compiler.codegen.Opcodes; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext; -import org.eclipse.jdt.internal.compiler.lookup.*; +import org.eclipse.jdt.internal.compiler.lookup.ClassScope; +import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; +import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; +import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; +import org.eclipse.jdt.internal.compiler.lookup.Scope; +import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; +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.objectteams.otdt.core.compiler.IOTConstants; import org.eclipse.objectteams.otdt.core.exceptions.InternalCompilerError; import org.eclipse.objectteams.otdt.internal.core.compiler.lifting.LiftingEnvironment; @@ -252,7 +272,7 @@ public class RoleMigrationImplementor return null; } @Override - public void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo flowInfo) { + public void analyseCode(ClassScope classScope, FlowContext flowContext, FlowInfo flowInfo) { // noop } }; diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/TeamMethodGenerator.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/TeamMethodGenerator.java index c9aea1c25..956cfc63e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/TeamMethodGenerator.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/statemachine/transformer/TeamMethodGenerator.java @@ -38,8 +38,8 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.MethodInfo; import org.eclipse.jdt.internal.compiler.env.IBinaryMethod; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.InitializationFlowContext; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; @@ -399,7 +399,7 @@ public class TeamMethodGenerator { // nop } @Override - public void analyseCode(ClassScope classScope, InitializationFlowContext initializationContext, FlowInfo flowInfo) { + public void analyseCode(ClassScope classScope, FlowContext flowContext, FlowInfo flowInfo) { // nop } @Override diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java index baf8fc990..fe408d060 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnit.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -867,7 +867,7 @@ public class CompilationUnit extends ASTNode { /** * Enables the recording of changes to this compilation - * unit and its descendents. The compilation unit must have + * unit and its descendants. The compilation unit must have * been created by <code>ASTParser</code> and still be in * its original state. Once recording is on, * arbitrary changes to the subtree rooted at this compilation diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java index 9d64111df..08fa9a798 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java @@ -1578,7 +1578,7 @@ class DefaultBindingResolver extends BindingResolver { org.eclipse.jdt.internal.compiler.ast.ASTNode node = (org.eclipse.jdt.internal.compiler.ast.ASTNode) this.newAstToOldAst.get(pkg); if (node instanceof ImportReference) { ImportReference importReference = (ImportReference) node; - Binding binding = this.scope.getTypeOrPackage(CharOperation.subarray(importReference.tokens, 0, importReference.tokens.length)); + Binding binding = this.scope.getOnlyPackage(CharOperation.subarray(importReference.tokens, 0, importReference.tokens.length)); if ((binding != null) && (binding.isValidBinding())) { if (binding instanceof ReferenceBinding) { // this only happens if a type name has the same name as its package diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java index aa2ea6603..c70d15293 100644 --- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java +++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java @@ -890,10 +890,10 @@ public final class ASTRewriteAnalyzer extends ASTVisitor { insertedPrefix = getLineDelimiter() + this.formatter.createIndentString(indent) + insertedPrefix.trim() + ' '; } doTextInsert(offset, insertedPrefix, editGroup); - String lineInPrefix= getCurrentLine(prefix, prefix.length()); - if (prefix.length() != lineInPrefix.length()) { + int lineStart= getCurrentLineStart(prefix, prefix.length()); + if (lineStart != 0) { // prefix contains a new line: update the indent to the one used in the prefix - indent= this.formatter.computeIndentUnits(lineInPrefix); + indent= this.formatter.computeIndentUnits(prefix.substring(lineStart)); } doTextInsert(offset, replacingNode, indent, true, editGroup); doTextInsert(offset, strings[1], editGroup); @@ -1325,7 +1325,12 @@ public final class ASTRewriteAnalyzer extends ASTVisitor { } currPos= offset; } else { - String destIndentString= this.formatter.getIndentString(getCurrentLine(formatted, offset)); + // If in the first line, there are cases (eg: catch clause) where the line will not be prefixed with + // proper indentation - see https://bugs.eclipse.org/bugs/show_bug.cgi?id=350285 + int lineOffset = getCurrentLineStart(formatted, offset); + String destIndentString = (lineOffset == 0) + ? this.formatter.createIndentString(initialIndentLevel) + : this.formatter.getIndentString(formatted.substring(lineOffset, offset)); if (data instanceof CopyPlaceholderData) { // replace with a copy/move target CopySourceInfo copySource= ((CopyPlaceholderData) data).copySource; int srcIndentLevel= getIndent(copySource.getNode().getStartPosition()); @@ -1358,17 +1363,16 @@ public final class ASTRewriteAnalyzer extends ASTVisitor { return offset < formatted.length() && !IndentManipulation.isLineDelimiterChar(formatted.charAt(offset)); } - private String getCurrentLine(String str, int pos) { + private int getCurrentLineStart(String str, int pos) { for (int i= pos - 1; i>= 0; i--) { char ch= str.charAt(i); if (IndentManipulation.isLineDelimiterChar(ch)) { - return str.substring(i + 1, pos); + return i+1; } } - return str.substring(0, pos); + return 0; } - - + private void rewriteModifiers(ASTNode parent, StructuralPropertyDescriptor property, int offset) { RewriteEvent event= getEvent(parent, property); if (event == null || event.getChangeKind() != RewriteEvent.REPLACED) { diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java index d823ab6b6..d834f8271 100644 --- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java +++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/internal/formatter/CodeFormatterVisitor.java @@ -112,7 +112,6 @@ import org.eclipse.jdt.internal.compiler.ast.WhileStatement; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; @@ -3845,8 +3844,7 @@ public class CodeFormatterVisitor extends ASTVisitor { if (numberOfParens > 0) { manageOpeningParenthesizedExpression(doubleLiteral, numberOfParens); } - Constant constant = doubleLiteral.constant; - if (constant != null && constant.doubleValue() < 0) { + if (isNextToken(TerminalTokens.TokenNameMINUS)) { this.scribe.printNextToken(TerminalTokens.TokenNameMINUS); } this.scribe.printNextToken(TerminalTokens.TokenNameDoubleLiteral); @@ -4070,8 +4068,7 @@ public class CodeFormatterVisitor extends ASTVisitor { if (numberOfParens > 0) { manageOpeningParenthesizedExpression(floatLiteral, numberOfParens); } - Constant constant = floatLiteral.constant; - if (constant != null && floatLiteral.constant.floatValue() < 0) { + if (isNextToken(TerminalTokens.TokenNameMINUS)) { this.scribe.printNextToken(TerminalTokens.TokenNameMINUS); } this.scribe.printNextToken(TerminalTokens.TokenNameFloatingPointLiteral); @@ -4384,8 +4381,7 @@ public class CodeFormatterVisitor extends ASTVisitor { if (numberOfParens > 0) { manageOpeningParenthesizedExpression(intLiteral, numberOfParens); } - Constant constant = intLiteral.constant; - if (constant != null && constant.intValue() < 0) { + if (isNextToken(TerminalTokens.TokenNameMINUS)) { this.scribe.printNextToken(TerminalTokens.TokenNameMINUS); } this.scribe.printNextToken(TerminalTokens.TokenNameIntegerLiteral); @@ -4435,8 +4431,7 @@ public class CodeFormatterVisitor extends ASTVisitor { if (numberOfParens > 0) { manageOpeningParenthesizedExpression(longLiteral, numberOfParens); } - Constant constant = longLiteral.constant; - if (constant != null && constant.longValue() < 0) { + if (isNextToken(TerminalTokens.TokenNameMINUS)) { this.scribe.printNextToken(TerminalTokens.TokenNameMINUS); } this.scribe.printNextToken(TerminalTokens.TokenNameLongLiteral); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java index dbc6e55c7..8d485abb8 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelMarker.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -114,4 +114,13 @@ public interface IJavaModelMarker { * @since 2.0 */ String CLASSPATH_FILE_FORMAT = "classpathFileFormat"; //$NON-NLS-1$ + + /** + * Output overlapping another source attribute (value <code>"outputOverlappingSource"</code>). + * Used only on buildpath problem markers. The value of this attribute is + * either "true" or "false". + * + * @since 3.6.4 + */ + String OUTPUT_OVERLAPPING_SOURCE = "outputOverlappingSource"; //$NON-NLS-1$ } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java index 4cc2f456b..a88db5e10 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java @@ -345,4 +345,11 @@ public interface IJavaModelStatusConstants { * @since 3.7 */ public static final int CANNOT_RETRIEVE_ATTACHED_JAVADOC_TIMEOUT = 1012; + + /** + * <p>Status constant indicating that the default or specific output folder is overlapping + * with another source location. </p> + * @since 3.6.4 + */ + public static final int OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE = 1013; } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java index a051e9122..4575100cf 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaConventions.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -618,11 +618,13 @@ public final class JavaConventions { * <li> The project output location path cannot be null, must be absolute and located inside the project. * <li> Specific output locations (specified on source entries) can be null, if not they must be located inside the project, * <li> A project entry cannot refer to itself directly (that is, a project cannot prerequisite itself). - * <li> Classpath entries or output locations cannot coincidate or be nested in each other, except for the following scenarii listed below: - * <ul><li> A source folder can coincidate with its own output location, in which case this output can then contain library archives. - * However, a specific output location cannot coincidate with any library or a distinct source folder than the one referring to it. </li> + * <li> Classpath entries or output locations cannot coincide or be nested in each other, except for the following scenarios listed below: + * <ul><li> A source folder can coincide with its own output location, in which case this output can then contain library archives. + * However, a specific output location cannot coincide with any library or a distinct source folder than the one referring to it.<br> + * Note: Since 3.8, this behavior can be overridden by configuring {@link JavaCore#CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE} + * </li> * <li> A source/library folder can be nested in any source folder as long as the nested folder is excluded from the enclosing one. </li> - * <li> An output location can be nested in a source folder, if the source folder coincidates with the project itself, or if the output + * <li> An output location can be nested in a source folder, if the source folder coincides with the project itself, or if the output * location is excluded from the source folder. * </ul> * </ul> diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java index fb5424b53..48d526532 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java @@ -84,6 +84,10 @@ * Benjamin Muskalla - added COMPILER_PB_MISSING_SYNCHRONIZED_ON_INHERITED_METHOD * Stephan Herrmann - added COMPILER_PB_UNUSED_OBJECT_ALLOCATION * Stephan Herrmann - added COMPILER_PB_SUPPRESS_OPTIONAL_ERRORS + * Stephan Herrmann - added the following constants: + * COMPILER_PB_UNCLOSED_CLOSEABLE, + * COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE + * COMPILER_PB_EXPLICITLY_CLOSED_AUTOCLOSEABLE * * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation @@ -1375,6 +1379,52 @@ public final class JavaCore extends Plugin { */ public static final String COMPILER_PB_POTENTIALLY_MISSING_STATIC_ON_METHOD = PLUGIN_ID + ".compiler.problem.reportMethodCanBePotentiallyStatic"; //$NON-NLS-1$ /** + * Compiler option ID: Reporting a resource that is not closed properly. + * <p>When enabled, the compiler will issue an error or a warning if + * a local variable holds a value of type <code>java.lang.AutoCloseable</code> (compliance>=1.7) + * or a value of type <code>java.io.Closeable</code> (compliance<=1.6) and if + * flow analysis shows that the method <code>close()</code> is not invoked locally on that value. + * <dl> + * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.reportUnclosedCloseable"</code></dd> + * <dt>Possible values:</dt><dd><code>{ "error", "warning", "ignore" }</code></dd> + * <dt>Default:</dt><dd><code>"warning"</code></dd> + * </dl> + * @since 3.8 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_UNCLOSED_CLOSEABLE = PLUGIN_ID + ".compiler.problem.unclosedCloseable"; //$NON-NLS-1$ + /** + * Compiler option ID: Reporting a resource that may not be closed properly. + * <p>When enabled, the compiler will issue an error or a warning if + * a local variable holds a value of type <code>java.lang.AutoCloseable</code> (compliance>=1.7) + * or a value of type <code>java.io.Closeable</code> (compliance<=1.6) and if + * flow analysis shows that the method <code>close()</code> is + * not invoked locally on that value for all execution paths. + * <dl> + * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.reportPotentiallyUnclosedCloseable"</code></dd> + * <dt>Possible values:</dt><dd><code>{ "error", "warning", "ignore" }</code></dd> + * <dt>Default:</dt><dd><code>"ignore"</code></dd> + * </dl> + * @since 3.8 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_POTENTIALLY_UNCLOSED_CLOSEABLE = PLUGIN_ID + ".compiler.problem.potentiallyUnclosedCloseable"; //$NON-NLS-1$ + /** + * Compiler option ID: Reporting a resource that is not managed by try-with-resources. + * <p>When enabled, the compiler will issue an error or a warning if a local variable + * holds a value of type <code>java.lang.AutoCloseable</code>, and if the method + * <code>close()</code> is explicitly invoked on that resource, but the resource is + * not managed by a try-with-resources block. + * <dl> + * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.reportPotentiallyUnclosedCloseable"</code></dd> + * <dt>Possible values:</dt><dd><code>{ "error", "warning", "ignore" }</code></dd> + * <dt>Default:</dt><dd><code>"ignore"</code></dd> + * </dl> + * @since 3.8 + * @category CompilerOptionID + */ + public static final String COMPILER_PB_EXPLICITLY_CLOSED_AUTOCLOSEABLE = PLUGIN_ID + ".compiler.problem.explicitlyClosedAutoCloseable"; //$NON-NLS-1$ + /** * Compiler option ID: Setting Source Compatibility Mode. * <p>Specify whether which source level compatibility is used. From 1.4 on, <code>'assert'</code> is a keyword * reserved for assertion support. Also note, than when toggling to 1.4 mode, the target VM @@ -1847,6 +1897,19 @@ public final class JavaCore extends Plugin { */ public static final String CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS = PLUGIN_ID + ".classpath.multipleOutputLocations"; //$NON-NLS-1$ /** + * Core option ID: Reporting an output location overlapping another source location. + * <p> Indicate the severity of the problem reported when a source entry's output location overlaps another + * source entry. </p> + * + * <dl> + * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.classpath.outputOverlappingAnotherSource"</code></dd> + * <dt>Possible values:</dt><dd><code>{ "error", "warning", "ignore" }</code></dd> + * <dt>Default:</dt><dd><code>"error"</code></dd> + * </dl> + * @since 3.6.4 + */ + public static final String CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE = PLUGIN_ID + ".classpath.outputOverlappingAnotherSource"; //$NON-NLS-1$ + /** * Core option ID: Set the timeout value for retrieving the method's parameter names from javadoc. * <p>Timeout in milliseconds to retrieve the method's parameter names from javadoc. * <p>If the value is <code>0</code>, the parameter names are not fetched and the raw names are returned. @@ -3714,6 +3777,7 @@ public final class JavaCore extends Plugin { try { if (JavaBuilder.DEBUG) System.out.println("Touching " + project.getElementName()); //$NON-NLS-1$ + new ClasspathValidation((JavaProject) project).validate(); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=287164 project.getProject().touch(progressMonitor2); } catch (CoreException e) { // could not touch this project: ignore diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ByteCodeVisitorAdapter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ByteCodeVisitorAdapter.java index dd894ade6..c23af13ac 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ByteCodeVisitorAdapter.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/ByteCodeVisitorAdapter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -923,8 +923,9 @@ public class ByteCodeVisitorAdapter implements IBytecodeVisitor { // default behavior is to do nothing } /** - * @see IBytecodeVisitor#_invokeinterface(int, int, byte, IConstantPoolEntry) + * @see IBytecodeVisitor#_invokedynamic(int, int, IConstantPoolEntry, IConstantPoolEntry) * @since 3.6 + * @deprecated This has been replaced with {@link IBytecodeVisitor#_invokedynamic(int, int, IConstantPoolEntry)} */ public void _invokedynamic( int pc, @@ -934,6 +935,16 @@ public class ByteCodeVisitorAdapter implements IBytecodeVisitor { // default behavior is to do nothing } /** + * @see IBytecodeVisitor#_invokedynamic(int, int, IConstantPoolEntry) + * @since 3.8 + */ + public void _invokedynamic( + int pc, + int index, + IConstantPoolEntry invokeDynamicEntry) { + // default behavior is to do nothing + } + /** * @see IBytecodeVisitor#_invokeinterface(int, int, byte, IConstantPoolEntry) */ public void _invokeinterface( diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java index e5dafa407..da838ec9c 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IAttributeNamesConstants.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -140,4 +140,10 @@ public interface IAttributeNamesConstants { * @since 3.2 */ char[] STACK_MAP = "StackMap".toCharArray(); //$NON-NLS-1$ + + /** + * "BootstrapMethods" attribute (added in cldc1.0). + * @since 3.8 + */ + char[] BOOTSTRAP_METHODS = "BootstrapMethods".toCharArray(); //$NON-NLS-1$ } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBootstrapMethodsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBootstrapMethodsAttribute.java new file mode 100644 index 000000000..d7bbd91a6 --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBootstrapMethodsAttribute.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2011 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.util; + +/** + * Description of a bootstrap methods attribute as described in the JVM specifications. + * + * This interface may be implemented by clients. + * + * @since 3.8 + */ +public interface IBootstrapMethodsAttribute extends IClassFileAttribute { + + /** + * Answer back the number of bootstrap methods of this entry as specified in + * the JVM specifications. + * + * @return the number of bootstrap methods of this entry as specified in + * the JVM specifications + */ + int getBootstrapMethodsLength(); + + /** + * Answer back the bootstrap methods table of this entry as specified in + * the JVM specifications. Answer an empty array if none. + * + * @return the bootstrap methods table of this entry as specified in + * the JVM specifications. Answer an empty array if none + */ + IBootstrapMethodsEntry[] getBootstrapMethods(); + +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBootstrapMethodsEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBootstrapMethodsEntry.java new file mode 100644 index 000000000..4078e85f9 --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBootstrapMethodsEntry.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2011 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.core.util; + +/** + * Description of a bootstrap method table entry as specified in the JVM specifications. + * + * This interface may be implemented by clients. + * + * @since 3.8 + */ +public interface IBootstrapMethodsEntry { + + int getBootstrapMethodReference(); + int[] getBootstrapArguments(); +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBytecodeVisitor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBytecodeVisitor.java index 52ccb168f..f36db8c38 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBytecodeVisitor.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IBytecodeVisitor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -168,12 +168,20 @@ public interface IBytecodeVisitor { IConstantPoolEntry constantClass); /** * @since 3.6 + * @deprecated This has been replaced with {@link #_invokedynamic(int, int, IConstantPoolEntry)} */ void _invokedynamic( int pc, int index, IConstantPoolEntry nameEntry, IConstantPoolEntry descriptorEntry); + /** + * @since 3.8 + */ + void _invokedynamic( + int pc, + int index, + IConstantPoolEntry invokeDynamic); void _invokeinterface( int pc, int index, diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPool.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPool.java index 69526063b..9f57bb10f 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPool.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPool.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -27,8 +27,7 @@ public interface IConstantPool { int getConstantPoolCount(); /** - * Answer back the type of the entry at the index @index - * in the constant pool. + * Answer back the type of the entry at the given index in the constant pool. * * @param index the index of the entry in the constant pool * @return the type of the entry at the index @index in the constant pool @@ -36,11 +35,14 @@ public interface IConstantPool { int getEntryKind(int index); /** - * Answer back the entry at the index @index - * in the constant pool. + * Answer back the entry at the given index in the constant pool. + * + * <p>The return value can be an instance of {@link IConstantPoolEntry2} if the value returned + * by {@link #getEntryKind(int)} is either {@link IConstantPoolConstant#CONSTANT_MethodHandle}, + * {@link IConstantPoolConstant#CONSTANT_MethodType} or {@link IConstantPoolConstant#CONSTANT_InvokeDynamic}.</p> * * @param index the index of the entry in the constant pool - * @return the entry at the index @index in the constant pool + * @return the entry at the given index in the constant pool */ IConstantPoolEntry decodeEntry(int index); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java index bc7cb54fb..ff6ed22c2 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolConstant.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -29,6 +29,18 @@ public interface IConstantPoolConstant { int CONSTANT_Double = 6; int CONSTANT_NameAndType = 12; int CONSTANT_Utf8 = 1; + /** + * @since 3.8 + */ + int CONSTANT_MethodHandle = 15; + /** + * @since 3.8 + */ + int CONSTANT_MethodType = 16; + /** + * @since 3.8 + */ + int CONSTANT_InvokeDynamic = 18; int CONSTANT_Methodref_SIZE = 5; int CONSTANT_Class_SIZE = 3; @@ -41,5 +53,62 @@ public interface IConstantPoolConstant { int CONSTANT_String_SIZE = 3; int CONSTANT_Utf8_SIZE = 3; int CONSTANT_NameAndType_SIZE = 5; + /** + * @since 3.8 + */ + int CONSTANT_MethodHandle_SIZE = 4; + /** + * @since 3.8 + */ + int CONSTANT_MethodType_SIZE = 3; + /** + * @since 3.8 + */ + int CONSTANT_InvokeDynamic_SIZE = 5; + /** + * The constant is described at 5.4.3.5 in the Java 7 VM specification (part 3). + * @since 3.8 + */ + int METHOD_TYPE_REF_GetField = 1; + /** + * The constant is described at 5.4.3.5 in the Java 7 VM specification (part 3). + * @since 3.8 + */ + int METHOD_TYPE_REF_GetStatic = 2; + /** + * The constant is described at 5.4.3.5 in the Java 7 VM specification (part 3). + * @since 3.8 + */ + int METHOD_TYPE_REF_PutField = 3; + /** + * The constant is described at 5.4.3.5 in the Java 7 VM specification (part 3). + * @since 3.8 + */ + int METHOD_TYPE_REF_PutStatic = 4; + /** + * The constant is described at 5.4.3.5 in the Java 7 VM specification (part 3). + * @since 3.8 + */ + int METHOD_TYPE_REF_InvokeVirtual = 5; + /** + * The constant is described at 5.4.3.5 in the Java 7 VM specification (part 3). + * @since 3.8 + */ + int METHOD_TYPE_REF_InvokeStatic = 6; + /** + * The constant is described at 5.4.3.5 in the Java 7 VM specification (part 3). + * @since 3.8 + */ + int METHOD_TYPE_REF_InvokeSpecial = 7; + /** + * The constant is described at 5.4.3.5 in the Java 7 VM specification (part 3). + * @since 3.8 + */ + int METHOD_TYPE_REF_NewInvokeSpecial = 8; + /** + * The constant is described at 5.4.3.5 in the Java 7 VM specification (part 3). + * @since 3.8 + */ + int METHOD_TYPE_REF_InvokeInterface = 9; } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry.java index 487ad82e4..c75bd40be 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -32,6 +32,7 @@ public interface IConstantPoolEntry { * The value is unspecified otherwise. * * @return the name index for a CONSTANT_Class type entry + * @see IConstantPoolConstant#CONSTANT_Class */ int getClassInfoNameIndex(); @@ -42,16 +43,25 @@ public interface IConstantPoolEntry { * * @return the class index for a CONSTANT_Fieldref, * CONSTANT_Methodref, CONSTANT_InterfaceMethodref type entry + * @see IConstantPoolConstant#CONSTANT_Fieldref + * @see IConstantPoolConstant#CONSTANT_Methodref + * @see IConstantPoolConstant#CONSTANT_InterfaceMethodref */ int getClassIndex(); /** * Returns the nameAndType index for a CONSTANT_Fieldref, - * CONSTANT_Methodref, CONSTANT_InterfaceMethodref type entry. + * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, + * CONSTANT_InvokeDynamic type entry. * The value is unspecified otherwise. * * @return the nameAndType index for a CONSTANT_Fieldref, - * CONSTANT_Methodref, CONSTANT_InterfaceMethodref type entry + * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, + * CONSTANT_InvokeDynamic type entry + * @see IConstantPoolConstant#CONSTANT_Fieldref + * @see IConstantPoolConstant#CONSTANT_Methodref + * @see IConstantPoolConstant#CONSTANT_InterfaceMethodref + * @see IConstantPoolConstant#CONSTANT_InvokeDynamic */ int getNameAndTypeIndex(); @@ -60,6 +70,7 @@ public interface IConstantPoolEntry { * The value is unspecified otherwise. * * @return the string index for a CONSTANT_String type entry + * @see IConstantPoolConstant#CONSTANT_String */ int getStringIndex(); @@ -68,6 +79,7 @@ public interface IConstantPoolEntry { * Returns null otherwise. * * @return the string value for a CONSTANT_String type entry + * @see IConstantPoolConstant#CONSTANT_String */ String getStringValue(); @@ -76,6 +88,7 @@ public interface IConstantPoolEntry { * The value is unspecified otherwise. * * @return the integer value for a CONSTANT_Integer type entry + * @see IConstantPoolConstant#CONSTANT_Integer */ int getIntegerValue(); @@ -84,6 +97,7 @@ public interface IConstantPoolEntry { * The value is unspecified otherwise. * * @return the float value for a CONSTANT_Float type entry + * @see IConstantPoolConstant#CONSTANT_Float */ float getFloatValue(); @@ -92,6 +106,7 @@ public interface IConstantPoolEntry { * The value is unspecified otherwise. * * @return the double value for a CONSTANT_Double type entry + * @see IConstantPoolConstant#CONSTANT_Double */ double getDoubleValue(); @@ -100,6 +115,7 @@ public interface IConstantPoolEntry { * The value is unspecified otherwise. * * @return the long value for a CONSTANT_Long type entry + * @see IConstantPoolConstant#CONSTANT_Long */ long getLongValue(); @@ -108,6 +124,7 @@ public interface IConstantPoolEntry { * The value is unspecified otherwise. * * @return the descriptor index for a CONSTANT_NameAndType type entry + * @see IConstantPoolConstant#CONSTANT_NameAndType */ int getNameAndTypeInfoDescriptorIndex(); @@ -116,6 +133,7 @@ public interface IConstantPoolEntry { * The value is unspecified otherwise. * * @return the name index for a CONSTANT_NameAndType type entry + * @see IConstantPoolConstant#CONSTANT_NameAndType */ int getNameAndTypeInfoNameIndex(); @@ -124,6 +142,7 @@ public interface IConstantPoolEntry { * Returns null otherwise. * * @return the class name for a CONSTANT_Class type entry + * @see IConstantPoolConstant#CONSTANT_Class */ char[] getClassInfoName(); @@ -134,6 +153,9 @@ public interface IConstantPoolEntry { * * @return the class name for a CONSTANT_Fieldref, * CONSTANT_Methodref, CONSTANT_InterfaceMethodref type entry + * @see IConstantPoolConstant#CONSTANT_Fieldref + * @see IConstantPoolConstant#CONSTANT_Methodref + * @see IConstantPoolConstant#CONSTANT_InterfaceMethodref */ char[] getClassName(); @@ -142,16 +164,20 @@ public interface IConstantPoolEntry { * Returns null otherwise. * * @return the field name for a CONSTANT_Fieldref type entry + * @see IConstantPoolConstant#CONSTANT_Fieldref */ char[] getFieldName(); /** - * Returns the field name for a CONSTANT_Methodref or CONSTANT_InterfaceMethodred - * type entry. + * Returns the field name for a CONSTANT_Methodref, CONSTANT_InterfaceMethodref + * or CONSTANT_InvokeDynamic type entry. * Returns null otherwise. * - * @return the field name for a CONSTANT_Methodref or CONSTANT_InterfaceMethodred - * type entry + * @return the method name for a CONSTANT_Methodref, CONSTANT_InterfaceMethodref + * or CONSTANT_InvokeDynamic type entry + * @see IConstantPoolConstant#CONSTANT_Methodref + * @see IConstantPoolConstant#CONSTANT_InterfaceMethodref + * @see IConstantPoolConstant#CONSTANT_InvokeDynamic */ char[] getMethodName(); @@ -162,18 +188,27 @@ public interface IConstantPoolEntry { * * @return the field descriptor value for a CONSTANT_Fieldref type entry. This value * is set only when decoding the CONSTANT_Fieldref entry + * @see IConstantPoolConstant#CONSTANT_Fieldref */ char[] getFieldDescriptor(); /** * Returns the method descriptor value for a CONSTANT_Methodref or * CONSTANT_InterfaceMethodref type entry. This value is set only when decoding the - * CONSTANT_Methodref or CONSTANT_InterfaceMethodref entry. + * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, CONSTANT_MethodType + * or CONSTANT_InvokeDynamic entry. + * * Returns null otherwise. * - * @return the method descriptor value for a CONSTANT_Methodref or + * @return the method descriptor value for a CONSTANT_Methodref, * CONSTANT_InterfaceMethodref type entry. This value is set only when decoding the - * CONSTANT_Methodref or CONSTANT_InterfaceMethodref entry + * CONSTANT_Methodref, CONSTANT_InterfaceMethodref, CONSTANT_MethodType + * or CONSTANT_InvokeDynamic entry + * + * @see IConstantPoolConstant#CONSTANT_Methodref + * @see IConstantPoolConstant#CONSTANT_InterfaceMethodref + * @see IConstantPoolConstant#CONSTANT_MethodType + * @see IConstantPoolConstant#CONSTANT_InvokeDynamic */ char[] getMethodDescriptor(); @@ -184,6 +219,7 @@ public interface IConstantPoolEntry { * * @return the utf8 value for a CONSTANT_Utf8 type entry. This value is set only when * decoding a UTF8 entry + * @see IConstantPoolConstant#CONSTANT_Utf8 */ char[] getUtf8Value(); @@ -194,6 +230,7 @@ public interface IConstantPoolEntry { * * @return the utf8 length for a CONSTANT_Utf8 type entry. This value is set only when * decoding a UTF8 entry + * @see IConstantPoolConstant#CONSTANT_Utf8 */ int getUtf8Length(); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry2.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry2.java new file mode 100644 index 000000000..3b4984bcd --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/util/IConstantPoolEntry2.java @@ -0,0 +1,59 @@ +/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.core.util;
+
+/**
+ * Description of the new constant pool entry as described in the JVM specifications
+ * added for Java 7 support.
+ * Its contents is initialized according to its kind.
+ *
+ * This interface may be implemented by clients.
+ *
+ * @since 3.8
+ */
+public interface IConstantPoolEntry2 extends IConstantPoolEntry {
+ /**
+ * Returns the descriptor index. This value is set only when decoding a MethodType entry.
+ * The value is unspecified otherwise. The corresponding UTF8 value can be retrieved by using
+ * {@link #getMethodDescriptor()}.
+ *
+ * @return the descriptor index. This value is set only when decoding a MethodType entry.
+ * @see IConstantPoolConstant#CONSTANT_MethodType
+ */
+ int getDescriptorIndex();
+
+ /**
+ * Returns the reference kind. This value is set only when decoding a MethodHandle entry.
+ * The value is unspecified otherwise.
+ *
+ * @return the reference kind. This value is set only when decoding a MethodHandle entry.
+ * @see IConstantPoolConstant#CONSTANT_MethodHandle
+ */
+ int getReferenceKind();
+
+ /**
+ * Returns the reference index. This value is set only when decoding a MethodHandle entry.
+ * The value is unspecified otherwise.
+ *
+ * @return the reference kind. This value is set only when decoding a MethodHandle entry.
+ * @see IConstantPoolConstant#CONSTANT_MethodHandle
+ */
+ int getReferenceIndex();
+
+ /**
+ * Returns the bootstrap method attribute index. This value is set only when decoding a InvokeDynamic entry.
+ * The value is unspecified otherwise.
+ *
+ * @return the reference kind. This value is set only when decoding a MethodHandle entry.
+ * @see IConstantPoolConstant#CONSTANT_InvokeDynamic
+ */
+ int getBootstrapMethodAttributeIndex();
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java index fbd0b539b..d1bbbb38a 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/compiler/parser/SourceTypeConverter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -8,7 +8,9 @@ * * Contributors: * IBM Corporation - initial API and implementation - * Stephan Herrmann <stephan@cs.tu-berlin.de> - TypeConverters don't set enclosingType - https://bugs.eclipse.org/bugs/show_bug.cgi?id=320841 + * Stephan Herrmann <stephan@cs.tu-berlin.de> - Contributions for + * Bug 320841 - TypeConverters don't set enclosingType + * Bug 353474 - type converters should include more annotations * Fraunhofer FIRST - extended API and implementation * Technical University Berlin - extended API and implementation *******************************************************************************/ @@ -32,6 +34,7 @@ import org.eclipse.jdt.core.IAnnotatable; import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.IImportDeclaration; import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.ILocalVariable; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; @@ -405,6 +408,7 @@ public class SourceTypeConverter extends TypeConverter { char[][] argumentNames = methodInfo.getArgumentNames(); int argumentCount = argumentTypeSignatures == null ? 0 : argumentTypeSignatures.length; if (argumentCount > 0) { + ILocalVariable[] parameters = methodHandle.getParameters(); long position = ((long) start << 32) + end; method.arguments = new Argument[argumentCount]; for (int i = 0; i < argumentCount; i++) { @@ -426,6 +430,11 @@ public class SourceTypeConverter extends TypeConverter { typeReference, ClassFileConstants.AccDefault); // do not care whether was final or not + // convert 1.5 specific constructs only if compliance is 1.5 or above + if (this.has1_5Compliance) { + /* convert annotations */ + method.arguments[i].annotations = convertAnnotations(parameters[i]); + } } } //{ObjectTeams: enhance signature for callin method: diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java index d8086ffc9..5656323e4 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Terry Parker <tparker@google.com> - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425 *******************************************************************************/ package org.eclipse.jdt.internal.core; @@ -1776,6 +1777,7 @@ public class ClasspathEntry implements IClasspathEntry { // perform one separate iteration so as to not take precedence over previously checked scenarii (in particular should // diagnose nesting source folder issue before this one, for example, [src]"Project/", [src]"Project/source/" and output="Project/" should // first complain about missing exclusion pattern + IJavaModelStatus cachedStatus = null; for (int i = 0 ; i < length; i++) { IClasspathEntry entry = classpath[i]; if (entry == null) continue; @@ -1788,30 +1790,53 @@ public class ClasspathEntry implements IClasspathEntry { if (kind == IClasspathEntry.CPE_SOURCE) { IPath output = entry.getOutputLocation(); - if (output == null) continue; // 36465 - for 2.0 backward compatibility, only check specific output locations (the default can still coincidate) - // if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output (this line would check default output) + if (output == null) output = projectOutputLocation; // if no specific output, still need to check using default output (this line would check default output) for (int j = 0; j < length; j++) { IClasspathEntry otherEntry = classpath[j]; if (otherEntry == entry) continue; - // Build some common strings for status message - boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0)); - String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString(); - switch (otherEntry.getEntryKind()) { case IClasspathEntry.CPE_SOURCE : - if (otherEntry.getPath().equals(output)) { - return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[] {entryPathMsg, otherPathMsg, projectName})); + // Bug 287164 : Report errors of overlapping output locations only if the user sets the corresponding preference. + // The check is required for backward compatibility with bug-fix 36465. + String option = javaProject.getOption(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, true); + if (otherEntry.getPath().equals(output) + && !JavaCore.IGNORE.equals(option)) { + boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0)); + String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString(); + if (JavaCore.ERROR.equals(option)) { + return new JavaModelStatus(IStatus.ERROR, IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, + Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[] { + entryPathMsg, otherPathMsg, projectName })); + } + if (cachedStatus == null) { + // Note that the isOK() is being overridden to return true. This is an exceptional scenario + cachedStatus = new JavaModelStatus(IStatus.OK, IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, + Messages.bind(Messages.classpath_cannotUseDistinctSourceFolderAsOutput, new String[] { + entryPathMsg, otherPathMsg, projectName })){ + public boolean isOK() { + return true; + } + }; + } } break; case IClasspathEntry.CPE_LIBRARY : - if (otherEntry.getPath().equals(output)) { + if (output != projectOutputLocation && otherEntry.getPath().equals(output)) { + boolean opStartsWithProject = projectName.equals(otherEntry.getPath().segment(0)); + String otherPathMsg = opStartsWithProject ? otherEntry.getPath().removeFirstSegments(1).toString() : otherEntry.getPath().makeRelative().toString(); return new JavaModelStatus(IJavaModelStatusConstants.INVALID_CLASSPATH, Messages.bind(Messages.classpath_cannotUseLibraryAsOutput, new String[] {entryPathMsg, otherPathMsg, projectName})); } } } } } + + // NOTE: The above code that checks for IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, can be configured to return + // a WARNING status and hence should be at the end of this validation method. Any other code that might return a more severe ERROR should be + // inserted before the mentioned code. + if (cachedStatus != null) return cachedStatus; + return JavaModelStatus.VERIFIED_OK; } @@ -1827,6 +1852,9 @@ public class ClasspathEntry implements IClasspathEntry { * @return a java model status describing the problem related to this classpath entry if any, a status object with code <code>IStatus.OK</code> if the entry is fine */ public static IJavaModelStatus validateClasspathEntry(IJavaProject project, IClasspathEntry entry, boolean checkSourceAttachment, boolean referredByContainer){ + if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { + JavaModelManager.getJavaModelManager().removeFromInvalidArchiveCache(entry.getPath()); + } IJavaModelStatus status = validateClasspathEntry(project, entry, null, checkSourceAttachment, referredByContainer); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=171136 and https://bugs.eclipse.org/bugs/show_bug.cgi?id=300136 // Ignore class path errors from optional entries. diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java index ea310a3c2..345535ac1 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathValidation.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -12,6 +12,7 @@ package org.eclipse.jdt.internal.core; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaModelStatus; import org.eclipse.jdt.core.JavaModelException; @@ -37,7 +38,7 @@ public class ClasspathValidation { // project doesn't exist IProject resource = this.project.getProject(); if (resource.isAccessible()) { - this.project.flushClasspathProblemMarkers(true/*flush cycle markers*/, true/*flush classpath format markers*/); + this.project.flushClasspathProblemMarkers(true/*flush cycle markers*/, true/*flush classpath format markers*/, true /*flush overlapping output markers*/); // remove problems and tasks created by the builder JavaBuilder.removeProblemsAndTasksFor(resource); @@ -56,12 +57,15 @@ public class ClasspathValidation { } // update classpath format problems - this.project.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/); + this.project.flushClasspathProblemMarkers(false/*cycle*/, true/*format*/, false/*overlapping*/); if (!status.isOK()) this.project.createClasspathProblemMarker(status); + // update overlapping output problem markers + this.project.flushClasspathProblemMarkers(false/*cycle*/, false/*format*/, true/*overlapping*/); + // update resolved classpath problems - this.project.flushClasspathProblemMarkers(false/*cycle*/, false/*format*/); + this.project.flushClasspathProblemMarkers(false/*cycle*/, false/*format*/, false/*overlapping*/); if (rawClasspath != JavaProject.INVALID_CLASSPATH && outputLocation != null) { for (int i = 0; i < rawClasspath.length; i++) { @@ -71,7 +75,7 @@ public class ClasspathValidation { } } status = ClasspathEntry.validateClasspath(this.project, rawClasspath, outputLocation); - if (!status.isOK()) + if (status.getCode() != IStatus.OK) this.project.createClasspathProblemMarker(status); } } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java index f2b617350..4a1d8ba87 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnitProblemFinder.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -100,8 +100,9 @@ public class CompilationUnitProblemFinder extends Compiler { */ public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) { // ensure to jump back to toplevel type for first one (could be a member) -// while (sourceTypes[0].getEnclosingType() != null) -// sourceTypes[0] = sourceTypes[0].getEnclosingType(); + while (sourceTypes[0].getEnclosingType() != null) { + sourceTypes[0] = sourceTypes[0].getEnclosingType(); + } CompilationResult result = new CompilationResult(sourceTypes[0].getFileName(), 1, 1, this.options.maxProblemsPerUnit); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java index f7a0c1cb8..126fcc918 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java @@ -8,6 +8,7 @@ * Contributors: * IBM Corporation - initial API and implementation * Terry Parker <tparker@google.com> - DeltaProcessor exhibits O(N^2) behavior, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=354332 + * Terry Parker <tparker@google.com> - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425 *******************************************************************************/ package org.eclipse.jdt.internal.core; @@ -954,7 +955,7 @@ public class DeltaProcessor { // project does not exist -> ignore continue; } - boolean hasChainedJar = false; + boolean deltaContainsModifiedJar = false; for (int j = 0; j < entries.length; j++){ if (entries[j].getEntryKind() == IClasspathEntry.CPE_LIBRARY) { IPath entryPath = entries[j].getPath(); @@ -1024,7 +1025,7 @@ public class DeltaProcessor { System.out.println("- External JAR ADDED, affecting root: "+root.getElementName()); //$NON-NLS-1$ } elementAdded(root, null, null); - hasChainedJar |= !this.manager.isNonChainingJar(entryPath); + deltaContainsModifiedJar = true; this.state.addClasspathValidation(javaProject); // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=185733 hasDelta = true; } else if (status == EXTERNAL_JAR_CHANGED) { @@ -1033,7 +1034,7 @@ public class DeltaProcessor { System.out.println("- External JAR CHANGED, affecting root: "+root.getElementName()); //$NON-NLS-1$ } contentChanged(root); - hasChainedJar |= !this.manager.isNonChainingJar(entryPath); + deltaContainsModifiedJar = true; hasDelta = true; } else if (status == EXTERNAL_JAR_REMOVED) { PackageFragmentRoot root = (PackageFragmentRoot) javaProject.getPackageFragmentRoot(entryPath.toString()); @@ -1041,7 +1042,7 @@ public class DeltaProcessor { System.out.println("- External JAR REMOVED, affecting root: "+root.getElementName()); //$NON-NLS-1$ } elementRemoved(root, null, null); - hasChainedJar |= !this.manager.isNonChainingJar(entryPath); + deltaContainsModifiedJar = true; this.state.addClasspathValidation(javaProject); // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=185733 hasDelta = true; } @@ -1049,7 +1050,7 @@ public class DeltaProcessor { } } - if (hasChainedJar) { + if (deltaContainsModifiedJar) { javaProject.resetResolvedClasspath(); } } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java index 532ed94d7..91c6ddeca 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java @@ -58,6 +58,7 @@ public class JavaCorePreferenceInitializer extends AbstractPreferenceInitializer defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, JavaCore.ENABLED); + defaultOptionsMap.put(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, JavaCore.ERROR); // encoding setting comes from resource plug-in optionNames.add(JavaCore.CORE_ENCODING); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java index 4127a2236..d9048ce78 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java @@ -11,6 +11,7 @@ * before its contents * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=102422) * Stephan Herrmann - Contribution for Bug 346010 - [model] strange initialization dependency in OptionTests + * Terry Parker <tparker@google.com> - DeltaProcessor misses state changes in archive files, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=357425 * Technical University Berlin - extended API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.core; @@ -1487,7 +1488,8 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS) || propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) || propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) || - propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL)) { + propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL) || + propertyName.equals(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE)) { JavaModelManager manager = JavaModelManager.getJavaModelManager(); IJavaModel model = manager.getJavaModel(); IJavaProject[] projects; @@ -2254,7 +2256,8 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis defaultOptionsMap.put(JavaCore.CORE_JAVA_BUILD_ORDER, JavaCore.IGNORE); defaultOptionsMap.put(JavaCore.CORE_INCOMPLETE_CLASSPATH, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_CIRCULAR_CLASSPATH, JavaCore.ERROR); - defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE); + defaultOptionsMap.put(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL, JavaCore.IGNORE); + defaultOptionsMap.put(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, JavaCore.ERROR); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_EXCLUSION_PATTERNS, JavaCore.ENABLED); defaultOptionsMap.put(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS, JavaCore.ENABLED); @@ -3092,6 +3095,12 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis return this.invalidArchives != null && this.invalidArchives.contains(path); } + public void removeFromInvalidArchiveCache(IPath path) { + if (this.invalidArchives != null) { + this.invalidArchives.remove(path); + } + } + public void setClasspathBeingResolved(IJavaProject project, boolean classpathIsResolved) { if (classpathIsResolved) { getClasspathBeingResolved().add(project); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java index 5de8f6480..5fd9dce56 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java @@ -437,7 +437,7 @@ public class JavaProject new JavaModelStatus(IJavaModelStatusConstants.CLASSPATH_CYCLE, project, cycleString)); } } else { - project.flushClasspathProblemMarkers(true, false); + project.flushClasspathProblemMarkers(true, false, false); } } } @@ -807,7 +807,7 @@ public class JavaProject IMarker marker = null; int severity; String[] arguments = CharOperation.NO_STRINGS; - boolean isCycleProblem = false, isClasspathFileFormatProblem = false; + boolean isCycleProblem = false, isClasspathFileFormatProblem = false, isOutputOverlapping = false; switch (status.getCode()) { case IJavaModelStatusConstants.CLASSPATH_CYCLE : @@ -834,7 +834,17 @@ public class JavaProject return; // setting == IGNORE } break; - + case IJavaModelStatusConstants.OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE : + isOutputOverlapping = true; + setting = getOption(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE, true); + if (JavaCore.ERROR.equals(setting)) { + severity = IMarker.SEVERITY_ERROR; + } else if (JavaCore.WARNING.equals(setting)) { + severity = IMarker.SEVERITY_WARNING; + } else { + return; // setting == IGNORE + } + break; default: IPath path = status.getPath(); if (path != null) arguments = new String[] { path.toString() }; @@ -856,6 +866,7 @@ public class JavaProject IMarker.LOCATION, IJavaModelMarker.CYCLE_DETECTED, IJavaModelMarker.CLASSPATH_FILE_FORMAT, + IJavaModelMarker.OUTPUT_OVERLAPPING_SOURCE, IJavaModelMarker.ID, IJavaModelMarker.ARGUMENTS , IJavaModelMarker.CATEGORY_ID, @@ -867,6 +878,7 @@ public class JavaProject Messages.classpath_buildPath, isCycleProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$ isClasspathFileFormatProblem ? "true" : "false",//$NON-NLS-1$ //$NON-NLS-2$ + isOutputOverlapping ? "true" : "false", //$NON-NLS-1$ //$NON-NLS-2$ new Integer(status.getCode()), Util.getProblemArgumentsForMarker(arguments) , new Integer(CategorizedProblem.CAT_BUILDPATH), @@ -1387,18 +1399,20 @@ public class JavaProject /** * Remove all markers denoting classpath problems */ //TODO (philippe) should improve to use a bitmask instead of booleans (CYCLE, FORMAT, VALID) - protected void flushClasspathProblemMarkers(boolean flushCycleMarkers, boolean flushClasspathFormatMarkers) { + protected void flushClasspathProblemMarkers(boolean flushCycleMarkers, boolean flushClasspathFormatMarkers, boolean flushOverlappingOutputMarkers) { try { if (this.project.isAccessible()) { IMarker[] markers = this.project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO); for (int i = 0, length = markers.length; i < length; i++) { IMarker marker = markers[i]; - if (flushCycleMarkers && flushClasspathFormatMarkers) { + if (flushCycleMarkers && flushClasspathFormatMarkers && flushOverlappingOutputMarkers) { marker.delete(); } else { String cycleAttr = (String)marker.getAttribute(IJavaModelMarker.CYCLE_DETECTED); String classpathFileFormatAttr = (String)marker.getAttribute(IJavaModelMarker.CLASSPATH_FILE_FORMAT); + String overlappingOutputAttr = (String) marker.getAttribute(IJavaModelMarker.OUTPUT_OVERLAPPING_SOURCE); if ((flushCycleMarkers == (cycleAttr != null && cycleAttr.equals("true"))) //$NON-NLS-1$ + && (flushOverlappingOutputMarkers == (overlappingOutputAttr != null && overlappingOutputAttr.equals("true"))) //$NON-NLS-1$ && (flushClasspathFormatMarkers == (classpathFileFormatAttr != null && classpathFileFormatAttr.equals("true")))){ //$NON-NLS-1$ marker.delete(); } @@ -1545,6 +1559,7 @@ public class JavaProject propertyName.equals(JavaCore.CORE_ENABLE_CLASSPATH_MULTIPLE_OUTPUT_LOCATIONS) || propertyName.equals(JavaCore.CORE_INCOMPLETE_CLASSPATH) || propertyName.equals(JavaCore.CORE_CIRCULAR_CLASSPATH) || + propertyName.equals(JavaCore.CORE_OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE) || propertyName.equals(JavaCore.CORE_INCOMPATIBLE_JDK_LEVEL)) { manager.deltaState.addClasspathValidation(JavaProject.this); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java index 59c69cec5..d08dff54f 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/NameLookup.java @@ -987,6 +987,13 @@ public class NameLookup implements SuffixConstants { break; case IPackageFragmentRoot.K_SOURCE : seekTypesInSourcePackage(matchName, pkg, firstDot, partialMatch, topLevelTypeName, acceptFlags, requestor); + if (matchName.indexOf('$') != -1) { + matchName= matchName.replace('$', '.'); + firstDot = matchName.indexOf('.'); + if (!partialMatch) + topLevelTypeName = firstDot == -1 ? matchName : matchName.substring(0, firstDot); + seekTypesInSourcePackage(matchName, pkg, firstDot, partialMatch, topLevelTypeName, acceptFlags, requestor); + } break; default : return; diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java index 96238136d..ec0ccf277 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SetClasspathOperation.java @@ -114,6 +114,7 @@ public class SetClasspathOperation extends ChangeClasspathOperation { IJavaModelStatus status = super.verify(); if (!status.isOK()) return status; + this.project.flushClasspathProblemMarkers(false, false, true); return ClasspathEntry.validateClasspath( this.project, this.newRawClasspath, this.newOutputLocation); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java index 3b170b51b..fda0e8fa1 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/State.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -46,7 +46,7 @@ private long previousStructuralBuildTime; private StringSet structurallyChangedTypes; public static int MaxStructurallyChangedTypes = 100; // keep track of ? structurally changed types, otherwise consider all to be changed -public static final byte VERSION = 0x0019; // fix for 325755 +public static final byte VERSION = 0x001A; // fix for 287164 static final byte SOURCE_FOLDER = 1; static final byte BINARY_FOLDER = 2; diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsAttribute.java new file mode 100644 index 000000000..b196927ea --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsAttribute.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2011 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.util; + +import org.eclipse.jdt.core.util.ClassFormatException; +import org.eclipse.jdt.core.util.IBootstrapMethodsAttribute; +import org.eclipse.jdt.core.util.IBootstrapMethodsEntry; +import org.eclipse.jdt.core.util.IConstantPool; + +/** + * Default implementation of IBootstrapMethodsAttribute. + */ +public class BootstrapMethodsAttribute extends ClassFileAttribute implements IBootstrapMethodsAttribute { + private static final IBootstrapMethodsEntry[] NO_ENTRIES = new IBootstrapMethodsEntry[0]; + + private IBootstrapMethodsEntry[] entries; + private int numberOfBootstrapMethods; + + /** + * Constructor for BootstrapMethodsAttribute. + * @param classFileBytes + * @param constantPool + * @param offset + * @throws ClassFormatException + */ + public BootstrapMethodsAttribute( + byte[] classFileBytes, + IConstantPool constantPool, + int offset) throws ClassFormatException { + super(classFileBytes, constantPool, offset); + this.numberOfBootstrapMethods = u2At(classFileBytes, 6, offset); + final int length = this.numberOfBootstrapMethods; + if (length != 0) { + int readOffset = 8; + this.entries = new IBootstrapMethodsEntry[length]; + for (int i = 0; i < length; i++) { + this.entries[i] = new BootstrapMethodsEntry(classFileBytes, constantPool, offset + readOffset); + readOffset += 8; + } + } else { + this.entries = NO_ENTRIES; + } + } + + /** + * @see IBootstrapMethodsAttribute#getBootstrapMethods() + */ + public IBootstrapMethodsEntry[] getBootstrapMethods() { + return this.entries; + } + + public int getBootstrapMethodsLength() { + return this.numberOfBootstrapMethods; + } +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsEntry.java new file mode 100644 index 000000000..e444dbd81 --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/BootstrapMethodsEntry.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2011 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.util; + +import org.eclipse.jdt.core.util.ClassFormatException; +import org.eclipse.jdt.core.util.IBootstrapMethodsEntry; +import org.eclipse.jdt.core.util.IConstantPool; + +/** + * Default implementation of {@link IBootstrapMethodsEntry} + */ +public class BootstrapMethodsEntry + extends ClassFileStruct + implements IBootstrapMethodsEntry { + + private int bootstrapMethodReference; + private int[] bootstrapArguments; + + public BootstrapMethodsEntry(byte classFileBytes[], IConstantPool constantPool, int offset) throws ClassFormatException { + this.bootstrapMethodReference = u2At(classFileBytes, 0, offset); + int length = u2At(classFileBytes, 2, offset); + int[] arguments = new int[length]; + int position = 4; + for (int i = 0; i < length; i++) { + arguments[i] = u2At(classFileBytes, position, offset); + position += 2; + } + this.bootstrapArguments = arguments; + } + + /** + * @see IBootstrapMethodsEntry#getBootstrapArguments() + */ + public int[] getBootstrapArguments() { + return this.bootstrapArguments; + } + + /** + * @see IBootstrapMethodsEntry#getBootstrapMethodReference() + */ + public int getBootstrapMethodReference() { + return this.bootstrapMethodReference; + } +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java index 19b80dcc3..0426dc431 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ClassFileReader.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -140,6 +140,18 @@ public class ClassFileReader extends ClassFileStruct implements IClassFileReader constantPoolOffsets[i] = readOffset; readOffset += IConstantPoolConstant.CONSTANT_NameAndType_SIZE; break; + case IConstantPoolConstant.CONSTANT_MethodHandle : + constantPoolOffsets[i] = readOffset; + readOffset += IConstantPoolConstant.CONSTANT_MethodHandle_SIZE; + break; + case IConstantPoolConstant.CONSTANT_MethodType : + constantPoolOffsets[i] = readOffset; + readOffset += IConstantPoolConstant.CONSTANT_MethodType_SIZE; + break; + case IConstantPoolConstant.CONSTANT_InvokeDynamic : + constantPoolOffsets[i] = readOffset; + readOffset += IConstantPoolConstant.CONSTANT_InvokeDynamic_SIZE; + break; default: throw new ClassFormatException(ClassFormatException.INVALID_TAG_CONSTANT); } @@ -261,6 +273,8 @@ public class ClassFileReader extends ClassFileStruct implements IClassFileReader this.attributes[attributesIndex++] = new RuntimeVisibleAnnotationsAttribute(classFileBytes, this.constantPool, readOffset); } else if (equals(attributeName, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS)) { this.attributes[attributesIndex++] = new RuntimeInvisibleAnnotationsAttribute(classFileBytes, this.constantPool, readOffset); + } else if (equals(attributeName, IAttributeNamesConstants.BOOTSTRAP_METHODS)) { + this.attributes[attributesIndex++] = new BootstrapMethodsAttribute(classFileBytes, this.constantPool, readOffset); } else { this.attributes[attributesIndex++] = new ClassFileAttribute(classFileBytes, this.constantPool, readOffset); } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeAttribute.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeAttribute.java index 82ba955ae..a281ab0df 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeAttribute.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/CodeAttribute.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -1049,14 +1049,13 @@ public class CodeAttribute extends ClassFileAttribute implements ICodeAttribute case IOpcodeMnemonics.INVOKEDYNAMIC : index = u2At(this.classFileBytes, 1, pc); constantPoolEntry = this.constantPool.decodeEntry(index); - if (constantPoolEntry.getKind() != IConstantPoolConstant.CONSTANT_NameAndType) { + if (constantPoolEntry.getKind() != IConstantPoolConstant.CONSTANT_InvokeDynamic) { throw new ClassFormatException(ClassFormatException.INVALID_CONSTANT_POOL_ENTRY); } visitor._invokedynamic( pc - this.codeOffset, index, - this.constantPool.decodeEntry(constantPoolEntry.getNameAndTypeInfoNameIndex()), - this.constantPool.decodeEntry(constantPoolEntry.getNameAndTypeInfoDescriptorIndex())); + constantPoolEntry); pc += 5; break; case IOpcodeMnemonics.NEW : diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPool.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPool.java index aeeee24fc..a9c4699b2 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPool.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPool.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -33,19 +33,28 @@ public class ConstantPool extends ClassFileStruct implements IConstantPool { * @see IConstantPool#decodeEntry(int) */ public IConstantPoolEntry decodeEntry(int index) { - ConstantPoolEntry constantPoolEntry = new ConstantPoolEntry(); - constantPoolEntry.reset(); + ConstantPoolEntry constantPoolEntry = null; int kind = getEntryKind(index); - constantPoolEntry.setKind(kind); switch(kind) { case IConstantPoolConstant.CONSTANT_Class : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setClassInfoNameIndex(u2At(this.classFileBytes, 1, this.constantPoolOffset[index])); constantPoolEntry.setClassInfoName(getUtf8ValueAt(constantPoolEntry.getClassInfoNameIndex())); break; case IConstantPoolConstant.CONSTANT_Double : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setDoubleValue(doubleAt(this.classFileBytes, 1, this.constantPoolOffset[index])); break; case IConstantPoolConstant.CONSTANT_Fieldref : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setClassIndex(u2At(this.classFileBytes, 1, this.constantPoolOffset[index])); int declaringClassIndex = u2At(this.classFileBytes, 1, this.constantPoolOffset[constantPoolEntry.getClassIndex()]); constantPoolEntry.setClassName(getUtf8ValueAt(declaringClassIndex)); @@ -57,6 +66,11 @@ public class ConstantPool extends ClassFileStruct implements IConstantPool { break; case IConstantPoolConstant.CONSTANT_Methodref : case IConstantPoolConstant.CONSTANT_InterfaceMethodref : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setClassIndex(u2At(this.classFileBytes, 1, this.constantPoolOffset[index])); declaringClassIndex = u2At(this.classFileBytes, 1, this.constantPoolOffset[constantPoolEntry.getClassIndex()]); constantPoolEntry.setClassName(getUtf8ValueAt(declaringClassIndex)); @@ -67,25 +81,76 @@ public class ConstantPool extends ClassFileStruct implements IConstantPool { constantPoolEntry.setMethodDescriptor(getUtf8ValueAt(methodDescriptorIndex)); break; case IConstantPoolConstant.CONSTANT_Float : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setFloatValue(floatAt(this.classFileBytes, 1, this.constantPoolOffset[index])); break; case IConstantPoolConstant.CONSTANT_Integer : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setIntegerValue(i4At(this.classFileBytes, 1, this.constantPoolOffset[index])); break; case IConstantPoolConstant.CONSTANT_Long : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setLongValue(i8At(this.classFileBytes, 1, this.constantPoolOffset[index])); break; case IConstantPoolConstant.CONSTANT_NameAndType : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setNameAndTypeNameIndex(u2At(this.classFileBytes, 1, this.constantPoolOffset[index])); constantPoolEntry.setNameAndTypeDescriptorIndex(u2At(this.classFileBytes, 3, this.constantPoolOffset[index])); break; case IConstantPoolConstant.CONSTANT_String : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setStringIndex(u2At(this.classFileBytes, 1, this.constantPoolOffset[index])); constantPoolEntry.setStringValue(getUtf8ValueAt(constantPoolEntry.getStringIndex())); break; case IConstantPoolConstant.CONSTANT_Utf8 : + constantPoolEntry = new ConstantPoolEntry(); + constantPoolEntry.reset(); + constantPoolEntry.setKind(kind); constantPoolEntry.setUtf8Length(u2At(this.classFileBytes, 1, this.constantPoolOffset[index])); constantPoolEntry.setUtf8Value(getUtf8ValueAt(index)); + break; + case IConstantPoolConstant.CONSTANT_MethodHandle : + ConstantPoolEntry2 constantPoolEntry2 = new ConstantPoolEntry2(); + constantPoolEntry2.reset(); + constantPoolEntry2.setKind(kind); + constantPoolEntry2.setReferenceKind(u1At(this.classFileBytes, 1, this.constantPoolOffset[index])); + constantPoolEntry2.setReferenceIndex(u2At(this.classFileBytes, 2, this.constantPoolOffset[index])); + constantPoolEntry = constantPoolEntry2; + break; + case IConstantPoolConstant.CONSTANT_MethodType : + constantPoolEntry2 = new ConstantPoolEntry2(); + constantPoolEntry2.reset(); + constantPoolEntry2.setKind(kind); + methodDescriptorIndex = u2At(this.classFileBytes, 1, this.constantPoolOffset[index]); + constantPoolEntry2.setDescriptorIndex(methodDescriptorIndex); + constantPoolEntry2.setMethodDescriptor(getUtf8ValueAt(methodDescriptorIndex)); + constantPoolEntry = constantPoolEntry2; + break; + case IConstantPoolConstant.CONSTANT_InvokeDynamic : + constantPoolEntry2 = new ConstantPoolEntry2(); + constantPoolEntry2.reset(); + constantPoolEntry2.setKind(kind); + constantPoolEntry2.setBootstrapMethodAttributeIndex(u2At(this.classFileBytes, 1, this.constantPoolOffset[index])); + int nameAndTypeIndex = u2At(this.classFileBytes, 3, this.constantPoolOffset[index]); + constantPoolEntry2.setNameAndTypeIndex(nameAndTypeIndex); + methodNameIndex = u2At(this.classFileBytes, 1, this.constantPoolOffset[nameAndTypeIndex]); + methodDescriptorIndex = u2At(this.classFileBytes, 3, this.constantPoolOffset[nameAndTypeIndex]); + constantPoolEntry2.setMethodName(getUtf8ValueAt(methodNameIndex)); + constantPoolEntry2.setMethodDescriptor(getUtf8ValueAt(methodDescriptorIndex)); + constantPoolEntry = constantPoolEntry2; + break; } return constantPoolEntry; } diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry.java index 55cc17027..9f9cae664 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ -341,6 +341,7 @@ public class ConstantPoolEntry implements IConstantPoolEntry { /** * Sets the methodDescriptor. + * * @param methodDescriptor The methodDescriptor to set */ public void setMethodDescriptor(char[] methodDescriptor) { diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry2.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry2.java new file mode 100644 index 000000000..c6c968625 --- /dev/null +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/ConstantPoolEntry2.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2000, 2011 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.util; + +import org.eclipse.jdt.core.util.IConstantPoolEntry2; + +/** + * Default implementation of IConstantPoolEntry + * + * @since 2.0 + */ +public class ConstantPoolEntry2 extends ConstantPoolEntry implements IConstantPoolEntry2 { + + private int descriptorIndex; + private int referenceKind; + private int referenceIndex; + private int bootstrapMethodAttributeIndex; + + public int getDescriptorIndex() { + return this.descriptorIndex; + } + + public int getReferenceKind() { + return this.referenceKind; + } + + public int getReferenceIndex() { + return this.referenceIndex; + } + + public int getBootstrapMethodAttributeIndex() { + return this.bootstrapMethodAttributeIndex; + } + + public void setDescriptorIndex(int descriptorIndex) { + this.descriptorIndex = descriptorIndex; + } + + public void setReferenceKind(int referenceKind) { + this.referenceKind = referenceKind; + } + + public void setReferenceIndex(int referenceIndex) { + this.referenceIndex = referenceIndex; + } + + public void setBootstrapMethodAttributeIndex(int bootstrapMethodAttributeIndex) { + this.bootstrapMethodAttributeIndex = bootstrapMethodAttributeIndex; + } + + public void reset() { + super.reset(); + this.descriptorIndex = 0; + this.referenceKind = 0; + this.referenceIndex = 0; + this.bootstrapMethodAttributeIndex = 0; + } +} diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultBytecodeVisitor.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultBytecodeVisitor.java index d94dd4e28..b5fe2abab 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultBytecodeVisitor.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/DefaultBytecodeVisitor.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. + * Copyright (c) 2000, 2011 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 @@ import org.eclipse.jdt.core.util.IBytecodeVisitor; import org.eclipse.jdt.core.util.ICodeAttribute; import org.eclipse.jdt.core.util.IConstantPoolConstant; import org.eclipse.jdt.core.util.IConstantPoolEntry; +import org.eclipse.jdt.core.util.IConstantPoolEntry2; import org.eclipse.jdt.core.util.ILocalVariableAttribute; import org.eclipse.jdt.core.util.ILocalVariableTableEntry; import org.eclipse.jdt.core.util.OpcodeStringValues; @@ -1491,7 +1492,7 @@ public class DefaultBytecodeVisitor implements IBytecodeVisitor { writeNewLine(); } /** - * @see IBytecodeVisitor#_invokedynamic(int, int, IConstantPoolEntry, IConstantPoolEntry) + * @see IBytecodeVisitor#_invokedynamic(int, int, IConstantPoolEntry) */ public void _invokedynamic( int pc, @@ -1513,6 +1514,30 @@ public class DefaultBytecodeVisitor implements IBytecodeVisitor { writeNewLine(); } /** + * @see IBytecodeVisitor#_invokedynamic(int, int, IConstantPoolEntry) + */ + public void _invokedynamic( + int pc, + int index, + IConstantPoolEntry invokeDynamicEntry) { + + dumpPcNumber(pc); + IConstantPoolEntry2 entry = (IConstantPoolEntry2) invokeDynamicEntry; + this.buffer.append(Messages.bind(Messages.classformat_invokedynamic, + new String[] { + OpcodeStringValues.BYTECODE_NAMES[IOpcodeMnemonics.INVOKEDYNAMIC], + Integer.toString(index), + Integer.toString(entry.getBootstrapMethodAttributeIndex()), + Util.toString( + null, + entry.getMethodName(), + entry.getMethodDescriptor(), + true, + isCompact()) + })); + writeNewLine(); + } + /** * @see IBytecodeVisitor#_invokeinterface(int, int, byte, IConstantPoolEntry) */ public void _invokeinterface( diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java index c54fd7395..067a219a2 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Disassembler.java @@ -741,7 +741,7 @@ public class Disassembler extends ClassFileBytesDisassembler { final int classNameLength = className.length; final int accessFlags = classFileReader.getAccessFlags(); final boolean isEnum = (accessFlags & IModifierConstants.ACC_ENUM) != 0; - + StringBuffer buffer = new StringBuffer(); ISourceAttribute sourceAttribute = classFileReader.getSourceFileAttribute(); IClassFileAttribute classFileAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.SIGNATURE); @@ -788,7 +788,7 @@ public class Disassembler extends ClassFileBytesDisassembler { } } final int lastDotIndexInClassName = CharOperation.lastIndexOf('.', className); - + if (checkMode(mode, WORKING_COPY) && lastDotIndexInClassName != -1) { // we print a package declaration buffer.append("package ");//$NON-NLS-1$ @@ -796,11 +796,13 @@ public class Disassembler extends ClassFileBytesDisassembler { buffer.append(';'); writeNewLine(buffer, lineSeparator, 0); } - + IInnerClassesAttribute innerClassesAttribute = classFileReader.getInnerClassesAttribute(); IClassFileAttribute runtimeVisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_VISIBLE_ANNOTATIONS); IClassFileAttribute runtimeInvisibleAnnotationsAttribute = Util.getAttribute(classFileReader, IAttributeNamesConstants.RUNTIME_INVISIBLE_ANNOTATIONS); - + + IClassFileAttribute bootstrapMethods = Util.getAttribute(classFileReader, IAttributeNamesConstants.BOOTSTRAP_METHODS); + if (checkMode(mode, DETAILED)) { // disassemble compact version of annotations if (runtimeInvisibleAnnotationsAttribute != null) { @@ -838,7 +840,7 @@ public class Disassembler extends ClassFileBytesDisassembler { } } } - + final boolean isAnnotation = (accessFlags & IModifierConstants.ACC_ANNOTATION) != 0; boolean isInterface = false; if (isEnum) { @@ -852,7 +854,7 @@ public class Disassembler extends ClassFileBytesDisassembler { buffer.append("interface "); //$NON-NLS-1$ isInterface = true; } - + if (checkMode(mode, WORKING_COPY)) { // we print the simple class name final int start = lastDotIndexInClassName + 1; @@ -864,7 +866,7 @@ public class Disassembler extends ClassFileBytesDisassembler { } else { buffer.append(className); } - + char[] superclassName = classFileReader.getSuperclassName(); if (superclassName != null) { CharOperation.replace(superclassName, '/', '.'); @@ -917,8 +919,17 @@ public class Disassembler extends ClassFileBytesDisassembler { if (signatureAttribute != null) { remainingAttributesLength--; } - if (innerClassesAttribute != null || enclosingMethodAttribute != null || remainingAttributesLength != 0) { - writeNewLine(buffer, lineSeparator, 0); + if (bootstrapMethods != null) { + remainingAttributesLength--; + } + if (innerClassesAttribute != null + || enclosingMethodAttribute != null + || bootstrapMethods != null + || remainingAttributesLength != 0) { + // this test is to ensure we don't insert more than one line separator + if (buffer.lastIndexOf(lineSeparator) != buffer.length() - lineSeparator.length()) { + writeNewLine(buffer, lineSeparator, 0); + } } if (innerClassesAttribute != null) { disassemble(innerClassesAttribute, buffer, lineSeparator, 1); @@ -926,6 +937,9 @@ public class Disassembler extends ClassFileBytesDisassembler { if (enclosingMethodAttribute != null) { disassemble(enclosingMethodAttribute, buffer, lineSeparator, 0); } + if (bootstrapMethods != null) { + disassemble((IBootstrapMethodsAttribute) bootstrapMethods, buffer, lineSeparator, 0); + } if (checkMode(mode, SYSTEM)) { if (runtimeVisibleAnnotationsAttribute != null) { disassemble((IRuntimeVisibleAnnotationsAttribute) runtimeVisibleAnnotationsAttribute, buffer, lineSeparator, 0, mode); @@ -937,13 +951,14 @@ public class Disassembler extends ClassFileBytesDisassembler { for (int i = 0; i < length; i++) { IClassFileAttribute attribute = attributes[i]; if (attribute != innerClassesAttribute - && attribute != sourceAttribute - && attribute != signatureAttribute - && attribute != enclosingMethodAttribute - && attribute != runtimeInvisibleAnnotationsAttribute - && attribute != runtimeVisibleAnnotationsAttribute - && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED) - && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC)) { + && attribute != sourceAttribute + && attribute != signatureAttribute + && attribute != enclosingMethodAttribute + && attribute != runtimeInvisibleAnnotationsAttribute + && attribute != runtimeVisibleAnnotationsAttribute + && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.DEPRECATED) + && !CharOperation.equals(attribute.getAttributeName(), IAttributeNamesConstants.SYNTHETIC) + && attribute != bootstrapMethods) { disassemble(attribute, buffer, lineSeparator, 0, mode); } } @@ -1408,9 +1423,73 @@ public class Disassembler extends ClassFileBytesDisassembler { Integer.toString(i), decodeStringValue(new String(constantPoolEntry.getUtf8Value()))})); break; + case IConstantPoolConstant.CONSTANT_MethodHandle : + IConstantPoolEntry2 entry2 = (IConstantPoolEntry2) constantPoolEntry; + buffer.append( + Messages.bind(Messages.disassembler_constantpool_methodhandle, + new String[] { + Integer.toString(i), + getReferenceKind(entry2.getReferenceKind()), + Integer.toString(entry2.getReferenceIndex()), + })); + break; + case IConstantPoolConstant.CONSTANT_MethodType : + entry2 = (IConstantPoolEntry2) constantPoolEntry; + buffer.append( + Messages.bind(Messages.disassembler_constantpool_methodtype, + new String[] { + Integer.toString(i), + Integer.toString(entry2.getDescriptorIndex()), + String.valueOf(entry2.getMethodDescriptor()), + })); + break; + case IConstantPoolConstant.CONSTANT_InvokeDynamic : + entry2 = (IConstantPoolEntry2) constantPoolEntry; + buffer.append( + Messages.bind(Messages.disassembler_constantpool_invokedynamic, + new String[] { + Integer.toString(i), + Integer.toString(entry2.getBootstrapMethodAttributeIndex()), + Integer.toString(entry2.getNameAndTypeIndex()), + new String(constantPoolEntry.getMethodName()), + new String(constantPoolEntry.getMethodDescriptor()) + })); } } } + + private String getReferenceKind(int referenceKind) { + String message = null; + switch(referenceKind) { + case IConstantPoolConstant.METHOD_TYPE_REF_GetField : + message = Messages.disassembler_method_type_ref_getfield; + break; + case IConstantPoolConstant.METHOD_TYPE_REF_GetStatic : + message = Messages.disassembler_method_type_ref_getstatic; + break; + case IConstantPoolConstant.METHOD_TYPE_REF_PutField : + message = Messages.disassembler_method_type_ref_putfield; + break; + case IConstantPoolConstant.METHOD_TYPE_REF_PutStatic : + message = Messages.disassembler_method_type_ref_putstatic; + break; + case IConstantPoolConstant.METHOD_TYPE_REF_InvokeInterface : + message = Messages.disassembler_method_type_ref_invokeinterface; + break; + case IConstantPoolConstant.METHOD_TYPE_REF_InvokeSpecial : + message = Messages.disassembler_method_type_ref_invokespecial; + break; + case IConstantPoolConstant.METHOD_TYPE_REF_InvokeStatic : + message = Messages.disassembler_method_type_ref_invokestatic; + break; + case IConstantPoolConstant.METHOD_TYPE_REF_InvokeVirtual : + message = Messages.disassembler_method_type_ref_invokevirtual; + break; + default : + message = Messages.disassembler_method_type_ref_newinvokespecial; + } + return Messages.bind(message, new String[] { Integer.toString(referenceKind) }); + } private void disassemble(IEnclosingMethodAttribute enclosingMethodAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) { writeNewLine(buffer, lineSeparator, tabNumber + 1); @@ -1669,6 +1748,46 @@ public class Disassembler extends ClassFileBytesDisassembler { } } + private void disassemble(IBootstrapMethodsAttribute bootstrapMethodsAttribute, StringBuffer buffer, String lineSeparator, int tabNumber) { + writeNewLine(buffer, lineSeparator, tabNumber); + buffer.append(Messages.disassembler_bootstrapmethodattributesheader); + writeNewLine(buffer, lineSeparator, tabNumber + 1); + IBootstrapMethodsEntry[] entries = bootstrapMethodsAttribute.getBootstrapMethods(); + int length = entries.length; + for (int i = 0; i < length; i++) { + if (i != 0) { + buffer.append(Messages.disassembler_comma); + writeNewLine(buffer, lineSeparator, tabNumber + 1); + } + IBootstrapMethodsEntry entry = entries[i]; + buffer.append( + Messages.bind( + Messages.disassembler_bootstrapmethodentry, + new String[] { + Integer.toString(i), + Integer.toString(entry.getBootstrapMethodReference()), + getArguments(entry.getBootstrapArguments()) + })); + } + } + + private String getArguments(int[] arguments) { + StringBuffer buffer = new StringBuffer(); + buffer.append('{'); + for (int i = 0, max = arguments.length; i < max; i++) { + if (i != 0) { + buffer.append(Messages.disassembler_comma); + } + buffer.append( + Messages.bind( + Messages.disassembler_bootstrapmethodentry_argument, + new String[] { + Integer.toString(arguments[i]), + })); + } + buffer.append('}'); + return String.valueOf(buffer); + } private void disassemble(int index, IParameterAnnotation parameterAnnotation, StringBuffer buffer, String lineSeparator, int tabNumber, int mode) { IAnnotation[] annotations = parameterAnnotation.getAnnotations(); writeNewLine(buffer, lineSeparator, tabNumber + 1); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java index 75ecbabdd..ff1cf8326 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java @@ -259,6 +259,9 @@ public final class Messages extends NLS { public static String disassembler_inner_accessflags; public static String disassembler_genericattributeheader; public static String disassembler_signatureattributeheader; + public static String disassembler_bootstrapmethodattributesheader; + public static String disassembler_bootstrapmethodentry; + public static String disassembler_bootstrapmethodentry_argument; public static String disassembler_indentation; public static String disassembler_constantpoolindex; public static String disassembler_space; @@ -278,6 +281,9 @@ public final class Messages extends NLS { public static String disassembler_constantpool_methodref; public static String disassembler_constantpool_name_and_type; public static String disassembler_constantpool_utf8; + public static String disassembler_constantpool_methodhandle; + public static String disassembler_constantpool_methodtype; + public static String disassembler_constantpool_invokedynamic; public static String disassembler_annotationdefaultheader; public static String disassembler_annotationdefaultvalue; public static String disassembler_annotationenumvalue; @@ -348,6 +354,16 @@ public final class Messages extends NLS { public static String disassembler_frame_same_frame; public static String disassembler_frame_same_locals_1_stack_item; public static String code_assist_internal_error; + + public static String disassembler_method_type_ref_getfield; + public static String disassembler_method_type_ref_putfield; + public static String disassembler_method_type_ref_getstatic; + public static String disassembler_method_type_ref_putstatic; + public static String disassembler_method_type_ref_invokestatic; + public static String disassembler_method_type_ref_invokevirtual; + public static String disassembler_method_type_ref_invokespecial; + public static String disassembler_method_type_ref_invokeinterface; + public static String disassembler_method_type_ref_newinvokespecial; static { NLS.initializeMessages(BUNDLE_NAME, Messages.class); diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties index e75e56ba7..5af88dbe8 100644 --- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties +++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties @@ -285,6 +285,9 @@ disassembler_genericattributeheader = Attribute: {0} Length: {1} disassembler_stackmaptableattributeheader = Stack map table: number of frames {0} disassembler_stackmapattributeheader = Stack map : number of frames {0} disassembler_signatureattributeheader = // Signature: {0} +disassembler_bootstrapmethodattributesheader = Bootstrap methods: +disassembler_bootstrapmethodentry = {0} : # {1} arguments: {2} +disassembler_bootstrapmethodentry_argument = #{0} disassembler_indentation = \ disassembler_constantpoolindex =\ # disassembler_space = \ @@ -304,6 +307,9 @@ disassembler_constantpool_interfacemethodref = constant #{0} interface_method_re disassembler_constantpool_methodref = constant #{0} method_ref: #{1}.#{2} {3}.{4} {5} disassembler_constantpool_name_and_type = constant #{0} name_and_type: #{1}.#{2} {3} {4} disassembler_constantpool_utf8 = constant #{0} utf8: "{1}" +disassembler_constantpool_methodhandle = constant #{0} method handle: {1} #{2} +disassembler_constantpool_methodtype = constant #{0} method type: #{1} {2} +disassembler_constantpool_invokedynamic = constant #{0} invoke dynamic: #{1} #{2} {3} {4} disassembler_annotationdefaultheader = Annotation Default:\ disassembler_annotationdefaultvalue= {0} (constant type) disassembler_annotationenumvalue = {2}.{3}(enum type #{0}.#{1}) @@ -323,6 +329,15 @@ disassembler_frame_same_locals_1_stack_item_extended=[pc: {0}, same_locals_1_sta disassembler_frame_chop=[pc: {0}, chop {1} local(s)] disassembler_frame_same_frame_extended=[pc: {0}, same_extended] disassembler_frame_append=[pc: {0}, append: {1}] +disassembler_method_type_ref_getfield = getfield ({0}) +disassembler_method_type_ref_putfield = putfield ({0}) +disassembler_method_type_ref_getstatic = getstatic ({0}) +disassembler_method_type_ref_putstatic = putstatic ({0}) +disassembler_method_type_ref_invokestatic = invokestatic ({0}) +disassembler_method_type_ref_invokevirtual = invokevirtual ({0}) +disassembler_method_type_ref_invokeinterface = invokeinterface ({0}) +disassembler_method_type_ref_invokespecial = invokespecial ({0}) +disassembler_method_type_ref_newinvokespecial = newinvokespecial ({0}) # {0} = offset delta # {1} = number of locals # {2} = locals @@ -358,7 +373,7 @@ classformat_new = {0} {2} [{1}] classformat_iinc = {0} {1} {2}{3} classformat_invokespecial ={0} {2} [{1}] classformat_invokeinterface ={0} {3} [{1}] [nargs: {2}] -classformat_invokedynamic={0} {2} [{1}] +classformat_invokedynamic={0} {2} {3} [{1}] classformat_invokestatic ={0} {2} [{1}] classformat_invokevirtual ={0} {2} [{1}] classformat_getfield ={0} {2}.{3} : {4} [{1}] diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java index 09e058bf3..753c785ed 100644 --- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java +++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MatchLocator.java @@ -1475,7 +1475,7 @@ protected void locatePackageDeclarations(SearchPattern searchPattern, SearchPart } //*/ protected IType lookupType(ReferenceBinding typeBinding) { - if (typeBinding == null) return null; + if (typeBinding == null || !typeBinding.isValidBinding()) return null; char[] packageName = typeBinding.qualifiedPackageName(); IPackageFragment[] pkgs = this.nameLookup.findPackageFragments( |