diff --git a/MODULE.bazel b/MODULE.bazel index 09f764b..051dabf 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -31,6 +31,7 @@ maven.install( "com.google.auto.value:auto-value-annotations:1.11.0", "com.google.code.findbugs:jsr305:3.0.2", "com.github.ben-manes.caffeine:caffeine:3.2.1", + "org.eclipse.jdt:ecj:3.42.0", # ASM (needed for coverage together with Jacoco) "org.ow2.asm:asm:9.7.1", "org.ow2.asm:asm-analysis:9.7.1", diff --git a/compiler/BUILD b/compiler/BUILD index 96d0b60..9c13a79 100644 --- a/compiler/BUILD +++ b/compiler/BUILD @@ -36,7 +36,6 @@ java_library( ], deps = [ "@bazel_org_jacoco_core//jar", - ":ecj", ":work_request_handlers", "//compiler/src/main/protobuf:deps_java_proto", "//compiler/src/main/protobuf:java_compilation_java_proto", @@ -46,23 +45,10 @@ java_library( "@maven//:com_github_ben_manes_caffeine_caffeine", "@maven//:com_google_guava_guava", "@maven//:com_google_code_findbugs_jsr305", + "@maven//:org_eclipse_jdt_ecj", ], plugins = [ java_plugin_artifact("com.google.auto.value:auto-value", "com.google.auto.value.processor.AutoValueProcessor"), ], ) -# Eclipse Java Compiler -java_library( - name = "ecj", - srcs = glob(["src/main/ecj/**/*.java"]), - javacopts = [ - "-nowarn", - "-XepDisableAllChecks", - ], - resource_strip_prefix = "compiler/src/main/ecj/", - resources = glob( - ["src/main/ecj/**"], - exclude = ["**/*.java"], - ), -) diff --git a/compiler/src/main/buildjar/com/google/devtools/build/buildjar/javac/BlazeEcjMain.java b/compiler/src/main/buildjar/com/google/devtools/build/buildjar/javac/BlazeEcjMain.java index 37bdf52..9bfb4c4 100644 --- a/compiler/src/main/buildjar/com/google/devtools/build/buildjar/javac/BlazeEcjMain.java +++ b/compiler/src/main/buildjar/com/google/devtools/build/buildjar/javac/BlazeEcjMain.java @@ -27,6 +27,7 @@ import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; +import java.net.URI; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; @@ -47,11 +48,11 @@ import org.eclipse.jdt.internal.compiler.ICompilerRequestor; import org.eclipse.jdt.internal.compiler.batch.ClasspathLocation; import org.eclipse.jdt.internal.compiler.batch.FileSystem; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; import org.eclipse.jdt.internal.compiler.batch.Main; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.env.IBinaryType; import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; @@ -170,7 +171,7 @@ public FileSystem getLibraryAccess() { // we use this to collect information about all used dependencies during // compilation FileSystem nameEnvironment = super.getLibraryAccess(); - nameEnvironment.nameEnvironmentListener = this::recordNameEnvironmentAnswer; + nameEnvironment.setNameEnvironmentAnswerListener(this::recordNameEnvironmentAnswer); return nameEnvironment; } @@ -214,18 +215,13 @@ protected void recordAnnotationProcessingAndPackageInfo(CompilationResult result processingModule.recordUnit(builder.build()); } - protected void recordNameEnvironmentAnswer(ClasspathAnswer classpathAnswer) { - Classpath classpath = classpathAnswer.source; - if (classpath instanceof ClasspathLocation) { - String jar = ((ClasspathLocation) classpath).getPath(); + protected void recordNameEnvironmentAnswer(NameEnvironmentAnswer answer) { + IBinaryType binaryType = answer.getBinaryType(); + if (binaryType != null) { + String jar = extractBinaryTypeJarPath(binaryType); if (jar != null && jar.endsWith(".jar")) { Path jarPath = Path.of(jar); if (processedJars.add(jarPath)) { - // we assume jars come from the execroot; JDT uses absolute/canonical paths - // therefore we translate the path back into an execroot relative path for Bazel - // to be happy - jarPath = sandboxPathPrefix.relativize(jarPath); - // update the dependency proto if (usedDependencyCollectionMode != UsedDependencyCollectionMode.None) { if (directJars.contains(jarPath)) { @@ -640,6 +636,37 @@ public static ClassLoader getPlatformClassLoader() { } } + /** + * Extract the jar file path from a binary type URI. The URI of a binary type is generally in this format: + *
+	 * jar:file://.jar!
+	 * 
+ * We only use URIs that start with "jar:file:///" and containing ".jar!", e.g.: + *
+	 * jar:file:///.../header_junit-jupiter-api-5.13.3.jar!/org/junit/jupiter/api/Test.class
+	 * 
+ * The URI format is coming from {@link org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader}, in particular see: + * + * + * @param binaryType a jar path is extracted from the URI of this binary type + * @return the path of the binary types jar or {@code null} if the URI didn't match the expected format + */ + private static String extractBinaryTypeJarPath(IBinaryType binaryType) { + URI binaryTypeUri = binaryType.getURI(); + String uri= binaryTypeUri.toString(); + String prefix = "jar:file:///"; + String suffix = ".jar!"; + int index = uri.indexOf(".jar!"); + String jar = null; + if (uri.startsWith(prefix) && index != -1) { + jar = uri.substring(prefix.length(), index + suffix.length() - 1); + } + return jar; + } + private BlazeEcjMain() { } -} \ No newline at end of file +} diff --git a/compiler/src/main/ecj/META-INF/services/javax.tools.JavaCompiler b/compiler/src/main/ecj/META-INF/services/javax.tools.JavaCompiler deleted file mode 100644 index 7fb91cf..0000000 --- a/compiler/src/main/ecj/META-INF/services/javax.tools.JavaCompiler +++ /dev/null @@ -1 +0,0 @@ -org.eclipse.jdt.internal.compiler.tool.EclipseCompiler #Eclipse compiler \ No newline at end of file diff --git a/compiler/src/main/ecj/README.md b/compiler/src/main/ecj/README.md deleted file mode 100644 index e44d364..0000000 --- a/compiler/src/main/ecj/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Eclipse Java Compiler - -We are using a patched version of ECJ 4.31 RC1 to incorporate fixes for: - -* None at this time - -As well as additional modification to support: - -* Collection of used dependencies during compilation (`FileSystem.nameEnvironmentListener`, see commit history) - - -## Updating - -1. Download `ecjsrc-4.??.jar` ECJ source code from https://download.eclipse.org/eclipse/downloads/ -2. Extract `org` folder from source jar into this directory. - Do a proper diff, i.e. delete files no longer part of ECJ! -3. Delete Ant compile adapter (not needed) -4. Re-apply patches listed above. -5. Test and ship diff --git a/compiler/src/main/ecj/about.html b/compiler/src/main/ecj/about.html deleted file mode 100644 index 164f781..0000000 --- a/compiler/src/main/ecj/about.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - -About - - -

About This Content

- -

November 30, 2017

-

License

- -

- The Eclipse Foundation makes available all content in this plug-in - ("Content"). Unless otherwise indicated below, the Content - is provided to you under the terms and conditions of the Eclipse - Public License Version 2.0 ("EPL"). A copy of the EPL is - available at http://www.eclipse.org/legal/epl-2.0. - For purposes of the EPL, "Program" will mean the Content. -

- -

- If you did not receive this Content directly from the Eclipse - Foundation, the Content is being redistributed by another party - ("Redistributor") and different terms and conditions may - apply to your use of any object code in the Content. Check the - Redistributor's license that was provided with the Content. If no such - license exists, contact the Redistributor. Unless otherwise indicated - below, the terms and conditions of the EPL still apply to any source - code in the Content and such source code may be obtained at http://www.eclipse.org. -

- - - \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/CategorizedProblem.java b/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/CategorizedProblem.java deleted file mode 100644 index 425a8e2..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/CategorizedProblem.java +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.core.compiler; - -import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; - -/** - * Richer description of a Java problem, as detected by the compiler or some of the underlying - * technology reusing the compiler. With the introduction of org.eclipse.jdt.core.compiler.CompilationParticipant, - * the simpler problem interface {@link IProblem} did not carry enough information to better - * separate and categorize Java problems. In order to minimize impact on existing API, Java problems - * are still passed around as {@link IProblem}, though actual implementations should explicitly - * extend {@link CategorizedProblem}. Participants can produce their own problem definitions, - * and given these are categorized problems, they can be better handled by clients (such as user - * interface). - *

- * A categorized problem provides access to: - *

- *

- * Note: the compiler produces IProblems internally, which are turned into markers by the JavaBuilder - * so as to persist problem descriptions. This explains why there is no API allowing to reach IProblem detected - * when compiling. However, the Java problem markers carry equivalent information to IProblem, in particular - * their ID (attribute "id") is set to one of the IDs defined on this interface. - *

- * Note: Standard Java problems produced by Java default tooling will be subclasses of this class. Technically, most - * API methods dealing with problems are referring to {@link IProblem} for backward compatibility reason. - * It is intended that {@link CategorizedProblem} will be subclassed for custom problem implementation when - * participating in compilation operations, so as to allow participant to contribute their own marker types, and thus - * defining their own domain specific problem/category IDs. - *

- * Note: standard Java problems produced by Java default tooling will set the marker - * IMarker#SOURCE_ID attribute to - * JavaBuilder#SOURCE_ID; compiler - * participants may specify the IMarker#SOURCE_ID - * attribute of their markers by adding it to the extra marker attributes of the problems they generate; - * markers resulting from compiler participants' problems that do not have the - * IMarker#SOURCE_ID extra attribute set do not have the - * JavaBuilder#SOURCE_ID attribute set either. - * - * @since 3.2 - */ -public abstract class CategorizedProblem implements IProblem { - - /** - * List of standard category IDs used by Java problems, more categories will be added - * in the future. - */ - public static final int CAT_UNSPECIFIED = 0; - /** Category for problems related to buildpath */ - public static final int CAT_BUILDPATH = 10; - /** Category for fatal problems related to syntax */ - public static final int CAT_SYNTAX = 20; - /** Category for fatal problems in import statements */ - public static final int CAT_IMPORT = 30; - /** Category for fatal problems related to types, could be addressed by some type change */ - public static final int CAT_TYPE = 40; - /** Category for fatal problems related to type members, could be addressed by some field or method change */ - public static final int CAT_MEMBER = 50; - /** Category for fatal problems which could not be addressed by external changes, but require an edit to be addressed */ - public static final int CAT_INTERNAL = 60; - /** Category for optional problems in Javadoc */ - public static final int CAT_JAVADOC = 70; - /** Category for optional problems related to coding style practices */ - public static final int CAT_CODE_STYLE = 80; - /** Category for optional problems related to potential programming flaws */ - public static final int CAT_POTENTIAL_PROGRAMMING_PROBLEM = 90; - /** Category for optional problems related to naming conflicts */ - public static final int CAT_NAME_SHADOWING_CONFLICT = 100; - /** Category for optional problems related to deprecation */ - public static final int CAT_DEPRECATION = 110; - /** Category for optional problems related to unnecessary code */ - public static final int CAT_UNNECESSARY_CODE = 120; - /** Category for optional problems related to type safety in generics */ - public static final int CAT_UNCHECKED_RAW = 130; - /** Category for optional problems related to internationalization of String literals */ - public static final int CAT_NLS = 140; - /** Category for optional problems related to access restrictions */ - public static final int CAT_RESTRICTION = 150; - /** - * Category for fatal problems relating to modules - * @since 3.14 - */ - public static final int CAT_MODULE = 160; - /** - * @since 3.18 - */ - public static final int CAT_COMPLIANCE = 170; - /** Category for problems related to preview features - * @since 3.20*/ - public static final int CAT_PREVIEW_RELATED = 180; - -/** - * Returns an integer identifying the category of this problem. Categories, like problem IDs are - * defined in the context of some marker type. Custom implementations of {@link CategorizedProblem} - * may choose arbitrary values for problem/category IDs, as long as they are associated with a different - * marker type. - * Standard Java problem markers (i.e. marker type is "org.eclipse.jdt.core.problem") carry an - * attribute "categoryId" persisting the originating problem category ID as defined by this method). - * @return id - an integer identifying the category of this problem - */ -public abstract int getCategoryID(); - -/** - * Returns the marker type associated to this problem, if it gets persisted into a marker by the JavaBuilder - * Standard Java problems are associated to marker type "org.eclipse.jdt.core.problem"). - * Note: problem markers are expected to extend "org.eclipse.core.resources.problemmarker" marker type. - * @return the type of the marker which would be associated to the problem - */ -public abstract String getMarkerType(); - -/** - * Returns the names of the extra marker attributes associated to this problem when persisted into a marker - * by the JavaBuilder. Extra attributes are only optional, and are allowing client customization of generated - * markers. By default, no EXTRA attributes is persisted, and a categorized problem only persists the following attributes: - *

- * The names must be eligible for marker creation, as defined by IMarker#setAttributes(String[], Object[]), - * and there must be as many names as values according to {@link #getExtraMarkerAttributeValues()}. - * Note that extra marker attributes will be inserted after default ones (as described in {@link CategorizedProblem#getMarkerType()}, - * and thus could be used to override defaults. - * @return the names of the corresponding marker attributes - */ -public String[] getExtraMarkerAttributeNames() { - return CharOperation.NO_STRINGS; -} - -/** - * Returns the respective values for the extra marker attributes associated to this problem when persisted into - * a marker by the JavaBuilder. Each value must correspond to a matching attribute name, as defined by - * {@link #getExtraMarkerAttributeNames()}. - * The values must be eligible for marker creation, as defined by IMarker#setAttributes(String[], Object[])}. - * @return the values of the corresponding extra marker attributes - */ -public Object[] getExtraMarkerAttributeValues() { - return DefaultProblem.EMPTY_VALUES; -} -/** - * {@inheritDoc} - *

Note: This implementation always returns false, subclasses can override.

- * - * @since 3.12 - */ -@Override -public boolean isInfo() { - return false; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/CharOperation.java b/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/CharOperation.java deleted file mode 100644 index 02df6a0..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/CharOperation.java +++ /dev/null @@ -1,4400 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Luiz-Otavio Zorzella - Improve CamelCase algorithm - * Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions - * Stefan Xenos (Google) - Bug 501283 - Lots of hash collisions during indexing - *******************************************************************************/ -package org.eclipse.jdt.core.compiler; - -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; - -/** - * This class is a collection of helper methods to manipulate char arrays. - * - * @since 2.1 - * @noinstantiate This class is not intended to be instantiated by clients. - */ -public final class CharOperation { - - /** - * Constant for an empty char array - */ - public static final char[] NO_CHAR = new char[0]; - - /** - * Constant for an empty char array with two dimensions. - */ - public static final char[][] NO_CHAR_CHAR = new char[0][]; - - /** - * Constant for an empty String array. - * @since 3.1 - */ - public static final String[] NO_STRINGS = new String[0]; - - /** - * Constant for all Prefix - * @since 3.14 - */ - public static final char[] ALL_PREFIX = new char[] {'*'}; - - /** - * Constant for comma - * @since 3.14 - */ - public static final char[] COMMA_SEPARATOR = new char[] {','}; - - private static final int[] EMPTY_REGIONS = new int[0]; - -/** - * Answers a new array with appending the suffix character at the end of the array. - *
- *
- * For example:
- *
    - *
  1. - *    array = { 'a', 'b' }
    - *    suffix = 'c'
    - *    => result = { 'a', 'b' , 'c' }
    - * 
    - *
  2. - *
  3. - *    array = null
    - *    suffix = 'c'
    - *    => result = { 'c' }
    - * 
  4. - *
- * - * @param array the array that is concatenated with the suffix character - * @param suffix the suffix character - * @return the new array - */ -public static final char[] append(char[] array, char suffix) { - if (array == null) - return new char[] { suffix }; - int length = array.length; - System.arraycopy(array, 0, array = new char[length + 1], 0, length); - array[length] = suffix; - return array; -} - -/** - * Answers a new array with appending the sub-array at the end of the array. - *
- *
- * For example:
- *
    - *
  1. - *    array = { 'a', 'b' }
    - *    suffix = { 'c', 'd' }
    - *    => result = { 'a', 'b' , 'c' , d' }
    - * 
    - *
  2. - *
  3. - *    array = null
    - *    suffix = { 'c' }
    - *    => result = { 'c' }
    - * 
  4. - *
- * - * @param target the array that is concatenated with the suffix array. - * @param suffix the array that will be concatenated to the target - * @return the new array - * @throws NullPointerException if the target array is null - * @since 3.11 - */ -public static final char[] append(char[] target, char[] suffix) { - if(suffix == null || suffix.length == 0) - return target; - int targetLength = target.length; - int subLength = suffix.length; - int newTargetLength = targetLength + subLength; - if (newTargetLength > targetLength) { - System.arraycopy(target, 0, target = new char[newTargetLength], 0, targetLength); - } - System.arraycopy(suffix, 0, target, targetLength, subLength); - return target; -} - -/** - * Append the given sub-array to the target array starting at the given index in the target array. - * The start of the sub-array is inclusive, the end is exclusive. - * Answers a new target array if it needs to grow, otherwise answers the same target array. - *
- * For example:
- *
    - *
  1. - *    target = { 'a', 'b', '0' }
    - *    index = 2
    - *    array = { 'c', 'd' }
    - *    start = 0
    - *    end = 1
    - *    => result = { 'a', 'b' , 'c' }
    - * 
    - *
  2. - *
  3. - *    target = { 'a', 'b' }
    - *    index = 2
    - *    array = { 'c', 'd' }
    - *    start = 0
    - *    end = 1
    - *    => result = { 'a', 'b' , 'c', '0', '0' , '0' } (new array)
    - * 
  4. - *
  5. - *    target = { 'a', 'b', 'c' }
    - *    index = 1
    - *    array = { 'c', 'd', 'e', 'f' }
    - *    start = 1
    - *    end = 4
    - *    => result = { 'a', 'd' , 'e', 'f', '0', '0', '0', '0' } (new array)
    - * 
  6. - *
- * - * @param target the given target - * @param index the given index - * @param array the given array - * @param start the given start index - * @param end the given end index - * - * @return the new array - * @throws NullPointerException if the target array is null - */ -public static final char[] append(char[] target, int index, char[] array, int start, int end) { - int targetLength = target.length; - int subLength = end-start; - int newTargetLength = subLength+index; - if (newTargetLength > targetLength) { - System.arraycopy(target, 0, target = new char[newTargetLength*2], 0, index); - } - System.arraycopy(array, start, target, index, subLength); - return target; -} - -/** - * Answers a new array with prepending the prefix character at the start of the array. - *
- *
- * For example:
- *
    - *
  1. - *    prefix = 'c'
    - *    array = { 'a', 'b' }
    - *    => result = { 'c' , 'a', 'b' }
    - * 
    - *
  2. - *
  3. - *    prefix = 'c'
    - *    array = null
    - *    => result = { 'c' }
    - * 
  4. - *
- * - * @param array the array that is concatenated with the prefix character - * @param prefix the prefix character - * @return the new array - * @since 3.14 - */ -public static final char[] prepend(char prefix, char[] array) { - if (array == null) - return new char[] { prefix }; - int length = array.length; - System.arraycopy(array, 0, array = new char[length + 1], 1, length); - array[0] = prefix; - return array; -} - -/** - * Answers the concatenation of the two arrays. It answers null if the two arrays are null. - * If the first array is null, then the second array is returned. - * If the second array is null, then the first array is returned. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = null
    - *    => result = null
    - * 
    - *
  2. - *
  3. - *    first = { { ' a' } }
    - *    second = null
    - *    => result = { { ' a' } }
    - * 
    - *
  4. - *
  5. - *    first = null
    - *    second = { { ' a' } }
    - *    => result = { { ' a' } }
    - * 
    - *
  6. - *
  7. - *    first = { { ' b' } }
    - *    second = { { ' a' } }
    - *    => result = { { ' b' }, { ' a' } }
    - * 
    - *
  8. - *
- * - * @param first the first array to concatenate - * @param second the second array to concatenate - * @return the concatenation of the two arrays, or null if the two arrays are null. - */ -public static final char[][] arrayConcat(char[][] first, char[][] second) { - if (first == null) - return second; - if (second == null) - return first; - - int length1 = first.length; - int length2 = second.length; - char[][] result = new char[length1 + length2][]; - System.arraycopy(first, 0, result, 0, length1); - System.arraycopy(second, 0, result, length1, length2); - return result; -} - -/** - * Answers true if the pattern matches the given name using CamelCase rules, or - * false otherwise. char[] CamelCase matching does NOT accept explicit wild-cards - * '*' and '?' and is inherently case sensitive. - *

- * CamelCase denotes the convention of writing compound names without spaces, - * and capitalizing every term. This function recognizes both upper and lower - * CamelCase, depending whether the leading character is capitalized or not. - * The leading part of an upper CamelCase pattern is assumed to contain a - * sequence of capitals which are appearing in the matching name; e.g. 'NPE' will - * match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern - * uses a lowercase first character. In Java, type names follow the upper - * CamelCase convention, whereas method or field names follow the lower - * CamelCase convention. - *

- * The pattern may contain lowercase characters, which will be matched in a case - * sensitive way. These characters must appear in sequence in the name. - * For instance, 'NPExcep' will match 'NullPointerException', but not - * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but not - * 'NoPointerException'. - *

- * Digit characters are treated in a special way. They can be used in the pattern - * but are not always considered as leading character. For instance, both - * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'. - *

- * Using this method allows matching names to have more parts than the specified - * pattern (see {@link #camelCaseMatch(char[], char[], boolean)}).
- * For instance, 'HM' , 'HaMa' and 'HMap' patterns will match 'HashMap', - * 'HatMapper' and also 'HashMapEntry'. - *

- * Examples: - *

    - *
  1. pattern = "NPE".toCharArray() - * name = "NullPointerException".toCharArray() - * result => true
  2. - *
  3. pattern = "NPE".toCharArray() - * name = "NoPermissionException".toCharArray() - * result => true
  4. - *
  5. pattern = "NuPoEx".toCharArray() - * name = "NullPointerException".toCharArray() - * result => true
  6. - *
  7. pattern = "NuPoEx".toCharArray() - * name = "NoPermissionException".toCharArray() - * result => false
  8. - *
  9. pattern = "npe".toCharArray() - * name = "NullPointerException".toCharArray() - * result => false
  10. - *
  11. pattern = "IPL3".toCharArray() - * name = "IPerspectiveListener3".toCharArray() - * result => true
  12. - *
  13. pattern = "HM".toCharArray() - * name = "HashMapEntry".toCharArray() - * result => true
  14. - *
- * - * @param pattern the given pattern - * @param name the given name - * @return true if the pattern matches the given name, false otherwise - * @since 3.2 - */ -public static final boolean camelCaseMatch(char[] pattern, char[] name) { - if (pattern == null) - return true; // null pattern is equivalent to '*' - if (name == null) - return false; // null name cannot match - - return camelCaseMatch(pattern, 0, pattern.length, name, 0, name.length, false/*not the same count of parts*/); -} - -/** - * Answers true if the pattern matches the given name using CamelCase rules, or - * false otherwise. char[] CamelCase matching does NOT accept explicit wild-cards - * '*' and '?' and is inherently case sensitive. - *

- * CamelCase denotes the convention of writing compound names without spaces, - * and capitalizing every term. This function recognizes both upper and lower - * CamelCase, depending whether the leading character is capitalized or not. - * The leading part of an upper CamelCase pattern is assumed to contain a - * sequence of capitals which are appearing in the matching name; e.g. 'NPE' will - * match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern - * uses a lowercase first character. In Java, type names follow the upper - * CamelCase convention, whereas method or field names follow the lower - * CamelCase convention. - *

- * The pattern may contain lowercase characters, which will be matched in a case - * sensitive way. These characters must appear in sequence in the name. - * For instance, 'NPExcep' will match 'NullPointerException', but not - * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but not - * 'NoPointerException'. - *

- * Digit characters are treated in a special way. They can be used in the pattern - * but are not always considered as leading character. For instance, both - * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'. - *

- * CamelCase can be restricted to match only the same count of parts. When this - * restriction is specified the given pattern and the given name must have exactly - * the same number of parts (i.e. the same number of uppercase characters).
- * For instance, 'HM' , 'HaMa' and 'HMap' patterns will match 'HashMap' and - * 'HatMapper' but not 'HashMapEntry'. - *

- * Examples:

    - *
  1. pattern = "NPE".toCharArray() - * name = "NullPointerException".toCharArray() - * result => true
  2. - *
  3. pattern = "NPE".toCharArray() - * name = "NoPermissionException".toCharArray() - * result => true
  4. - *
  5. pattern = "NuPoEx".toCharArray() - * name = "NullPointerException".toCharArray() - * result => true
  6. - *
  7. pattern = "NuPoEx".toCharArray() - * name = "NoPermissionException".toCharArray() - * result => false
  8. - *
  9. pattern = "npe".toCharArray() - * name = "NullPointerException".toCharArray() - * result => false
  10. - *
  11. pattern = "IPL3".toCharArray() - * name = "IPerspectiveListener3".toCharArray() - * result => true
  12. - *
  13. pattern = "HM".toCharArray() - * name = "HashMapEntry".toCharArray() - * result => (samePartCount == false)
  14. - *
- * - * @param pattern the given pattern - * @param name the given name - * @param samePartCount flag telling whether the pattern and the name should - * have the same count of parts or not.
- *   For example: - * - * @return true if the pattern matches the given name, false otherwise - * @since 3.4 - */ -public static final boolean camelCaseMatch(char[] pattern, char[] name, boolean samePartCount) { - if (pattern == null) - return true; // null pattern is equivalent to '*' - if (name == null) - return false; // null name cannot match - - return camelCaseMatch(pattern, 0, pattern.length, name, 0, name.length, samePartCount); -} - -/** - * Answers true if a sub-pattern matches the sub-part of the given name using - * CamelCase rules, or false otherwise. char[] CamelCase matching does NOT - * accept explicit wild-cards '*' and '?' and is inherently case sensitive. - * Can match only subset of name/pattern, considering end positions as non-inclusive. - * The sub-pattern is defined by the patternStart and patternEnd positions. - *

- * CamelCase denotes the convention of writing compound names without spaces, - * and capitalizing every term. This function recognizes both upper and lower - * CamelCase, depending whether the leading character is capitalized or not. - * The leading part of an upper CamelCase pattern is assumed to contain a - * sequence of capitals which are appearing in the matching name; e.g. 'NPE' will - * match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern - * uses a lowercase first character. In Java, type names follow the upper - * CamelCase convention, whereas method or field names follow the lower - * CamelCase convention. - *

- * The pattern may contain lowercase characters, which will be matched in a case - * sensitive way. These characters must appear in sequence in the name. - * For instance, 'NPExcep' will match 'NullPointerException', but not - * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but not - * 'NoPointerException'. - *

- * Digit characters are treated in a special way. They can be used in the pattern - * but are not always considered as leading character. For instance, both - * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'. - *

- * Digit characters are treated in a special way. They can be used in the pattern - * but are not always considered as leading character. For instance, both - * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'. - *

- * Using this method allows matching names to have more parts than the specified - * pattern (see {@link #camelCaseMatch(char[], int, int, char[], int, int, boolean)}).
- * For instance, 'HM' , 'HaMa' and 'HMap' patterns will match 'HashMap', - * 'HatMapper' and also 'HashMapEntry'. - *

- * Examples: - *

    - *
  1. pattern = "NPE".toCharArray() - * patternStart = 0 - * patternEnd = 3 - * name = "NullPointerException".toCharArray() - * nameStart = 0 - * nameEnd = 20 - * result => true
  2. - *
  3. pattern = "NPE".toCharArray() - * patternStart = 0 - * patternEnd = 3 - * name = "NoPermissionException".toCharArray() - * nameStart = 0 - * nameEnd = 21 - * result => true
  4. - *
  5. pattern = "NuPoEx".toCharArray() - * patternStart = 0 - * patternEnd = 6 - * name = "NullPointerException".toCharArray() - * nameStart = 0 - * nameEnd = 20 - * result => true
  6. - *
  7. pattern = "NuPoEx".toCharArray() - * patternStart = 0 - * patternEnd = 6 - * name = "NoPermissionException".toCharArray() - * nameStart = 0 - * nameEnd = 21 - * result => false
  8. - *
  9. pattern = "npe".toCharArray() - * patternStart = 0 - * patternEnd = 3 - * name = "NullPointerException".toCharArray() - * nameStart = 0 - * nameEnd = 20 - * result => false
  10. - *
  11. pattern = "IPL3".toCharArray() - * patternStart = 0 - * patternEnd = 4 - * name = "IPerspectiveListener3".toCharArray() - * nameStart = 0 - * nameEnd = 21 - * result => true
  12. - *
  13. pattern = "HM".toCharArray() - * patternStart = 0 - * patternEnd = 2 - * name = "HashMapEntry".toCharArray() - * nameStart = 0 - * nameEnd = 12 - * result => true
  14. - *
- * - * @param pattern the given pattern - * @param patternStart the start index of the pattern, inclusive - * @param patternEnd the end index of the pattern, exclusive - * @param name the given name - * @param nameStart the start index of the name, inclusive - * @param nameEnd the end index of the name, exclusive - * @return true if a sub-pattern matches the sub-part of the given name, false otherwise - * @since 3.2 - */ -public static final boolean camelCaseMatch(char[] pattern, int patternStart, int patternEnd, char[] name, int nameStart, int nameEnd) { - return camelCaseMatch(pattern, patternStart, patternEnd, name, nameStart, nameEnd, false/*not the same count of parts*/); -} - -/** - * Answers true if a sub-pattern matches the sub-part of the given name using - * CamelCase rules, or false otherwise. char[] CamelCase matching does NOT - * accept explicit wild-cards '*' and '?' and is inherently case sensitive. - * Can match only subset of name/pattern, considering end positions as - * non-inclusive. The sub-pattern is defined by the patternStart and patternEnd - * positions. - *

- * CamelCase denotes the convention of writing compound names without spaces, - * and capitalizing every term. This function recognizes both upper and lower - * CamelCase, depending whether the leading character is capitalized or not. - * The leading part of an upper CamelCase pattern is assumed to contain - * a sequence of capitals which are appearing in the matching name; e.g. 'NPE' will - * match 'NullPointerException', but not 'NewPerfData'. A lower CamelCase pattern - * uses a lowercase first character. In Java, type names follow the upper - * CamelCase convention, whereas method or field names follow the lower - * CamelCase convention. - *

- * The pattern may contain lowercase characters, which will be matched in a case - * sensitive way. These characters must appear in sequence in the name. - * For instance, 'NPExcep' will match 'NullPointerException', but not - * 'NullPointerExCEPTION' or 'NuPoEx' will match 'NullPointerException', but not - * 'NoPointerException'. - *

- * Digit characters are treated in a special way. They can be used in the pattern - * but are not always considered as leading character. For instance, both - * 'UTF16DSS' and 'UTFDSS' patterns will match 'UTF16DocumentScannerSupport'. - *

- * CamelCase can be restricted to match only the same count of parts. When this - * restriction is specified the given pattern and the given name must have exactly - * the same number of parts (i.e. the same number of uppercase characters).
- * For instance, 'HM' , 'HaMa' and 'HMap' patterns will match 'HashMap' and - * 'HatMapper' but not 'HashMapEntry'. - *

- * Examples: - *

    - *
  1. pattern = "NPE".toCharArray() - * patternStart = 0 - * patternEnd = 3 - * name = "NullPointerException".toCharArray() - * nameStart = 0 - * nameEnd = 20 - * result => true
  2. - *
  3. pattern = "NPE".toCharArray() - * patternStart = 0 - * patternEnd = 3 - * name = "NoPermissionException".toCharArray() - * nameStart = 0 - * nameEnd = 21 - * result => true
  4. - *
  5. pattern = "NuPoEx".toCharArray() - * patternStart = 0 - * patternEnd = 6 - * name = "NullPointerException".toCharArray() - * nameStart = 0 - * nameEnd = 20 - * result => true
  6. - *
  7. pattern = "NuPoEx".toCharArray() - * patternStart = 0 - * patternEnd = 6 - * name = "NoPermissionException".toCharArray() - * nameStart = 0 - * nameEnd = 21 - * result => false
  8. - *
  9. pattern = "npe".toCharArray() - * patternStart = 0 - * patternEnd = 3 - * name = "NullPointerException".toCharArray() - * nameStart = 0 - * nameEnd = 20 - * result => false
  10. - *
  11. pattern = "IPL3".toCharArray() - * patternStart = 0 - * patternEnd = 4 - * name = "IPerspectiveListener3".toCharArray() - * nameStart = 0 - * nameEnd = 21 - * result => true
  12. - *
  13. pattern = "HM".toCharArray() - * patternStart = 0 - * patternEnd = 2 - * name = "HashMapEntry".toCharArray() - * nameStart = 0 - * nameEnd = 12 - * result => (samePartCount == false)
  14. - *
- * - * @param pattern the given pattern - * @param patternStart the start index of the pattern, inclusive - * @param patternEnd the end index of the pattern, exclusive - * @param name the given name - * @param nameStart the start index of the name, inclusive - * @param nameEnd the end index of the name, exclusive - * @param samePartCount flag telling whether the pattern and the name should - * have the same count of parts or not.
- *   For example: - * - * @return true if a sub-pattern matches the sub-part of the given name, false otherwise - * @since 3.4 - */ -public static final boolean camelCaseMatch(char[] pattern, int patternStart, int patternEnd, char[] name, int nameStart, int nameEnd, boolean samePartCount) { - - /* !!!!!!!!!! WARNING !!!!!!!!!! - * The algorithm implemented in this method has been heavily used in - * StringOperation#getCamelCaseMatchingRegions(String, int, int, String, int, int, boolean) - * method. - * - * So, if any change needs to be applied in the current algorithm, - * do NOT forget to also apply the same change in the StringOperation method! - */ - - if (name == null) - return false; // null name cannot match - if (pattern == null) - return true; // null pattern is equivalent to '*' - if (patternEnd < 0) patternEnd = pattern.length; - if (nameEnd < 0) nameEnd = name.length; - - if (patternEnd <= patternStart) return nameEnd <= nameStart; - if (nameEnd <= nameStart) return false; - // check first pattern char - if (name[nameStart] != pattern[patternStart]) { - // first char must strictly match (upper/lower) - return false; - } - - char patternChar, nameChar; - int iPattern = patternStart; - int iName = nameStart; - - // Main loop is on pattern characters - while (true) { - - iPattern++; - iName++; - - if (iPattern == patternEnd) { // we have exhausted pattern... - // it's a match if the name can have additional parts (i.e. uppercase characters) or is also exhausted - if (!samePartCount || iName == nameEnd) return true; - - // otherwise it's a match only if the name has no more uppercase characters - while (true) { - if (iName == nameEnd) { - // we have exhausted the name, so it's a match - return true; - } - nameChar = name[iName]; - // test if the name character is uppercase - if (nameChar < ScannerHelper.MAX_OBVIOUS) { - if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[nameChar] & ScannerHelper.C_UPPER_LETTER) != 0) { - return false; - } - } - else if (!Character.isJavaIdentifierPart(nameChar) || Character.isUpperCase(nameChar)) { - return false; - } - iName++; - } - } - - if (iName == nameEnd){ - // We have exhausted the name (and not the pattern), so it's not a match - return false; - } - - // For as long as we're exactly matching, bring it on (even if it's a lower case character) - if ((patternChar = pattern[iPattern]) == name[iName]) { - continue; - } - - // If characters are not equals, then it's not a match if patternChar is lowercase - if (patternChar < ScannerHelper.MAX_OBVIOUS) { - if ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[patternChar] & (ScannerHelper.C_UPPER_LETTER | ScannerHelper.C_DIGIT)) == 0) { - return false; - } - } - else if (Character.isJavaIdentifierPart(patternChar) && !Character.isUpperCase(patternChar) && !Character.isDigit(patternChar)) { - return false; - } - - // patternChar is uppercase, so let's find the next uppercase in name - while (true) { - if (iName == nameEnd){ - // We have exhausted name (and not pattern), so it's not a match - return false; - } - - nameChar = name[iName]; - if (nameChar < ScannerHelper.MAX_OBVIOUS) { - int charNature = ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[nameChar]; - if ((charNature & (ScannerHelper.C_LOWER_LETTER | ScannerHelper.C_SPECIAL)) != 0) { - // nameChar is lowercase - iName++; - } else if ((charNature & ScannerHelper.C_DIGIT) != 0) { - // nameChar is digit => break if the digit is current pattern character otherwise consume it - if (patternChar == nameChar) break; - iName++; - // nameChar is uppercase... - } else if (patternChar != nameChar) { - //.. and it does not match patternChar, so it's not a match - return false; - } else { - //.. and it matched patternChar. Back to the big loop - break; - } - } - // Same tests for non-obvious characters - else if (Character.isJavaIdentifierPart(nameChar) && !Character.isUpperCase(nameChar)) { - iName++; - } else if (Character.isDigit(nameChar)) { - if (patternChar == nameChar) break; - iName++; - } else if (patternChar != nameChar) { - return false; - } else { - break; - } - } - // At this point, either name has been exhausted, or it is at an uppercase letter. - // Since pattern is also at an uppercase letter - } -} - -/** - * Answers true if the characters of the pattern are contained in the - * name as a subword, in a case-insensitive way. - * - * @param pattern the given pattern - * @param name the given name - * @return true if the pattern matches the given name, false otherwise - * @since 3.21 - */ -public static final boolean subWordMatch(char[] pattern, char[] name) { - if (name == null) - return false; // null name cannot match - if (pattern == null) - return true; // null pattern is equivalent to '*' - - int[] matchingRegions = getSubWordMatchingRegions(new String(pattern), new String(name)); - return matchingRegions != null; -} - -/** - * Answers all the regions in a given name matching a subword pattern. - *

- * Each of these regions is made of its starting index and its length in the given - * name. They are all concatenated in a single array of int - * which therefore always has an even length. - *

- * Note that each region is disjointed from the following one.
- * E.g. if the regions are { start1, length1, start2, length2 }, - * then start1+length1 will always be smaller than - * start2. - *

- * Examples: - *

    - *
  1. - *    pattern = "linkedmap"
    - *    name = LinkedHashMap
    - *    result:  { 0, 6, 10, 3 }
    - * 
  2. - *
- * - * @see CharOperation#subWordMatch(char[], char[]) - * for more details on the subword behavior - * - * @param pattern the given pattern - * @param name the given name - * @return an array of int having two slots per returned - * regions (first one is the starting index of the region and the second - * one the length of the region).
- * Note that it may be null if the given name does not match - * the pattern - * @since 3.21 - */ -public static final int[] getSubWordMatchingRegions(String pattern, String name) { - - if (name == null) - return null; // null name cannot match - if (pattern == null) { - // null pattern cannot match any region - // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=264816 - return EMPTY_REGIONS; - } - - return new SubwordMatcher(name).getMatchingRegions(pattern); -} - -/** - * Answers true if the characters of the pattern are contained in the - * name as a substring, in a case-insensitive way. - * - * @param pattern the given pattern - * @param name the given name - * @return true if the pattern matches the given name, false otherwise - * @since 3.12 - */ -public static final boolean substringMatch(String pattern, String name) { - if (pattern == null || pattern.length() == 0) { - return true; - } - if (name == null) { - return false; - } - return checkSubstringMatch(pattern.toCharArray(), name.toCharArray()); -} - -/** - * Answers true if the characters of the pattern are contained in the - * name as a substring, in a case-insensitive way. - * - * @param pattern the given pattern - * @param name the given name - * @return true if the pattern matches the given name, false otherwise - * @since 3.12 - */ -public static final boolean substringMatch(char[] pattern, char[] name) { - if (pattern == null || pattern.length == 0) { - return true; - } - if (name == null) { - return false; - } - return checkSubstringMatch(pattern, name); -} - -/** - * Internal substring matching method; called after the null and length - * checks are performed. - * - * @param pattern the given pattern - * @param name the given name - * @return true if the pattern matches the given name, false otherwise - * - * @see CharOperation#substringMatch(char[], char[]) - */ -private static final boolean checkSubstringMatch(char[] pattern, char[] name) { - -/* XXX: to be revised/enabled - - // allow non-consecutive occurrence of pattern characters - if (pattern.length >= 3) { - int pidx = 0; - - for (int nidx = 0; nidx < name.length; nidx++) { - if (Character.toLowerCase(name[nidx]) == - Character.toLowerCase(pattern[pidx])) - pidx++; - if (pidx == pattern.length) - return true; - } - - // for short patterns only allow consecutive occurrence - } else { -*/ - // outer loop iterates on the characters of the name; trying to - // match at any possible position - outer: for (int nidx = 0; nidx < name.length - pattern.length + 1; nidx++) { - // inner loop iterates on pattern characters - for (int pidx = 0; pidx < pattern.length; pidx++) { - if (Character.toLowerCase(name[nidx + pidx]) != - Character.toLowerCase(pattern[pidx])) { - // no match until parameter list; do not match parameter list - if ((name[nidx + pidx] == '(') || (name[nidx + pidx] == ':')) - return false; - continue outer; - } - if (pidx == pattern.length - 1) - return true; - } - } - // XXX: } - - return false; -} - -/** - * Returns the char arrays as an array of Strings - * - * @param charArrays the char array to convert - * @return the char arrays as an array of Strings or null if the given char arrays is null. - * @since 3.0 - */ -public static String[] charArrayToStringArray(char[][] charArrays) { - if (charArrays == null) - return null; - int length = charArrays.length; - if (length == 0) - return NO_STRINGS; - String[] strings= new String[length]; - for (int i= 0; i < length; i++) - strings[i]= new String(charArrays[i]); - return strings; -} - -/** - * Returns the char array as a String - - * @param charArray the char array to convert - * @return the char array as a String or null if the given char array is null. - * @since 3.0 - */ -public static String charToString(char[] charArray) { - if (charArray == null) return null; - return new String(charArray); -} - -/** - * Converts the given list of strings to an array of equal size, - * containing the individual strings converted to char[] each. - * - * @return an array of char[], representing the elements in the input list, or {@code null} if the list was {@code null}. - * @since 3.14 - */ -public static char[][] toCharArrays(List stringList) { - if (stringList == null) - return null; - char[][] result = new char[stringList.size()][]; - for (int i = 0; i < result.length; i++) - result[i] = stringList.get(i).toCharArray(); - return result; -} -/** - * Answers a new array adding the second array at the end of first array. - * It answers null if the first and second are null. - * If the first array is null, then a new array char[][] is created with second. - * If the second array is null, then the first array is returned. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = { 'a' }
    - *    => result = { { ' a' } }
    - * 
    - *
  2. - *    first = { { ' a' } }
    - *    second = null
    - *    => result = { { ' a' } }
    - * 
    - *
  3. - *
  4. - *    first = { { ' a' } }
    - *    second = { ' b' }
    - *    => result = { { ' a' } , { ' b' } }
    - * 
    - *
  5. - *
- * - * @param first the first array to concatenate - * @param second the array to add at the end of the first array - * @return a new array adding the second array at the end of first array, or null if the two arrays are null. - */ -public static final char[][] arrayConcat(char[][] first, char[] second) { - if (second == null) - return first; - if (first == null) - return new char[][] { second }; - - int length = first.length; - char[][] result = new char[length + 1][]; - System.arraycopy(first, 0, result, 0, length); - result[length] = second; - return result; -} -/** - * Compares the two char arrays lexicographically. - * - * Returns a negative integer if array1 lexicographically precedes the array2, - * a positive integer if this array1 lexicographically follows the array2, or - * zero if both arrays are equal. - * - * @param array1 the first given array - * @param array2 the second given array - * @return the returned value of the comparison between array1 and array2 - * @throws NullPointerException if one of the arrays is null - * @since 3.3 - */ -public static final int compareTo(char[] array1, char[] array2) { - int length1 = array1.length; - int length2 = array2.length; - int min = Math.min(length1, length2); - for (int i = 0; i < min; i++) { - if (array1[i] != array2[i]) { - return array1[i] - array2[i]; - } - } - return length1 - length2; -} -/** - * Compares the two char arrays lexicographically between the given start and end positions. - * - * Returns a negative integer if array1 lexicographically precedes the array2, - * a positive integer if this array1 lexicographically follows the array2, or - * zero if both arrays are equal. - *

The comparison is done between start and end positions.

- * - * @param array1 the first given array - * @param array2 the second given array - * @param start the starting position to compare (inclusive) - * @param end the ending position to compare (exclusive) - * - * @return the returned value of the comparison between array1 and array2 - * @throws NullPointerException if one of the arrays is null - * @since 3.7.1 - */ -public static final int compareTo(char[] array1, char[] array2, int start, int end) { - int length1 = array1.length; - int length2 = array2.length; - int min = Math.min(length1, length2); - min = Math.min(min, end); - for (int i = start; i < min; i++) { - if (array1[i] != array2[i]) { - return array1[i] - array2[i]; - } - } - return length1 - length2; -} -/** - * Compares the contents of the two arrays array and prefix. Returns - *
    - *
  • zero if the array starts with the prefix contents
  • - *
  • the difference between the first two characters that are not equal
  • - *
  • one if array length is lower than the prefix length and that the prefix starts with the - * array contents.
  • - *
- *

- * For example: - *

    - *
  1. - *    array = null
    - *    prefix = null
    - *    => result = NullPointerException
    - * 
    - *
  2. - *
  3. - *    array = { 'a', 'b', 'c', 'd', 'e' }
    - *    prefix = { 'a', 'b', 'c'}
    - *    => result = 0
    - * 
    - *
  4. - *
  5. - *    array = { 'a', 'b', 'c', 'd', 'e' }
    - *    prefix = { 'a', 'B', 'c'}
    - *    => result = 32
    - * 
    - *
  6. - *
  7. - *    array = { 'd', 'b', 'c', 'd', 'e' }
    - *    prefix = { 'a', 'b', 'c'}
    - *    => result = 3
    - * 
    - *
  8. - *
  9. - *    array = { 'a', 'b', 'c', 'd', 'e' }
    - *    prefix = { 'd', 'b', 'c'}
    - *    => result = -3
    - * 
    - *
  10. - *
  11. - *    array = { 'a', 'a', 'c', 'd', 'e' }
    - *    prefix = { 'a', 'e', 'c'}
    - *    => result = -4
    - * 
    - *
  12. - *
- * - * @param array the given array - * @param prefix the given prefix - * @return the result of the comparison (>=0 if array>prefix) - * @throws NullPointerException if either array or prefix is null - */ -public static final int compareWith(char[] array, char[] prefix) { - int arrayLength = array.length; - int prefixLength = prefix.length; - int min = Math.min(arrayLength, prefixLength); - int i = 0; - while (min-- != 0) { - char c1 = array[i]; - char c2 = prefix[i++]; - if (c1 != c2) - return c1 - c2; - } - if (prefixLength == i) - return 0; - return -1; // array is shorter than prefix (e.g. array:'ab' < prefix:'abc'). -} - -/** - * Answers the concatenation of the two arrays. It answers null if the two arrays are null. - * If the first array is null, then the second array is returned. - * If the second array is null, then the first array is returned. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = { 'a' }
    - *    => result = { ' a' }
    - * 
    - *
  2. - *
  3. - *    first = { ' a' }
    - *    second = null
    - *    => result = { ' a' }
    - * 
    - *
  4. - *
  5. - *    first = { ' a' }
    - *    second = { ' b' }
    - *    => result = { ' a' , ' b' }
    - * 
    - *
  6. - *
- * - * @param first the first array to concatenate - * @param second the second array to concatenate - * @return the concatenation of the two arrays, or null if the two arrays are null. - */ -public static final char[] concat(char[] first, char[] second) { - if (first == null) - return second; - if (second == null) - return first; - - int length1 = first.length; - int length2 = second.length; - char[] result = new char[length1 + length2]; - System.arraycopy(first, 0, result, 0, length1); - System.arraycopy(second, 0, result, length1, length2); - return result; -} - -/** - * Answers the concatenation of the three arrays. It answers null if the three arrays are null. - * If first is null, it answers the concatenation of second and third. - * If second is null, it answers the concatenation of first and third. - * If third is null, it answers the concatenation of first and second. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = { 'a' }
    - *    third = { 'b' }
    - *    => result = { ' a', 'b' }
    - * 
    - *
  2. - *
  3. - *    first = { 'a' }
    - *    second = null
    - *    third = { 'b' }
    - *    => result = { ' a', 'b' }
    - * 
    - *
  4. - *
  5. - *    first = { 'a' }
    - *    second = { 'b' }
    - *    third = null
    - *    => result = { ' a', 'b' }
    - * 
    - *
  6. - *
  7. - *    first = null
    - *    second = null
    - *    third = null
    - *    => result = null
    - * 
    - *
  8. - *
  9. - *    first = { 'a' }
    - *    second = { 'b' }
    - *    third = { 'c' }
    - *    => result = { 'a', 'b', 'c' }
    - * 
    - *
  10. - *
- * - * @param first the first array to concatenate - * @param second the second array to concatenate - * @param third the third array to concatenate - * - * @return the concatenation of the three arrays, or null if the three arrays are null. - */ -public static final char[] concat( - char[] first, - char[] second, - char[] third) { - if (first == null) - return concat(second, third); - if (second == null) - return concat(first, third); - if (third == null) - return concat(first, second); - - int length1 = first.length; - int length2 = second.length; - int length3 = third.length; - char[] result = new char[length1 + length2 + length3]; - System.arraycopy(first, 0, result, 0, length1); - System.arraycopy(second, 0, result, length1, length2); - System.arraycopy(third, 0, result, length1 + length2, length3); - return result; -} - -/** - * Answers the concatenation of the two arrays inserting the separator character between the two arrays. - * It answers null if the two arrays are null. - * If the first array is null, then the second array is returned. - * If the second array is null, then the first array is returned. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = { 'a' }
    - *    separator = '/'
    - *    => result = { ' a' }
    - * 
    - *
  2. - *
  3. - *    first = { ' a' }
    - *    second = null
    - *    separator = '/'
    - *    => result = { ' a' }
    - * 
    - *
  4. - *
  5. - *    first = { ' a' }
    - *    second = { ' b' }
    - *    separator = '/'
    - *    => result = { ' a' , '/', 'b' }
    - * 
    - *
  6. - *
- * - * @param first the first array to concatenate - * @param second the second array to concatenate - * @param separator the character to insert - * @return the concatenation of the two arrays inserting the separator character - * between the two arrays , or null if the two arrays are null. - */ -public static final char[] concat( - char[] first, - char[] second, - char separator) { - if (first == null) - return second; - if (second == null) - return first; - - int length1 = first.length; - if (length1 == 0) - return second; - int length2 = second.length; - if (length2 == 0) - return first; - - char[] result = new char[length1 + length2 + 1]; - System.arraycopy(first, 0, result, 0, length1); - result[length1] = separator; - System.arraycopy(second, 0, result, length1 + 1, length2); - return result; -} - -/** - * Answers the concatenation of the two arrays inserting the separator character between the two arrays. Differs from - * {@link CharOperation#contains(char, char[])} in case second array is a zero length array. - * It answers null if the two arrays are null. - * If the first array is null, then the second array is returned. - * If the second array is null, then the first array is returned. - * if the second array is zero length array, the separator is appended. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = { 'a' }
    - *    separator = '/'
    - *    => result = { ' a' }
    - * 
    - *
  2. - *
  3. - *    first = { ' a' }
    - *    second = null
    - *    separator = '/'
    - *    => result = { ' a' }
    - * 
    - *
  4. - *
  5. - *    first = { ' a' }
    - *    second = { ' b' }
    - *    separator = '/'
    - *    => result = { ' a' , '/', 'b' }
    - * 
    - *
  6. - *
  7. - *    first = { ' a' }
    - *    second = { '' }
    - *    separator = '.'
    - *    => result = { ' a' , '.', }
    - * 
    - *
  8. - *
- * - * @param first the first array to concatenate - * @param second the second array to concatenate - * @param separator the character to insert - * @return the concatenation of the two arrays inserting the separator character - * between the two arrays , or null if the two arrays are null. If second array - * is of zero length, the separator is appended to the first array and returned. - * @since 3.14 - */ -public static final char[] concatAll( - char[] first, - char[] second, - char separator) { - if (first == null) - return second; - if (second == null) - return first; - - int length1 = first.length; - if (length1 == 0) - return second; - int length2 = second.length; - - char[] result = new char[length1 + length2 + 1]; - System.arraycopy(first, 0, result, 0, length1); - result[length1] = separator; - if (length2 > 0) - System.arraycopy(second, 0, result, length1 + 1, length2); - return result; -} - -/** - * Answers the concatenation of the three arrays inserting the sep1 character between the - * first two arrays and sep2 between the last two. - * It answers null if the three arrays are null. - * If the first array is null, then it answers the concatenation of second and third inserting - * the sep2 character between them. - * If the second array is null, then it answers the concatenation of first and third inserting - * the sep1 character between them. - * If the third array is null, then it answers the concatenation of first and second inserting - * the sep1 character between them. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    sep1 = '/'
    - *    second = { 'a' }
    - *    sep2 = ':'
    - *    third = { 'b' }
    - *    => result = { ' a' , ':', 'b' }
    - * 
    - *
  2. - *
  3. - *    first = { 'a' }
    - *    sep1 = '/'
    - *    second = null
    - *    sep2 = ':'
    - *    third = { 'b' }
    - *    => result = { ' a' , '/', 'b' }
    - * 
    - *
  4. - *
  5. - *    first = { 'a' }
    - *    sep1 = '/'
    - *    second = { 'b' }
    - *    sep2 = ':'
    - *    third = null
    - *    => result = { ' a' , '/', 'b' }
    - * 
    - *
  6. - *
  7. - *    first = { 'a' }
    - *    sep1 = '/'
    - *    second = { 'b' }
    - *    sep2 = ':'
    - *    third = { 'c' }
    - *    => result = { ' a' , '/', 'b' , ':', 'c' }
    - * 
    - *
  8. - *
- * - * @param first the first array to concatenate - * @param sep1 the character to insert - * @param second the second array to concatenate - * @param sep2 the character to insert - * @param third the second array to concatenate - * @return the concatenation of the three arrays inserting the sep1 character between the - * two arrays and sep2 between the last two. - */ -public static final char[] concat( - char[] first, - char sep1, - char[] second, - char sep2, - char[] third) { - if (first == null) - return concat(second, third, sep2); - if (second == null) - return concat(first, third, sep1); - if (third == null) - return concat(first, second, sep1); - - int length1 = first.length; - int length2 = second.length; - int length3 = third.length; - char[] result = new char[length1 + length2 + length3 + 2]; - System.arraycopy(first, 0, result, 0, length1); - result[length1] = sep1; - System.arraycopy(second, 0, result, length1 + 1, length2); - result[length1 + length2 + 1] = sep2; - System.arraycopy(third, 0, result, length1 + length2 + 2, length3); - return result; -} -/** - * Answers the concatenation of the two arrays inserting the separator character between the two arrays. - * It answers null if the two arrays are null. - * If the first array is null or is empty, then the second array is returned. - * If the second array is null or is empty, then the first array is returned. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = { 'a' }
    - *    separator = '/'
    - *    => result = { ' a' }
    - * 
    - *
  2. - *
  3. - *    first = { ' a' }
    - *    second = null
    - *    separator = '/'
    - *    => result = { ' a' }
    - * 
    - *
  4. - *
  5. - *    first = { ' a' }
    - *    second = { ' b' }
    - *    separator = '/'
    - *    => result = { ' a' , '/', 'b' }
    - * 
    - *
  6. - *
  7. - *    first = { ' a' }
    - *    second = {  }
    - *    separator = '/'
    - *    => result = { ' a'}
    - * 
    - *
  8. - - *
- * - * @param first the first array to concatenate - * @param second the second array to concatenate - * @param separator the character to insert - * @return the concatenation of the two arrays inserting the separator character - * between the two arrays , or null if the two arrays are null. - * @since 3.12 - */ -public static final char[] concatNonEmpty( - char[] first, - char[] second, - char separator) { - if (first == null || first.length == 0) - return second; - if (second == null || second.length == 0) - return first; - return concat(first, second, separator); -} -/** - * Answers the concatenation of the three arrays inserting the sep1 character between the - * first two arrays and sep2 between the last two. - * It answers null if the three arrays are null. - * If the first array is null or empty, then it answers the concatenation of second and third inserting - * the sep2 character between them. - * If the second array is null or empty, then it answers the concatenation of first and third inserting - * the sep1 character between them. - * If the third array is null or empty, then it answers the concatenation of first and second inserting - * the sep1 character between them. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    sep1 = '/'
    - *    second = { 'a' }
    - *    sep2 = ':'
    - *    third = { 'b' }
    - *    => result = { ' a' , ':', 'b' }
    - * 
    - *
  2. - *
  3. - *    first = { 'a' }
    - *    sep1 = '/'
    - *    second = null
    - *    sep2 = ':'
    - *    third = { 'b' }
    - *    => result = { ' a' , '/', 'b' }
    - * 
    - *
  4. - *
  5. - *    first = { 'a' }
    - *    sep1 = '/'
    - *    second = { 'b' }
    - *    sep2 = ':'
    - *    third = null
    - *    => result = { ' a' , '/', 'b' }
    - * 
    - *
  6. - *
  7. - *    first = { 'a' }
    - *    sep1 = '/'
    - *    second = { 'b' }
    - *    sep2 = ':'
    - *    third = { 'c' }
    - *    => result = { ' a' , '/', 'b' , ':', 'c' }
    - * 
    - *
  8. - *
  9. - *    first = { 'a' }
    - *    sep1 = '/'
    - *    second = { }
    - *    sep2 = ':'
    - *    third = { 'c' }
    - *    => result = { ' a', ':', 'c' }
    - * 
    - *
  10. - *
- * - * @param first the first array to concatenate - * @param sep1 the character to insert - * @param second the second array to concatenate - * @param sep2 the character to insert - * @param third the second array to concatenate - * @return the concatenation of the three arrays inserting the sep1 character between the - * two arrays and sep2 between the last two. - * @since 3.12 - */ -public static final char[] concatNonEmpty( - char[] first, - char sep1, - char[] second, - char sep2, - char[] third) { - if (first == null || first.length == 0) - return concatNonEmpty(second, third, sep2); - if (second == null || second.length == 0) - return concatNonEmpty(first, third, sep1); - if (third == null || third.length == 0) - return concatNonEmpty(first, second, sep1); - - return concat(first, sep1, second, sep2, third); -} - -/** - * Answers a new array with prepending the prefix character and appending the suffix - * character at the end of the array. If array is null, it answers a new array containing the - * prefix and the suffix characters. - *
- *
- * For example:
- *
    - *
  1. - *    prefix = 'a'
    - *    array = { 'b' }
    - *    suffix = 'c'
    - *    => result = { 'a', 'b' , 'c' }
    - * 
    - *
  2. - *
  3. - *    prefix = 'a'
    - *    array = null
    - *    suffix = 'c'
    - *    => result = { 'a', 'c' }
    - * 
  4. - *
- * - * @param prefix the prefix character - * @param array the array that is concatenated with the prefix and suffix characters - * @param suffix the suffix character - * @return the new array - */ -public static final char[] concat(char prefix, char[] array, char suffix) { - if (array == null) - return new char[] { prefix, suffix }; - - int length = array.length; - char[] result = new char[length + 2]; - result[0] = prefix; - System.arraycopy(array, 0, result, 1, length); - result[length + 1] = suffix; - return result; -} - -/** - * Answers the concatenation of the given array parts using the given separator between each - * part and prepending the given name at the beginning. - *
- *
- * For example:
- *
    - *
  1. - *    name = { 'c' }
    - *    array = { { 'a' }, { 'b' } }
    - *    separator = '.'
    - *    => result = { 'a', '.', 'b' , '.', 'c' }
    - * 
    - *
  2. - *
  3. - *    name = null
    - *    array = { { 'a' }, { 'b' } }
    - *    separator = '.'
    - *    => result = { 'a', '.', 'b' }
    - * 
  4. - *
  5. - *    name = { ' c' }
    - *    array = null
    - *    separator = '.'
    - *    => result = { 'c' }
    - * 
  6. - *
- * - * @param name the given name - * @param array the given array - * @param separator the given separator - * @return the concatenation of the given array parts using the given separator between each - * part and prepending the given name at the beginning - */ -public static final char[] concatWith( - char[] name, - char[][] array, - char separator) { - int nameLength = name == null ? 0 : name.length; - if (nameLength == 0) - return concatWith(array, separator); - - int length = array == null ? 0 : array.length; - if (length == 0) - return name; - - int size = nameLength; - int index = length; - while (--index >= 0) - if (array[index].length > 0) - size += array[index].length + 1; - char[] result = new char[size]; - index = size; - for (int i = length - 1; i >= 0; i--) { - int subLength = array[i].length; - if (subLength > 0) { - index -= subLength; - System.arraycopy(array[i], 0, result, index, subLength); - result[--index] = separator; - } - } - System.arraycopy(name, 0, result, 0, nameLength); - return result; -} - -/** - * Answers the concatenation of the given array parts using the given separator between each - * part and appending the given name at the end. - *
- *
- * For example:
- *
    - *
  1. - *    name = { 'c' }
    - *    array = { { 'a' }, { 'b' } }
    - *    separator = '.'
    - *    => result = { 'a', '.', 'b' , '.', 'c' }
    - * 
    - *
  2. - *
  3. - *    name = null
    - *    array = { { 'a' }, { 'b' } }
    - *    separator = '.'
    - *    => result = { 'a', '.', 'b' }
    - * 
  4. - *
  5. - *    name = { ' c' }
    - *    array = null
    - *    separator = '.'
    - *    => result = { 'c' }
    - * 
  6. - *
- * - * @param array the given array - * @param name the given name - * @param separator the given separator - * @return the concatenation of the given array parts using the given separator between each - * part and appending the given name at the end - */ -public static final char[] concatWith( - char[][] array, - char[] name, - char separator) { - int nameLength = name == null ? 0 : name.length; - if (nameLength == 0) - return concatWith(array, separator); - - int length = array == null ? 0 : array.length; - if (length == 0) - return name; - - int size = nameLength; - int index = length; - while (--index >= 0) - if (array[index].length > 0) - size += array[index].length + 1; - char[] result = new char[size]; - index = 0; - for (int i = 0; i < length; i++) { - int subLength = array[i].length; - if (subLength > 0) { - System.arraycopy(array[i], 0, result, index, subLength); - index += subLength; - result[index++] = separator; - } - } - System.arraycopy(name, 0, result, index, nameLength); - return result; -} - -/** - * Answers the concatenation of the given array parts using the given separator between each part. - *
- *
- * For example:
- *
    - *
  1. - *    array = { { 'a' }, { 'b' } }
    - *    separator = '.'
    - *    => result = { 'a', '.', 'b' }
    - * 
    - *
  2. - *
  3. - *    array = null
    - *    separator = '.'
    - *    => result = { }
    - * 
  4. - *
- * - * @param array the given array - * @param separator the given separator - * @return the concatenation of the given array parts using the given separator between each part - */ -public static final char[] concatWith(char[][] array, char separator) { - int length = array == null ? 0 : array.length; - if (length == 0) - return CharOperation.NO_CHAR; - - int size = length - 1; - int index = length; - while (--index >= 0) { - if (array[index].length == 0) - size--; - else - size += array[index].length; - } - if (size <= 0) - return CharOperation.NO_CHAR; - char[] result = new char[size]; - index = length; - while (--index >= 0) { - length = array[index].length; - if (length > 0) { - System.arraycopy( - array[index], - 0, - result, - (size -= length), - length); - if (--size >= 0) - result[size] = separator; - } - } - return result; -} - -/** - * Answers the concatenation of the given array parts using the given separator between each part - * irrespective of whether an element is a zero length array or not. - *
- *
- * For example:
- *
    - *
  1. - *    array = { { 'a' }, {}, { 'b' } }
    - *    separator = ''
    - *    => result = { 'a', '/', '/', 'b' }
    - * 
    - *
  2. - *
  3. - *    array = { { 'a' }, { 'b' } }
    - *    separator = '.'
    - *    => result = { 'a', '.', 'b' }
    - * 
    - *
  4. - *
  5. - *    array = null
    - *    separator = '.'
    - *    => result = { }
    - * 
  6. - *
- * - * @param array the given array - * @param separator the given separator - * @return the concatenation of the given array parts using the given separator between each part - * @since 3.12 - */ -public static final char[] concatWithAll(char[][] array, char separator) { - int length = array == null ? 0 : array.length; - if (length == 0) - return CharOperation.NO_CHAR; - - int size = length - 1; - int index = length; - while (--index >= 0) { - size += array[index].length; - } - char[] result = new char[size]; - index = length; - while (--index >= 0) { - length = array[index].length; - if (length > 0) { - System.arraycopy( - array[index], - 0, - result, - (size -= length), - length); - } - if (--size >= 0) - result[size] = separator; - } - return result; -} - -/** - * Answers true if the array contains an occurrence of character, false otherwise. - * - *
- *
- * For example: - *
    - *
  1. - *    character = 'c'
    - *    array = { { ' a' }, { ' b' } }
    - *    result => false
    - * 
    - *
  2. - *
  3. - *    character = 'a'
    - *    array = { { ' a' }, { ' b' } }
    - *    result => true
    - * 
    - *
  4. - *
- * - * @param character the character to search - * @param array the array in which the search is done - * @return true if the array contains an occurrence of character, false otherwise. - * @throws NullPointerException if array is null. - */ -public static final boolean contains(char character, char[][] array) { - for (int i = array.length; --i >= 0;) { - char[] subarray = array[i]; - for (int j = subarray.length; --j >= 0;) - if (subarray[j] == character) - return true; - } - return false; -} - -/** - * Answers true if the array contains an occurrence of character, false otherwise. - * - *
- *
- * For example: - *
    - *
  1. - *    character = 'c'
    - *    array = { ' b'  }
    - *    result => false
    - * 
    - *
  2. - *
  3. - *    character = 'a'
    - *    array = { ' a' , ' b' }
    - *    result => true
    - * 
    - *
  4. - *
- * - * @param character the character to search - * @param array the array in which the search is done - * @return true if the array contains an occurrence of character, false otherwise. - * @throws NullPointerException if array is null. - */ -public static final boolean contains(char character, char[] array) { - for (int i = array.length; --i >= 0;) - if (array[i] == character) - return true; - return false; -} - -/** - * Answers true if the array contains an occurrence of one of the characters, false otherwise. - * - *
- *
- * For example: - *
    - *
  1. - *    characters = { 'c', 'd' }
    - *    array = { 'a', ' b'  }
    - *    result => false
    - * 
    - *
  2. - *
  3. - *    characters = { 'c', 'd' }
    - *    array = { 'a', ' b', 'c'  }
    - *    result => true
    - * 
    - *
  4. - *
- * - * @param characters the characters to search - * @param array the array in which the search is done - * @return true if the array contains an occurrence of one of the characters, false otherwise. - * @throws NullPointerException if array is null. - * @since 3.1 - */ -public static final boolean contains(char[] characters, char[] array) { - for (int i = array.length; --i >= 0;) - for (int j = characters.length; --j >= 0;) - if (array[i] == characters[j]) - return true; - return false; -} - -/** - * Does the given array contain a char sequence that is equal to the give sequence? - * @return true if sequence is equal to an element in array - * @since 3.14 - */ -public static boolean containsEqual(char[][] array, char[] sequence) { - for (int i = 0; i < array.length; i++) { - if (equals(array[i], sequence)) - return true; - } - return false; -} - -/** - * Answers a deep copy of the toCopy array. - * - * @param toCopy the array to copy - * @return a deep copy of the toCopy array. - */ - -public static final char[][] deepCopy(char[][] toCopy) { - int toCopyLength = toCopy.length; - char[][] result = new char[toCopyLength][]; - for (int i = 0; i < toCopyLength; i++) { - char[] toElement = toCopy[i]; - int toElementLength = toElement.length; - char[] resultElement = new char[toElementLength]; - System.arraycopy(toElement, 0, resultElement, 0, toElementLength); - result[i] = resultElement; - } - return result; -} - -/** - * Return true if array ends with the sequence of characters contained in toBeFound, - * otherwise false. - *
- *
- * For example: - *
    - *
  1. - *    array = { 'a', 'b', 'c', 'd' }
    - *    toBeFound = { 'b', 'c' }
    - *    result => false
    - * 
    - *
  2. - *
  3. - *    array = { 'a', 'b', 'c' }
    - *    toBeFound = { 'b', 'c' }
    - *    result => true
    - * 
    - *
  4. - *
- * - * @param array the array to check - * @param toBeFound the array to find - * @return true if array ends with the sequence of characters contained in toBeFound, - * otherwise false. - * @throws NullPointerException if array is null or toBeFound is null - */ -public static final boolean endsWith(char[] array, char[] toBeFound) { - int i = toBeFound.length; - int j = array.length - i; - - if (j < 0) - return false; - while (--i >= 0) - if (toBeFound[i] != array[i + j]) - return false; - return true; -} - -/** - * Answers true if the two arrays are identical character by character, otherwise false. - * The equality is case sensitive. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = null
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    first = { { } }
    - *    second = null
    - *    result => false
    - * 
    - *
  4. - *
  5. - *    first = { { 'a' } }
    - *    second = { { 'a' } }
    - *    result => true
    - * 
    - *
  6. - *
  7. - *    first = { { 'A' } }
    - *    second = { { 'a' } }
    - *    result => false
    - * 
    - *
  8. - *
- * @param first the first array - * @param second the second array - * @return true if the two arrays are identical character by character, otherwise false - */ -public static final boolean equals(char[][] first, char[][] second) { - if (first == second) - return true; - if (first == null || second == null) - return false; - if (first.length != second.length) - return false; - - for (int i = first.length; --i >= 0;) - if (!equals(first[i], second[i])) - return false; - return true; -} - -/** - * If isCaseSensite is true, answers true if the two arrays are identical character - * by character, otherwise false. - * If it is false, answers true if the two arrays are identical character by - * character without checking the case, otherwise false. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = null
    - *    isCaseSensitive = true
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    first = { { } }
    - *    second = null
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  4. - *
  5. - *    first = { { 'A' } }
    - *    second = { { 'a' } }
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  6. - *
  7. - *    first = { { 'A' } }
    - *    second = { { 'a' } }
    - *    isCaseSensitive = false
    - *    result => true
    - * 
    - *
  8. - *
- * - * @param first the first array - * @param second the second array - * @param isCaseSensitive check whether or not the equality should be case sensitive - * @return true if the two arrays are identical character by character according to the value - * of isCaseSensitive, otherwise false - */ -public static final boolean equals( - char[][] first, - char[][] second, - boolean isCaseSensitive) { - - if (isCaseSensitive) { - return equals(first, second); - } - if (first == second) - return true; - if (first == null || second == null) - return false; - if (first.length != second.length) - return false; - - for (int i = first.length; --i >= 0;) - if (!equals(first[i], second[i], false)) - return false; - return true; -} - -/** - * Answers true if the two arrays are identical character by character, otherwise false. - * The equality is case sensitive. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = null
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    first = { }
    - *    second = null
    - *    result => false
    - * 
    - *
  4. - *
  5. - *    first = { 'a' }
    - *    second = { 'a' }
    - *    result => true
    - * 
    - *
  6. - *
  7. - *    first = { 'a' }
    - *    second = { 'A' }
    - *    result => false
    - * 
    - *
  8. - *
- * @param first the first array - * @param second the second array - * @return true if the two arrays are identical character by character, otherwise false - */ -public static final boolean equals(char[] first, char[] second) { - return Arrays.equals(first, second); -} - -/** - * Answers true if the first array is identical character by character to a portion of the second array - * delimited from position secondStart (inclusive) to secondEnd(exclusive), otherwise false. - * The equality is case sensitive. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = null
    - *    secondStart = 0
    - *    secondEnd = 0
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    first = { }
    - *    second = null
    - *    secondStart = 0
    - *    secondEnd = 0
    - *    result => false
    - * 
    - *
  4. - *
  5. - *    first = { 'a' }
    - *    second = { 'a' }
    - *    secondStart = 0
    - *    secondEnd = 1
    - *    result => true
    - * 
    - *
  6. - *
  7. - *    first = { 'a' }
    - *    second = { 'A' }
    - *    secondStart = 0
    - *    secondEnd = 1
    - *    result => false
    - * 
    - *
  8. - *
- * @param first the first array - * @param second the second array - * @param secondStart inclusive start position in the second array to compare - * @param secondEnd exclusive end position in the second array to compare - * @return true if the first array is identical character by character to fragment of second array ranging from secondStart to secondEnd-1, otherwise false - * @since 3.0 - */ -public static final boolean equals(char[] first, char[] second, int secondStart, int secondEnd) { - return equals(first, second, secondStart, secondEnd, true); -} -/** - *

Answers true if the first array is identical character by character to a portion of the second array - * delimited from position secondStart (inclusive) to secondEnd(exclusive), otherwise false. The equality could be either - * case sensitive or case insensitive according to the value of the isCaseSensitive parameter. - *

- *

For example:

- *
    - *
  1. - *    first = null
    - *    second = null
    - *    secondStart = 0
    - *    secondEnd = 0
    - *    isCaseSensitive = false
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    first = { }
    - *    second = null
    - *    secondStart = 0
    - *    secondEnd = 0
    - *    isCaseSensitive = false
    - *    result => false
    - * 
    - *
  4. - *
  5. - *    first = { 'a' }
    - *    second = { 'a' }
    - *    secondStart = 0
    - *    secondEnd = 1
    - *    isCaseSensitive = true
    - *    result => true
    - * 
    - *
  6. - *
  7. - *    first = { 'a' }
    - *    second = { 'A' }
    - *    secondStart = 0
    - *    secondEnd = 1
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  8. - *
  9. - *    first = { 'a' }
    - *    second = { 'A' }
    - *    secondStart = 0
    - *    secondEnd = 1
    - *    isCaseSensitive = false
    - *    result => true
    - * 
    - *
  10. - *
- * @param first the first array - * @param second the second array - * @param secondStart inclusive start position in the second array to compare - * @param secondEnd exclusive end position in the second array to compare - * @param isCaseSensitive check whether or not the equality should be case sensitive - * @return true if the first array is identical character by character to fragment of second array ranging from secondStart to secondEnd-1, otherwise false - * @since 3.2 - */ -public static final boolean equals(char[] first, char[] second, int secondStart, int secondEnd, boolean isCaseSensitive) { - if (first == second) - return true; - if (first == null || second == null) - return false; - if (first.length != secondEnd - secondStart) - return false; - if (isCaseSensitive) { - for (int i = first.length; --i >= 0;) - if (first[i] != second[i+secondStart]) - return false; - } else { - for (int i = first.length; --i >= 0;) - if (ScannerHelper.toLowerCase(first[i]) != ScannerHelper.toLowerCase(second[i+secondStart])) - return false; - } - return true; -} - -/** - * If isCaseSensite is true, answers true if the two arrays are identical character - * by character, otherwise false. - * If it is false, answers true if the two arrays are identical character by - * character without checking the case, otherwise false. - *
- *
- * For example: - *
    - *
  1. - *    first = null
    - *    second = null
    - *    isCaseSensitive = true
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    first = { }
    - *    second = null
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  4. - *
  5. - *    first = { 'A' }
    - *    second = { 'a' }
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  6. - *
  7. - *    first = { 'A' }
    - *    second = { 'a' }
    - *    isCaseSensitive = false
    - *    result => true
    - * 
    - *
  8. - *
- * - * @param first the first array - * @param second the second array - * @param isCaseSensitive check whether or not the equality should be case sensitive - * @return true if the two arrays are identical character by character according to the value - * of isCaseSensitive, otherwise false - */ -public static final boolean equals( - char[] first, - char[] second, - boolean isCaseSensitive) { - - if (isCaseSensitive) { - return equals(first, second); - } - if (first == second) - return true; - if (first == null || second == null) - return false; - if (first.length != second.length) - return false; - - for (int i = first.length; --i >= 0;) - if (ScannerHelper.toLowerCase(first[i]) - != ScannerHelper.toLowerCase(second[i])) - return false; - return true; -} - -/** - * If isCaseSensite is true, the equality is case sensitive, otherwise it is case insensitive. - * - * Answers true if the name contains the fragment at the starting index startIndex, otherwise false. - *
- *
- * For example: - *
    - *
  1. - *    fragment = { 'b', 'c' , 'd' }
    - *    name = { 'a', 'b', 'c' , 'd' }
    - *    startIndex = 1
    - *    isCaseSensitive = true
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    fragment = { 'b', 'c' , 'd' }
    - *    name = { 'a', 'b', 'C' , 'd' }
    - *    startIndex = 1
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  4. - *
  5. - *    fragment = { 'b', 'c' , 'd' }
    - *    name = { 'a', 'b', 'C' , 'd' }
    - *    startIndex = 0
    - *    isCaseSensitive = false
    - *    result => false
    - * 
    - *
  6. - *
  7. - *    fragment = { 'b', 'c' , 'd' }
    - *    name = { 'a', 'b'}
    - *    startIndex = 0
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  8. - *
- * - * @param fragment the fragment to check - * @param name the array to check - * @param startIndex the starting index - * @param isCaseSensitive check whether or not the equality should be case sensitive - * @return true if the name contains the fragment at the starting index startIndex according to the - * value of isCaseSensitive, otherwise false. - * @throws NullPointerException if fragment or name is null. - */ -public static final boolean fragmentEquals( - char[] fragment, - char[] name, - int startIndex, - boolean isCaseSensitive) { - - int max = fragment.length; - if (name.length < max + startIndex) - return false; - if (isCaseSensitive) { - for (int i = max; - --i >= 0; - ) // assumes the prefix is not larger than the name - if (fragment[i] != name[i + startIndex]) - return false; - return true; - } - for (int i = max; - --i >= 0; - ) // assumes the prefix is not larger than the name - if (ScannerHelper.toLowerCase(fragment[i]) - != ScannerHelper.toLowerCase(name[i + startIndex])) - return false; - return true; -} - -/** - * Answers a hashcode for the array - * - * @param array the array for which a hashcode is required - * @return the hashcode - */ -public static final int hashCode(char[] array) { - int hash = Arrays.hashCode(array); - return hash & 0x7FFFFFFF; -} - -/** - * Answers true if c is a whitespace according to the JLS (\u0009, \u000a, \u000c, \u000d, \u0020), otherwise false. - *
- *
- * For example: - *
    - *
  1. - *    c = ' '
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    c = '\u3000'
    - *    result => false
    - * 
    - *
  4. - *
- * - * @param c the character to check - * @return true if c is a whitespace according to the JLS, otherwise false. - */ -public static boolean isWhitespace(char c) { - return c < ScannerHelper.MAX_OBVIOUS && ((ScannerHelper.OBVIOUS_IDENT_CHAR_NATURES[c] & ScannerHelper.C_JLS_SPACE) != 0); -} - -/** - * Answers the first index in the array for which the corresponding character is - * equal to toBeFound. Answers -1 if no occurrence of this character is found. - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    result => 2
    - * 
    - *
  2. - *
  3. - *    toBeFound = 'e'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    result => -1
    - * 
    - *
  4. - *
- * - * @param toBeFound the character to search - * @param array the array to be searched - * @return the first index in the array for which the corresponding character is - * equal to toBeFound, -1 otherwise - * @throws NullPointerException if array is null - */ -public static final int indexOf(char toBeFound, char[] array) { - return indexOf(toBeFound, array, 0); -} - -/** - * Answers the first index in the array for which the toBeFound array is a matching - * subarray following the case rule. Answers -1 if no match is found. - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = { 'c' }
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    result => 2
    - * 
    - *
  2. - *
  3. - *    toBeFound = { 'e' }
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    result => -1
    - * 
    - *
  4. - *
- * - * @param toBeFound the subarray to search - * @param array the array to be searched - * @param isCaseSensitive flag to know if the matching should be case sensitive - * @return the first index in the array for which the toBeFound array is a matching - * subarray following the case rule, -1 otherwise - * @throws NullPointerException if array is null or toBeFound is null - * @since 3.2 - */ -public static final int indexOf(char[] toBeFound, char[] array, boolean isCaseSensitive) { - return indexOf(toBeFound, array, isCaseSensitive, 0); -} - -/** - * Answers the first index in the array for which the toBeFound array is a matching - * subarray following the case rule starting at the index start. Answers -1 if no match is found. - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = { 'c' }
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    result => 2
    - * 
    - *
  2. - *
  3. - *    toBeFound = { 'e' }
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    result => -1
    - * 
    - *
  4. - *
- * - * @param toBeFound the subarray to search - * @param array the array to be searched - * @param isCaseSensitive flag to know if the matching should be case sensitive - * @param start the starting index - * @return the first index in the array for which the toBeFound array is a matching - * subarray following the case rule starting at the index start, -1 otherwise - * @throws NullPointerException if array is null or toBeFound is null - * @since 3.2 - */ -public static final int indexOf(final char[] toBeFound, final char[] array, final boolean isCaseSensitive, final int start) { - return indexOf(toBeFound, array, isCaseSensitive, start, array.length); -} - -/** - * Answers the first index in the array for which the toBeFound array is a matching - * subarray following the case rule starting at the index start. Answers -1 if no match is found. - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = { 'c' }
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    result => 2
    - * 
    - *
  2. - *
  3. - *    toBeFound = { 'e' }
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    result => -1
    - * 
    - *
  4. - *
- * - * @param toBeFound the subarray to search - * @param array the array to be searched - * @param isCaseSensitive flag to know if the matching should be case sensitive - * @param start the starting index (inclusive) - * @param end the end index (exclusive) - * @return the first index in the array for which the toBeFound array is a matching - * subarray following the case rule starting at the index start, -1 otherwise - * @throws NullPointerException if array is null or toBeFound is null - * @since 3.2 - */ -public static final int indexOf(final char[] toBeFound, final char[] array, final boolean isCaseSensitive, final int start, final int end) { - final int arrayLength = end; - final int toBeFoundLength = toBeFound.length; - if (toBeFoundLength > arrayLength || start < 0) return -1; - if (toBeFoundLength == 0) return 0; - if (toBeFoundLength == arrayLength) { - if (isCaseSensitive) { - for (int i = start; i < arrayLength; i++) { - if (array[i] != toBeFound[i]) return -1; - } - return 0; - } else { - for (int i = start; i < arrayLength; i++) { - if (ScannerHelper.toLowerCase(array[i]) != ScannerHelper.toLowerCase(toBeFound[i])) return -1; - } - return 0; - } - } - if (isCaseSensitive) { - arrayLoop: for (int i = start, max = arrayLength - toBeFoundLength + 1; i < max; i++) { - if (array[i] == toBeFound[0]) { - for (int j = 1; j < toBeFoundLength; j++) { - if (array[i + j] != toBeFound[j]) continue arrayLoop; - } - return i; - } - } - } else { - arrayLoop: for (int i = start, max = arrayLength - toBeFoundLength + 1; i < max; i++) { - if (ScannerHelper.toLowerCase(array[i]) == ScannerHelper.toLowerCase(toBeFound[0])) { - for (int j = 1; j < toBeFoundLength; j++) { - if (ScannerHelper.toLowerCase(array[i + j]) != ScannerHelper.toLowerCase(toBeFound[j])) continue arrayLoop; - } - return i; - } - } - } - return -1; -} - -/** - * Answers the first index in the array for which the corresponding character is - * equal to toBeFound starting the search at index start. - * Answers -1 if no occurrence of this character is found. - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    start = 2
    - *    result => 2
    - * 
    - *
  2. - *
  3. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    start = 3
    - *    result => -1
    - * 
    - *
  4. - *
  5. - *    toBeFound = 'e'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    start = 1
    - *    result => -1
    - * 
    - *
  6. - *
- * - * @param toBeFound the character to search - * @param array the array to be searched - * @param start the starting index - * @return the first index in the array for which the corresponding character is - * equal to toBeFound, -1 otherwise - * @throws NullPointerException if array is null - * @throws ArrayIndexOutOfBoundsException if start is lower than 0 - */ -public static final int indexOf(char toBeFound, char[] array, int start) { - for (int i = start; i < array.length; i++) - if (toBeFound == array[i]) - return i; - return -1; -} - -/** - * Answers the first index in the array for which the corresponding character is - * equal to toBeFound starting the search at index start and before the ending index. - * Answers -1 if no occurrence of this character is found. - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    start = 2
    - *    result => 2
    - * 
    - *
  2. - *
  3. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    start = 3
    - *    result => -1
    - * 
    - *
  4. - *
  5. - *    toBeFound = 'e'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    start = 1
    - *    result => -1
    - * 
    - *
  6. - *
- * - * @param toBeFound the character to search - * @param array the array to be searched - * @param start the starting index (inclusive) - * @param end the ending index (exclusive) - * @return the first index in the array for which the corresponding character is - * equal to toBeFound, -1 otherwise - * @throws NullPointerException if array is null - * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or ending greater than array length - * @since 3.2 - */ -public static final int indexOf(char toBeFound, char[] array, int start, int end) { - for (int i = start; i < end; i++) - if (toBeFound == array[i]) - return i; - return -1; -} - -/** - * Answers the last index in the array for which the corresponding character is - * equal to toBeFound starting from the end of the array. - * Answers -1 if no occurrence of this character is found. - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd' , 'c', 'e' }
    - *    result => 4
    - * 
    - *
  2. - *
  3. - *    toBeFound = 'e'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    result => -1
    - * 
    - *
  4. - *
- * - * @param toBeFound the character to search - * @param array the array to be searched - * @return the last index in the array for which the corresponding character is - * equal to toBeFound starting from the end of the array, -1 otherwise - * @throws NullPointerException if array is null - */ -public static final int lastIndexOf(char toBeFound, char[] array) { - for (int i = array.length; --i >= 0;) - if (toBeFound == array[i]) - return i; - return -1; -} - -/** - * Answers the last index in the array for which the corresponding character is - * equal to toBeFound stopping at the index startIndex. - * Answers -1 if no occurrence of this character is found. - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    startIndex = 2
    - *    result => 2
    - * 
    - *
  2. - *
  3. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd', 'e' }
    - *    startIndex = 3
    - *    result => -1
    - * 
    - *
  4. - *
  5. - *    toBeFound = 'e'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    startIndex = 0
    - *    result => -1
    - * 
    - *
  6. - *
- * - * @param toBeFound the character to search - * @param array the array to be searched - * @param startIndex the stopping index - * @return the last index in the array for which the corresponding character is - * equal to toBeFound stopping at the index startIndex, -1 otherwise - * @throws NullPointerException if array is null - * @throws ArrayIndexOutOfBoundsException if startIndex is lower than 0 - */ -public static final int lastIndexOf( - char toBeFound, - char[] array, - int startIndex) { - for (int i = array.length; --i >= startIndex;) - if (toBeFound == array[i]) - return i; - return -1; -} - -/** - * Answers the last index in the array for which the corresponding character is - * equal to toBeFound starting from endIndex to startIndex. - * Answers -1 if no occurrence of this character is found. - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    startIndex = 2
    - *    endIndex = 2
    - *    result => 2
    - * 
    - *
  2. - *
  3. - *    toBeFound = 'c'
    - *    array = { ' a', 'b', 'c', 'd', 'e' }
    - *    startIndex = 3
    - *    endIndex = 4
    - *    result => -1
    - * 
    - *
  4. - *
  5. - *    toBeFound = 'e'
    - *    array = { ' a', 'b', 'c', 'd' }
    - *    startIndex = 0
    - *    endIndex = 3
    - *    result => -1
    - * 
    - *
  6. - *
- * - * @param toBeFound the character to search - * @param array the array to be searched - * @param startIndex the stopping index - * @param endIndex the starting index - * @return the last index in the array for which the corresponding character is - * equal to toBeFound starting from endIndex to startIndex, -1 otherwise - * @throws NullPointerException if array is null - * @throws ArrayIndexOutOfBoundsException if endIndex is greater or equals to array length or starting is lower than 0 - */ -public static final int lastIndexOf( - char toBeFound, - char[] array, - int startIndex, - int endIndex) { - for (int i = endIndex; --i >= startIndex;) - if (toBeFound == array[i]) - return i; - return -1; -} - -/** - * Answers the last portion of a name given a separator. - *
- *
- * For example, - *
- * 	lastSegment("java.lang.Object".toCharArray(),'.') --> Object
- * 
- * - * @param array the array - * @param separator the given separator - * @return the last portion of a name given a separator - * @throws NullPointerException if array is null - */ -final static public char[] lastSegment(char[] array, char separator) { - int pos = lastIndexOf(separator, array); - if (pos < 0) - return array; - return subarray(array, pos + 1, array.length); -} - -/** - *

Answers true if the pattern matches the given name, false otherwise. This char[] pattern matching - * accepts wild-cards '*' and '?'.

- * - *

When not case sensitive, the pattern is assumed to already be lowercased, the - * name will be lowercased character per character as comparing.
- * If name is null, the answer is false.
- * If pattern is null, the answer is true if name is not null. - *

- * For example: - *
    - *
  1. - *    pattern = { '?', 'b', '*' }
    - *    name = { 'a', 'b', 'c' , 'd' }
    - *    isCaseSensitive = true
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    pattern = { '?', 'b', '?' }
    - *    name = { 'a', 'b', 'c' , 'd' }
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  4. - *
  5. - *    pattern = { 'b', '*' }
    - *    name = { 'a', 'b', 'c' , 'd' }
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  6. - *
- * - * @param pattern the given pattern - * @param name the given name - * @param isCaseSensitive flag to know whether or not the matching should be case sensitive - * @return true if the pattern matches the given name, false otherwise - */ -public static final boolean match( - char[] pattern, - char[] name, - boolean isCaseSensitive) { - - if (name == null) - return false; // null name cannot match - if (pattern == null) - return true; // null pattern is equivalent to '*' - - return match( - pattern, - 0, - pattern.length, - name, - 0, - name.length, - isCaseSensitive); -} - -/** - * Answers true if a sub-pattern matches the subpart of the given name, false otherwise. - * char[] pattern matching, accepting wild-cards '*' and '?'. Can match only subset of name/pattern. - * end positions are non-inclusive. - * The subpattern is defined by the patternStart and pattternEnd positions. - * When not case sensitive, the pattern is assumed to already be lowercased, the - * name will be lowercased character per character as comparing. - *
- *
- * For example: - *
    - *
  1. - *    pattern = { '?', 'b', '*' }
    - *    patternStart = 1
    - *    patternEnd = 3
    - *    name = { 'a', 'b', 'c' , 'd' }
    - *    nameStart = 1
    - *    nameEnd = 4
    - *    isCaseSensitive = true
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    pattern = { '?', 'b', '*' }
    - *    patternStart = 1
    - *    patternEnd = 2
    - *    name = { 'a', 'b', 'c' , 'd' }
    - *    nameStart = 1
    - *    nameEnd = 4
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  4. - *
- * - * @param pattern the given pattern - * @param patternStart the given pattern start - * @param patternEnd the given pattern end - * @param name the given name - * @param nameStart the given name start - * @param nameEnd the given name end - * @param isCaseSensitive flag to know if the matching should be case sensitive - * @return true if a sub-pattern matches the subpart of the given name, false otherwise - */ -public static final boolean match( - char[] pattern, - int patternStart, - int patternEnd, - char[] name, - int nameStart, - int nameEnd, - boolean isCaseSensitive) { - - if (name == null) - return false; // null name cannot match - if (pattern == null) - return true; // null pattern is equivalent to '*' - int iPattern = patternStart; - int iName = nameStart; - - if (patternEnd < 0) - patternEnd = pattern.length; - if (nameEnd < 0) - nameEnd = name.length; - - /* check first segment */ - char patternChar = 0; - while (true) { - if (iPattern == patternEnd) { - if (iName == nameEnd) return true; // the chars match - return false; // pattern has ended but not the name, no match - } - if ((patternChar = pattern[iPattern]) == '*') { - break; - } - if (iName == nameEnd) { - return false; // name has ended but not the pattern - } - if (patternChar - != (isCaseSensitive - ? name[iName] - : ScannerHelper.toLowerCase(name[iName])) - && patternChar != '?') { - return false; - } - iName++; - iPattern++; - } - /* check sequence of star+segment */ - int segmentStart; - if (patternChar == '*') { - segmentStart = ++iPattern; // skip star - } else { - segmentStart = 0; // force iName check - } - int prefixStart = iName; - checkSegment : while (iName < nameEnd) { - if (iPattern == patternEnd) { - iPattern = segmentStart; // mismatch - restart current segment - iName = ++prefixStart; - continue checkSegment; - } - /* segment is ending */ - if ((patternChar = pattern[iPattern]) == '*') { - segmentStart = ++iPattern; // skip start - if (segmentStart == patternEnd) { - return true; - } - prefixStart = iName; - continue checkSegment; - } - /* check current name character */ - if ((isCaseSensitive ? name[iName] : ScannerHelper.toLowerCase(name[iName])) - != patternChar - && patternChar != '?') { - iPattern = segmentStart; // mismatch - restart current segment - iName = ++prefixStart; - continue checkSegment; - } - iName++; - iPattern++; - } - - return (segmentStart == patternEnd) - || (iName == nameEnd && iPattern == patternEnd) - || (iPattern == patternEnd - 1 && pattern[iPattern] == '*'); -} - -/** - * Answers true if the pattern matches the filepath using the pathSepatator, false otherwise. - * - * Path char[] pattern matching, accepting wild-cards '**', '*' and '?' (using Ant directory tasks - * conventions, also see "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes"). - * Path pattern matching is enhancing regular pattern matching in supporting extra rule where '**' represent - * any folder combination. - * Special rule: - * - foo\ is equivalent to foo\** - * When not case sensitive, the pattern is assumed to already be lowercased, the - * name will be lowercased character per character as comparing. - * - * @param pattern the given pattern - * @param filepath the given path - * @param isCaseSensitive to find out whether or not the matching should be case sensitive - * @param pathSeparator the given path separator - * @return true if the pattern matches the filepath using the pathSepatator, false otherwise - */ -public static final boolean pathMatch( - char[] pattern, - char[] filepath, - boolean isCaseSensitive, - char pathSeparator) { - - if (filepath == null) - return false; // null name cannot match - if (pattern == null) - return true; // null pattern is equivalent to '*' - - // offsets inside pattern - int pSegmentStart = pattern[0] == pathSeparator ? 1 : 0; - int pLength = pattern.length; - int pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern, pSegmentStart+1); - if (pSegmentEnd < 0) pSegmentEnd = pLength; - - // special case: pattern foo\ is equivalent to foo\** - boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator; - - // offsets inside filepath - int fSegmentStart, fLength = filepath.length; - if (filepath[0] != pathSeparator){ - fSegmentStart = 0; - } else { - fSegmentStart = 1; - } - if (fSegmentStart != pSegmentStart) { - return false; // both must start with a separator or none. - } - int fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath, fSegmentStart+1); - if (fSegmentEnd < 0) fSegmentEnd = fLength; - - // first segments - while (pSegmentStart < pLength - && !(pSegmentEnd == pLength && freeTrailingDoubleStar - || (pSegmentEnd == pSegmentStart + 2 - && pattern[pSegmentStart] == '*' - && pattern[pSegmentStart + 1] == '*'))) { - - if (fSegmentStart >= fLength) - return false; - if (!CharOperation - .match( - pattern, - pSegmentStart, - pSegmentEnd, - filepath, - fSegmentStart, - fSegmentEnd, - isCaseSensitive)) { - return false; - } - - // jump to next segment - pSegmentEnd = - CharOperation.indexOf( - pathSeparator, - pattern, - pSegmentStart = pSegmentEnd + 1); - // skip separator - if (pSegmentEnd < 0) - pSegmentEnd = pLength; - - fSegmentEnd = - CharOperation.indexOf( - pathSeparator, - filepath, - fSegmentStart = fSegmentEnd + 1); - // skip separator - if (fSegmentEnd < 0) fSegmentEnd = fLength; - } - - /* check sequence of doubleStar+segment */ - int pSegmentRestart; - if ((pSegmentStart >= pLength && freeTrailingDoubleStar) - || (pSegmentEnd == pSegmentStart + 2 - && pattern[pSegmentStart] == '*' - && pattern[pSegmentStart + 1] == '*')) { - pSegmentEnd = - CharOperation.indexOf( - pathSeparator, - pattern, - pSegmentStart = pSegmentEnd + 1); - // skip separator - if (pSegmentEnd < 0) pSegmentEnd = pLength; - pSegmentRestart = pSegmentStart; - } else { - if (pSegmentStart >= pLength) return fSegmentStart >= fLength; // true if filepath is done too. - pSegmentRestart = 0; // force fSegmentStart check - } - int fSegmentRestart = fSegmentStart; - checkSegment : while (fSegmentStart < fLength) { - - if (pSegmentStart >= pLength) { - if (freeTrailingDoubleStar) return true; - // mismatch - restart current path segment - pSegmentEnd = - CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart); - if (pSegmentEnd < 0) pSegmentEnd = pLength; - - fSegmentRestart = - CharOperation.indexOf(pathSeparator, filepath, fSegmentRestart + 1); - // skip separator - if (fSegmentRestart < 0) { - fSegmentRestart = fLength; - } else { - fSegmentRestart++; - } - fSegmentEnd = - CharOperation.indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart); - if (fSegmentEnd < 0) fSegmentEnd = fLength; - continue checkSegment; - } - - /* path segment is ending */ - if (pSegmentEnd == pSegmentStart + 2 - && pattern[pSegmentStart] == '*' - && pattern[pSegmentStart + 1] == '*') { - pSegmentEnd = - CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentEnd + 1); - // skip separator - if (pSegmentEnd < 0) pSegmentEnd = pLength; - pSegmentRestart = pSegmentStart; - fSegmentRestart = fSegmentStart; - if (pSegmentStart >= pLength) return true; - continue checkSegment; - } - /* chech current path segment */ - if (!CharOperation.match( - pattern, - pSegmentStart, - pSegmentEnd, - filepath, - fSegmentStart, - fSegmentEnd, - isCaseSensitive)) { - // mismatch - restart current path segment - pSegmentEnd = - CharOperation.indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart); - if (pSegmentEnd < 0) pSegmentEnd = pLength; - - fSegmentRestart = - CharOperation.indexOf(pathSeparator, filepath, fSegmentRestart + 1); - // skip separator - if (fSegmentRestart < 0) { - fSegmentRestart = fLength; - } else { - fSegmentRestart++; - } - fSegmentEnd = - CharOperation.indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart); - if (fSegmentEnd < 0) fSegmentEnd = fLength; - continue checkSegment; - } - // jump to next segment - pSegmentEnd = - CharOperation.indexOf( - pathSeparator, - pattern, - pSegmentStart = pSegmentEnd + 1); - // skip separator - if (pSegmentEnd < 0) - pSegmentEnd = pLength; - - fSegmentEnd = - CharOperation.indexOf( - pathSeparator, - filepath, - fSegmentStart = fSegmentEnd + 1); - // skip separator - if (fSegmentEnd < 0) - fSegmentEnd = fLength; - } - - return (pSegmentRestart >= pSegmentEnd) - || (fSegmentStart >= fLength && pSegmentStart >= pLength) - || (pSegmentStart == pLength - 2 - && pattern[pSegmentStart] == '*' - && pattern[pSegmentStart + 1] == '*') - || (pSegmentStart == pLength && freeTrailingDoubleStar); -} - -/** - * Answers the number of occurrences of the given character in the given array, 0 if any. - * - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = 'b'
    - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    result => 3
    - * 
    - *
  2. - *
  3. - *    toBeFound = 'c'
    - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    result => 0
    - * 
    - *
  4. - *
- * - * @param toBeFound the given character - * @param array the given array - * @return the number of occurrences of the given character in the given array, 0 if any - * @throws NullPointerException if array is null - */ -public static final int occurencesOf(char toBeFound, char[] array) { - int count = 0; - for (int i = 0; i < array.length; i++) - if (toBeFound == array[i]) - count++; - return count; -} - -/** - * Answers the number of occurrences of the given character in the given array starting - * at the given index, 0 if any. - * - *
- *
- * For example: - *
    - *
  1. - *    toBeFound = 'b'
    - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    start = 2
    - *    result => 2
    - * 
    - *
  2. - *
  3. - *    toBeFound = 'c'
    - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    start = 0
    - *    result => 0
    - * 
    - *
  4. - *
- * - * @param toBeFound the given character - * @param array the given array - * @param start the given index - * @return the number of occurrences of the given character in the given array, 0 if any - * @throws NullPointerException if array is null - * @throws ArrayIndexOutOfBoundsException if start is lower than 0 - */ -public static final int occurencesOf( - char toBeFound, - char[] array, - int start) { - int count = 0; - for (int i = start; i < array.length; i++) - if (toBeFound == array[i]) - count++; - return count; -} -/** - * Return the int value represented by the designated subpart of array. The - * calculation of the result for single-digit positive integers is optimized in - * time. - * @param array the array within which the int value is to be parsed - * @param start first character of the int value in array - * @param length length of the int value in array - * @return the int value of a subpart of array - * @throws NumberFormatException if the designated subpart of array does not - * parse to an int - * @since 3.4 - */ -public static final int parseInt(char[] array, int start, int length) throws NumberFormatException { - if (length == 1) { - int result = array[start] - '0'; - if (result < 0 || result > 9) { - throw new NumberFormatException("invalid digit"); //$NON-NLS-1$ - } - return result; - } else { - return Integer.parseInt(new String(array, start, length)); - } -} -/** - * Answers true if the given name starts with the given prefix, false otherwise. - * The comparison is case sensitive. - *
- *
- * For example: - *
    - *
  1. - *    prefix = { 'a' , 'b' }
    - *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    prefix = { 'a' , 'c' }
    - *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    result => false
    - * 
    - *
  4. - *
- * - * @param prefix the given prefix - * @param name the given name - * @return true if the given name starts with the given prefix, false otherwise - * @throws NullPointerException if the given name is null or if the given prefix is null - */ -public static final boolean prefixEquals(char[] prefix, char[] name) { - - int max = prefix.length; - if (name.length < max) - return false; - for (int i = max; - --i >= 0; - ) // assumes the prefix is not larger than the name - if (prefix[i] != name[i]) - return false; - return true; -} - -/** - * Answers true if the given name starts with the given prefix, false otherwise. - * isCaseSensitive is used to find out whether or not the comparison should be case sensitive. - *
- *
- * For example: - *
    - *
  1. - *    prefix = { 'a' , 'B' }
    - *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    isCaseSensitive = false
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    prefix = { 'a' , 'B' }
    - *    name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  4. - *
- * - * @param prefix the given prefix - * @param name the given name - * @param isCaseSensitive to find out whether or not the comparison should be case sensitive - * @return true if the given name starts with the given prefix, false otherwise - * @throws NullPointerException if the given name is null or if the given prefix is null - */ -public static final boolean prefixEquals( - char[] prefix, - char[] name, - boolean isCaseSensitive) { - return prefixEquals(prefix, name, isCaseSensitive, 0); -} - -/** - * Answers true if the given name, starting from the given index, starts with the given prefix, - * false otherwise. isCaseSensitive is used to find out whether or not the comparison should be - * case sensitive. - *
- *
- * For example: - *
    - *
  1. - *    prefix = { 'a' , 'B' }
    - *    name = { 'c', 'd', 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    startIndex = 2
    - *    isCaseSensitive = false
    - *    result => true
    - * 
    - *
  2. - *
  3. - *    prefix = { 'a' , 'B' }
    - *    name = { 'c', 'd', 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    startIndex = 2
    - *    isCaseSensitive = true
    - *    result => false
    - * 
    - *
  4. - *
- * - * @param prefix the given prefix - * @param name the given name - * @param isCaseSensitive to find out whether or not the comparison should be case sensitive - * @param startIndex index from which the prefix should be searched in the name - * @return true if the given name starts with the given prefix, false otherwise - * @throws NullPointerException if the given name is null or if the given prefix is null - * @since 3.7 - */ -public static final boolean prefixEquals( - char[] prefix, - char[] name, - boolean isCaseSensitive, - int startIndex) { - - int max = prefix.length; - if (name.length - startIndex < max) - return false; - if (isCaseSensitive) { - for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name - if (prefix[i] != name[startIndex + i]) - return false; - return true; - } - - for (int i = max; --i >= 0;) // assumes the prefix is not larger than the name - if (ScannerHelper.toLowerCase(prefix[i]) - != ScannerHelper.toLowerCase(name[startIndex + i])) - return false; - return true; -} - -/** - * Answers a new array removing a given character. Answers the given array if there is - * no occurrence of the character to remove. - *
- *
- * For example: - *
    - *
  1. - *    array = { 'a' , 'b', 'b', 'c', 'b', 'a' }
    - *    toBeRemoved = 'b'
    - *    return { 'a' , 'c', 'a' }
    - * 
    - *
  2. - *
  3. - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    toBeRemoved = 'c'
    - *    return array
    - * 
    - *
  4. - *
- * - * @param array the given array - * @param toBeRemoved the character to be removed - * @return a new array removing given character - * @since 3.2 - */ -public static final char[] remove(char[] array, char toBeRemoved) { - - if (array == null) return null; - int length = array.length; - if (length == 0) return array; - char[] result = null; - int count = 0; - for (int i = 0; i < length; i++) { - char c = array[i]; - if (c == toBeRemoved) { - if (result == null) { - result = new char[length]; - System.arraycopy(array, 0, result, 0, i); - count = i; - } - } else if (result != null) { - result[count++] = c; - } - } - if (result == null) return array; - System.arraycopy(result, 0, result = new char[count], 0, count); - return result; -} - -/** - * Replace all occurrence of the character to be replaced with the replacement character in the - * given array. - *
- *
- * For example: - *
    - *
  1. - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    toBeReplaced = 'b'
    - *    replacementChar = 'a'
    - *    result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a' }
    - * 
    - *
  2. - *
  3. - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    toBeReplaced = 'c'
    - *    replacementChar = 'a'
    - *    result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - * 
    - *
  4. - *
- * - * @param array the given array - * @param toBeReplaced the character to be replaced - * @param replacementChar the replacement character - * @throws NullPointerException if the given array is null - */ -public static final void replace( - char[] array, - char toBeReplaced, - char replacementChar) { - if (toBeReplaced != replacementChar) { - for (int i = 0, max = array.length; i < max; i++) { - if (array[i] == toBeReplaced) - array[i] = replacementChar; - } - } -} - -/** - * Replace all occurrences of characters to be replaced with the replacement character in the - * given array. - *
- *
- * For example: - *
    - *
  1. - *    array = { 'a' , 'b', 'b', 'c', 'a', 'b', 'c', 'a' }
    - *    toBeReplaced = { 'b', 'c' }
    - *    replacementChar = 'a'
    - *    result => No returned value, but array is now equals to { 'a' , 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
    - * 
    - *
  2. - *
- * - * @param array the given array - * @param toBeReplaced characters to be replaced - * @param replacementChar the replacement character - * @throws NullPointerException if arrays are null. - * @since 3.1 - */ -public static final void replace(char[] array, char[] toBeReplaced, char replacementChar) { - replace(array, toBeReplaced, replacementChar, 0, array.length); -} - -/** - * Replace all occurrences of characters to be replaced with the replacement character in the - * given array from the start position (inclusive) to the end position (exclusive). - *
- *
- * For example: - *
    - *
  1. - *    array = { 'a' , 'b', 'b', 'c', 'a', 'b', 'c', 'a' }
    - *    toBeReplaced = { 'b', 'c' }
    - *    replacementChar = 'a'
    - *    start = 4
    - *    end = 8
    - *    result => No returned value, but array is now equals to { 'a' , 'b', 'b', 'c', 'a', 'a', 'a', 'a' }
    - * 
    - *
  2. - *
- * - * @param array the given array - * @param toBeReplaced characters to be replaced - * @param replacementChar the replacement character - * @param start the given start position (inclusive) - * @param end the given end position (exclusive) - * @throws NullPointerException if arrays are null. - * @since 3.2 - */ -public static final void replace(char[] array, char[] toBeReplaced, char replacementChar, int start, int end) { - for (int i = end; --i >= start;) - for (int j = toBeReplaced.length; --j >= 0;) - if (array[i] == toBeReplaced[j]) - array[i] = replacementChar; -} -/** - * Answers a new array of characters with substitutions. No side-effect is operated on the original - * array, in case no substitution happened, then the result is the same as the - * original one. - *
- *
- * For example: - *
    - *
  1. - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    toBeReplaced = { 'b' }
    - *    replacementChar = { 'a', 'a' }
    - *    result => { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
    - * 
    - *
  2. - *
  3. - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    toBeReplaced = { 'c' }
    - *    replacementChar = { 'a' }
    - *    result => { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - * 
    - *
  4. - *
- * - * @param array the given array - * @param toBeReplaced characters to be replaced - * @param replacementChars the replacement characters - * @return a new array of characters with substitutions or the given array if none - * @throws NullPointerException if the given array is null - */ -public static final char[] replace( - char[] array, - char[] toBeReplaced, - char[] replacementChars) { - - int max = array.length; - int replacedLength = toBeReplaced.length; - int replacementLength = replacementChars.length; - - int[] starts = new int[5]; - int occurrenceCount = 0; - - if (!equals(toBeReplaced, replacementChars)) { - - next : for (int i = 0; i < max;) { - int index = indexOf(toBeReplaced, array, true, i); - if (index == -1) { - i++; - continue next; - } - if (occurrenceCount == starts.length) { - System.arraycopy( - starts, - 0, - starts = new int[occurrenceCount * 2], - 0, - occurrenceCount); - } - starts[occurrenceCount++] = index; - i = index + replacedLength; - } - } - if (occurrenceCount == 0) - return array; - char[] result = - new char[max - + occurrenceCount * (replacementLength - replacedLength)]; - int inStart = 0, outStart = 0; - for (int i = 0; i < occurrenceCount; i++) { - int offset = starts[i] - inStart; - System.arraycopy(array, inStart, result, outStart, offset); - inStart += offset; - outStart += offset; - System.arraycopy( - replacementChars, - 0, - result, - outStart, - replacementLength); - inStart += replacedLength; - outStart += replacementLength; - } - System.arraycopy(array, inStart, result, outStart, max - inStart); - return result; -} - -/** - * Replace all occurrence of the character to be replaced with the replacement character - * in a copy of the given array. Returns the given array if no occurrences of the character - * to be replaced are found. - *
- *
- * For example: - *
    - *
  1. - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    toBeReplaced = 'b'
    - *    replacementChar = 'a'
    - *    result => A new array that is equals to { 'a' , 'a', 'a', 'a', 'a', 'a' }
    - * 
    - *
  2. - *
  3. - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    toBeReplaced = 'c'
    - *    replacementChar = 'a'
    - *    result => The original array that remains unchanged.
    - * 
    - *
  4. - *
- * - * @param array the given array - * @param toBeReplaced the character to be replaced - * @param replacementChar the replacement character - * @throws NullPointerException if the given array is null - * @since 3.1 - */ -public static final char[] replaceOnCopy( - char[] array, - char toBeReplaced, - char replacementChar) { - - char[] result = null; - for (int i = 0, length = array.length; i < length; i++) { - char c = array[i]; - if (c == toBeReplaced) { - if (result == null) { - result = new char[length]; - System.arraycopy(array, 0, result, 0, i); - } - result[i] = replacementChar; - } else if (result != null) { - result[i] = c; - } - } - if (result == null) return array; - return result; -} - -/** - * Return a new array which is the split of the given array using the given divider and trimming each subarray to remove - * whitespaces equals to ' '. - *
- *
- * For example: - *
    - *
  1. - *    divider = 'b'
    - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
    - * 
    - *
  2. - *
  3. - *    divider = 'c'
    - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
    - * 
    - *
  4. - *
  5. - *    divider = 'b'
    - *    array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' }
    - *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
    - * 
    - *
  6. - *
  7. - *    divider = 'c'
    - *    array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
    - *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
    - * 
    - *
  8. - *
- * - * @param divider the given divider - * @param array the given array - * @return a new array which is the split of the given array using the given divider and trimming each subarray to remove - * whitespaces equals to ' ' - */ -public static final char[][] splitAndTrimOn(char divider, char[] array) { - int length = array == null ? 0 : array.length; - if (length == 0) - return NO_CHAR_CHAR; - - int wordCount = 1; - for (int i = 0; i < length; i++) - if (array[i] == divider) - wordCount++; - char[][] split = new char[wordCount][]; - int last = 0, currentWord = 0; - for (int i = 0; i < length; i++) { - if (array[i] == divider) { - int start = last, end = i - 1; - while (start < i && array[start] == ' ') - start++; - while (end > start && array[end] == ' ') - end--; - split[currentWord] = new char[end - start + 1]; - System.arraycopy( - array, - start, - split[currentWord++], - 0, - end - start + 1); - last = i + 1; - } - } - int start = last, end = length - 1; - while (start < length && array[start] == ' ') - start++; - while (end > start && array[end] == ' ') - end--; - split[currentWord] = new char[end - start + 1]; - System.arraycopy( - array, - start, - split[currentWord++], - 0, - end - start + 1); - return split; -} - -/** - * Return a new array which is the split of the given array using the given divider. - *
- *
- * For example: - *
    - *
  1. - *    divider = 'b'
    - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    result => { { 'a' }, {  }, { 'a' }, { 'a' } }
    - * 
    - *
  2. - *
  3. - *    divider = 'c'
    - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
    - * 
    - *
  4. - *
  5. - *    divider = 'c'
    - *    array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
    - *    result => { { ' ', 'a', 'b', 'b', 'a', 'b', 'a', ' ' } }
    - * 
    - *
  6. - *
- * - * @param divider the given divider - * @param array the given array - * @return a new array which is the split of the given array using the given divider - */ -public static final char[][] splitOn(char divider, char[] array) { - int length = array == null ? 0 : array.length; - if (length == 0) - return NO_CHAR_CHAR; - - int wordCount = 1; - for (int i = 0; i < length; i++) - if (array[i] == divider) - wordCount++; - char[][] split = new char[wordCount][]; - int last = 0, currentWord = 0; - for (int i = 0; i < length; i++) { - if (array[i] == divider) { - split[currentWord] = new char[i - last]; - System.arraycopy( - array, - last, - split[currentWord++], - 0, - i - last); - last = i + 1; - } - } - split[currentWord] = new char[length - last]; - System.arraycopy(array, last, split[currentWord], 0, length - last); - return split; -} - -/** - * Return a new array which is the split of the given array using the given divider. The given end - * is exclusive and the given start is inclusive. - *
- *
- * For example: - *
    - *
  1. - *    divider = 'b'
    - *    array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
    - *    start = 2
    - *    end = 5
    - *    result => { {  }, { 'a' }, {  } }
    - * 
    - *
  2. - *
- * - * @param divider the given divider - * @param array the given array - * @param start the given starting index - * @param end the given ending index - * @return a new array which is the split of the given array using the given divider - * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length - */ -public static final char[][] splitOn( - char divider, - char[] array, - int start, - int end) { - int length = array == null ? 0 : array.length; - if (length == 0 || start > end) - return NO_CHAR_CHAR; - - int wordCount = 1; - for (int i = start; i < end; i++) - if (array[i] == divider) - wordCount++; - char[][] split = new char[wordCount][]; - int last = start, currentWord = 0; - for (int i = start; i < end; i++) { - if (array[i] == divider) { - split[currentWord] = new char[i - last]; - System.arraycopy( - array, - last, - split[currentWord++], - 0, - i - last); - last = i + 1; - } - } - split[currentWord] = new char[end - last]; - System.arraycopy(array, last, split[currentWord], 0, end - last); - return split; -} - -/** - * Return a new array which is the split of the given array using the given divider ignoring the - * text between (possibly nested) openEncl and closingEncl. If there are no openEncl in the code - * this is identical to {@link CharOperation#splitOn(char, char[], int, int)}. The given end - * is exclusive and the given start is inclusive. - *
- *
- * For example: - *
    - *
  1. - * {@code
    - *    divider = ','
    - *    array = { 'A' , '<', 'B', ',', 'C', '>', ',', 'D' }
    - *    start = 0
    - *    end = 8
    - *    result => { {  'A' , '<', 'B', ',', 'C', '>'}, { 'D' }}
    - * }
    - * 
    - *
  2. - *
- * - * @param divider the given divider - * @param openEncl the opening enclosure - * @param closeEncl the closing enclosure - * @param array the given array - * @param start the given starting index - * @param end the given ending index - * @return a new array which is the split of the given array using the given divider - * @throws ArrayIndexOutOfBoundsException if start is lower than 0 or end is greater than the array length - * @since 3.12 - */ -public static final char[][] splitOnWithEnclosures( - char divider, - char openEncl, - char closeEncl, - char[] array, - int start, - int end) { - int length = array == null ? 0 : array.length; - if (length == 0 || start > end) - return NO_CHAR_CHAR; - - int wordCount = 1; - int enclCount = 0; - for (int i = start; i < end; i++) { - if (array[i] == openEncl) - enclCount++; - else if (array[i] == divider) - wordCount++; - } - if (enclCount == 0) - return CharOperation.splitOn(divider, array, start, end); - - int nesting = 0; - if (openEncl == divider || closeEncl == divider) // divider should be distinct - return CharOperation.NO_CHAR_CHAR; - - int[][] splitOffsets = new int[wordCount][2]; //maximum - int last = start, currentWord = 0, prevOffset = start; - for (int i = start; i < end; i++) { - if (array[i] == openEncl) { - ++nesting; - continue; - } - if (array[i] == closeEncl) { - if (nesting > 0) - --nesting; - continue; - } - if (array[i] == divider && nesting == 0) { - splitOffsets[currentWord][0] = prevOffset; - last = splitOffsets[currentWord++][1] = i; - prevOffset = last + 1; - } - } - if (last < end - 1) { - splitOffsets[currentWord][0] = prevOffset; - splitOffsets[currentWord++][1] = end; - } - char[][] split = new char[currentWord][]; - for (int i = 0; i < currentWord; ++i) { - int sStart = splitOffsets[i][0]; - int sEnd = splitOffsets[i][1]; - int size = sEnd - sStart; - split[i] = new char[size]; - System.arraycopy(array, sStart, split[i], 0, size); - } - return split; - } - -/** - * Answers a new array which is a copy of the given array starting at the given start and - * ending at the given end. The given start is inclusive and the given end is exclusive. - * Answers null if start is greater than end, if start is lower than 0 or if end is greater - * than the length of the given array. If end equals -1, it is converted to the array length. - *
- *
- * For example: - *
    - *
  1. - *    array = { { 'a' } , { 'b' } }
    - *    start = 0
    - *    end = 1
    - *    result => { { 'a' } }
    - * 
    - *
  2. - *
  3. - *    array = { { 'a' } , { 'b' } }
    - *    start = 0
    - *    end = -1
    - *    result => { { 'a' }, { 'b' } }
    - * 
    - *
  4. - *
- * - * @param array the given array - * @param start the given starting index - * @param end the given ending index - * @return a new array which is a copy of the given array starting at the given start and - * ending at the given end - * @throws NullPointerException if the given array is null - */ -public static final char[][] subarray(char[][] array, int start, int end) { - if (end == -1) - end = array.length; - if (start > end) - return null; - if (start < 0) - return null; - if (end > array.length) - return null; - - char[][] result = new char[end - start][]; - System.arraycopy(array, start, result, 0, end - start); - return result; -} - -/** - * Answers a new array which is a copy of the given array starting at the given start and - * ending at the given end. The given start is inclusive and the given end is exclusive. - * Answers null if start is greater than end, if start is lower than 0 or if end is greater - * than the length of the given array. If end equals -1, it is converted to the array length. - *
- *
- * For example: - *
    - *
  1. - *    array = { 'a' , 'b' }
    - *    start = 0
    - *    end = 1
    - *    result => { 'a' }
    - * 
    - *
  2. - *
  3. - *    array = { 'a', 'b' }
    - *    start = 0
    - *    end = -1
    - *    result => { 'a' , 'b' }
    - * 
    - *
  4. - *
- * - * @param array the given array - * @param start the given starting index - * @param end the given ending index - * @return a new array which is a copy of the given array starting at the given start and - * ending at the given end - * @throws NullPointerException if the given array is null - */ -public static final char[] subarray(char[] array, int start, int end) { - if (end == -1) - end = array.length; - if (start > end) - return null; - if (start < 0) - return null; - if (end > array.length) - return null; - - char[] result = new char[end - start]; - System.arraycopy(array, start, result, 0, end - start); - return result; -} - -/** - * Answers the result of a char[] conversion to lowercase. Answers null if the given chars array is null. - *
- * NOTE: If no conversion was necessary, then answers back the argument one. - *
- *
- * For example: - *
    - *
  1. - *    chars = { 'a' , 'b' }
    - *    result => { 'a' , 'b' }
    - * 
    - *
  2. - *
  3. - *    array = { 'A', 'b' }
    - *    result => { 'a' , 'b' }
    - * 
    - *
  4. - *
- * - * @param chars the chars to convert - * @return the result of a char[] conversion to lowercase - */ -final static public char[] toLowerCase(char[] chars) { - if (chars == null) - return null; - int length = chars.length; - char[] lowerChars = null; - for (int i = 0; i < length; i++) { - char c = chars[i]; - char lc = ScannerHelper.toLowerCase(c); - if ((c != lc) || (lowerChars != null)) { - if (lowerChars == null) { - System.arraycopy( - chars, - 0, - lowerChars = new char[length], - 0, - i); - } - lowerChars[i] = lc; - } - } - return lowerChars == null ? chars : lowerChars; -} - -/** - * Answers the result of a char[] conversion to uppercase. Answers null if the given chars array is null. - *
- * NOTE: If no conversion was necessary, then answers back the argument one. - *
- *
- * For example: - *
    - *
  1. - *    chars = { 'A' , 'B' }
    - *    result => { 'A' , 'B' }
    - * 
    - *
  2. - *
  3. - *    array = { 'a', 'B' }
    - *    result => { 'A' , 'B' }
    - * 
    - *
  4. - *
- * - * @param chars the chars to convert - * @return the result of a char[] conversion to uppercase - * - * @since 3.5 - */ -final static public char[] toUpperCase(char[] chars) { - if (chars == null) - return null; - int length = chars.length; - char[] upperChars = null; - for (int i = 0; i < length; i++) { - char c = chars[i]; - char lc = ScannerHelper.toUpperCase(c); - if ((c != lc) || (upperChars != null)) { - if (upperChars == null) { - System.arraycopy( - chars, - 0, - upperChars = new char[length], - 0, - i); - } - upperChars[i] = lc; - } - } - return upperChars == null ? chars : upperChars; -} - -/** - * Answers a new array removing leading and trailing spaces (' '). Answers the given array if there is no - * space characters to remove. - *
- *
- * For example: - *
    - *
  1. - *    chars = { ' ', 'a' , 'b', ' ',  ' ' }
    - *    result => { 'a' , 'b' }
    - * 
    - *
  2. - *
  3. - *    array = { 'A', 'b' }
    - *    result => { 'A' , 'b' }
    - * 
    - *
  4. - *
- * - * @param chars the given array - * @return a new array removing leading and trailing spaces (' ') - */ -final static public char[] trim(char[] chars) { - - if (chars == null) - return null; - - int start = 0, length = chars.length, end = length - 1; - while (start < length && chars[start] == ' ') { - start++; - } - while (end > start && chars[end] == ' ') { - end--; - } - if (start != 0 || end != length - 1) { - return subarray(chars, start, end + 1); - } - return chars; -} - -/** - * Answers a string which is the concatenation of the given array using the '.' as a separator. - *
- *
- * For example: - *
    - *
  1. - *    array = { { 'a' } , { 'b' } }
    - *    result => "a.b"
    - * 
    - *
  2. - *
  3. - *    array = { { ' ',  'a' } , { 'b' } }
    - *    result => " a.b"
    - * 
    - *
  4. - *
- * - * @param array the given array - * @return a string which is the concatenation of the given array using the '.' as a separator - */ -final static public String toString(char[][] array) { - char[] result = concatWith(array, '.'); - return new String(result); -} - -/** - * Answers an array of strings from the given array of char array. - * - * @param array the given array - * @return an array of strings - * @since 3.0 - */ -final static public String[] toStrings(char[][] array) { - if (array == null) return NO_STRINGS; - int length = array.length; - if (length == 0) return NO_STRINGS; - String[] result = new String[length]; - for (int i = 0; i < length; i++) - result[i] = new String(array[i]); - return result; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/CompilationProgress.java b/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/CompilationProgress.java deleted file mode 100644 index a45cb69..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/CompilationProgress.java +++ /dev/null @@ -1,90 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.core.compiler; - -import org.eclipse.jdt.core.compiler.batch.BatchCompiler; - -/** - * A compilation progress is used by the {@link BatchCompiler} to report progress during compilation. - * It is also used to request cancellation of the compilation. - * Clients of the {@link BatchCompiler} should subclass this class, instantiate the subclass and pass this instance to - * {@link BatchCompiler#compile(String, java.io.PrintWriter, java.io.PrintWriter, CompilationProgress)}. - *

- * This class is intended to be instantiated and subclassed by clients. - *

- * - * @since 3.4 - */ - -public abstract class CompilationProgress { - - /** - * Notifies that the compilation is beginning. This is called exactly once per batch compilation. - * An estimated amount of remaining work is given. This amount will change as the compilation - * progresses. The new estimated amount of remaining work is reported using {@link #worked(int, int)}. - *

- * Clients should not call this method. - *

- * - * @param remainingWork the estimated amount of remaining work. - */ - public abstract void begin(int remainingWork); - - /** - * Notifies that the work is done; that is, either the compilation is completed - * or a cancellation was requested. This is called exactly once per batch compilation. - *

- * Clients should not call this method. - *

- */ - public abstract void done(); - - /** - * Returns whether cancellation of the compilation has been requested. - * - * @return true if cancellation has been requested, - * and false otherwise - */ - public abstract boolean isCanceled(); - - /** - * Reports the name (or description) of the current task. - *

- * Clients should not call this method. - *

- * - * @param name the name (or description) of the current task - */ - public abstract void setTaskName(String name); - - - /** - * Notifies that a given amount of work of the compilation - * has been completed. Note that this amount represents an - * installment, as opposed to a cumulative amount of work done - * to date. - * Also notifies an estimated amount of remaining work. Note that this - * amount of remaining work may be greater than the previous estimated - * amount as new compilation units are injected in the compile loop. - *

- * Clients should not call this method. - *

- * - * @param workIncrement a non-negative amount of work just completed - * @param remainingWork a non-negative amount of estimated remaining work - */ - public abstract void worked(int workIncrement, int remainingWork); - - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/IProblem.java b/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/IProblem.java deleted file mode 100644 index 6f36cbb..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/IProblem.java +++ /dev/null @@ -1,2595 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * IBM Corporation - added the following constants - * NonStaticAccessToStaticField - * NonStaticAccessToStaticMethod - * Task - * ExpressionShouldBeAVariable - * AssignmentHasNoEffect - * IBM Corporation - added the following constants - * TooManySyntheticArgumentSlots - * TooManyArrayDimensions - * TooManyBytesForStringConstant - * TooManyMethods - * TooManyFields - * NonBlankFinalLocalAssignment - * ObjectCannotHaveSuperTypes - * MissingSemiColon - * InvalidParenthesizedExpression - * EnclosingInstanceInConstructorCall - * BytecodeExceeds64KLimitForConstructor - * IncompatibleReturnTypeForNonInheritedInterfaceMethod - * UnusedPrivateMethod - * UnusedPrivateConstructor - * UnusedPrivateType - * UnusedPrivateField - * IncompatibleExceptionInThrowsClauseForNonInheritedInterfaceMethod - * InvalidExplicitConstructorCall - * IBM Corporation - added the following constants - * PossibleAccidentalBooleanAssignment - * SuperfluousSemicolon - * IndirectAccessToStaticField - * IndirectAccessToStaticMethod - * IndirectAccessToStaticType - * BooleanMethodThrowingException - * UnnecessaryCast - * UnnecessaryArgumentCast - * UnnecessaryInstanceof - * FinallyMustCompleteNormally - * UnusedMethodDeclaredThrownException - * UnusedConstructorDeclaredThrownException - * InvalidCatchBlockSequence - * UnqualifiedFieldAccess - * IBM Corporation - added the following constants - * Javadoc - * JavadocUnexpectedTag - * JavadocMissingParamTag - * JavadocMissingParamName - * JavadocDuplicateParamName - * JavadocInvalidParamName - * JavadocMissingReturnTag - * JavadocDuplicateReturnTag - * JavadocMissingThrowsTag - * JavadocMissingThrowsClassName - * JavadocInvalidThrowsClass - * JavadocDuplicateThrowsClassName - * JavadocInvalidThrowsClassName - * JavadocMissingSeeReference - * JavadocInvalidSeeReference - * JavadocInvalidSeeHref - * JavadocInvalidSeeArgs - * JavadocMissing - * JavadocInvalidTag - * JavadocMessagePrefix - * EmptyControlFlowStatement - * IBM Corporation - added the following constants - * IllegalUsageOfQualifiedTypeReference - * InvalidDigit - * IBM Corporation - added the following constants - * ParameterAssignment - * FallthroughCase - * IBM Corporation - added the following constants - * UnusedLabel - * UnnecessaryNLSTag - * LocalVariableMayBeNull - * EnumConstantsCannotBeSurroundedByParenthesis - * JavadocMissingIdentifier - * JavadocNonStaticTypeFromStaticInvocation - * RawTypeReference - * NoAdditionalBoundAfterTypeVariable - * UnsafeGenericArrayForVarargs - * IllegalAccessFromTypeVariable - * AnnotationValueMustBeArrayInitializer - * InvalidEncoding - * CannotReadSource - * EnumStaticFieldInInInitializerContext - * ExternalProblemNotFixable - * ExternalProblemFixable - * IBM Corporation - added the following constants - * AnnotationValueMustBeAnEnumConstant - * OverridingMethodWithoutSuperInvocation - * MethodMustOverrideOrImplement - * TypeHidingTypeParameterFromType - * TypeHidingTypeParameterFromMethod - * TypeHidingType - * IBM Corporation - added the following constants - * NullLocalVariableReference - * PotentialNullLocalVariableReference - * RedundantNullCheckOnNullLocalVariable - * NullLocalVariableComparisonYieldsFalse - * RedundantLocalVariableNullAssignment - * NullLocalVariableInstanceofYieldsFalse - * RedundantNullCheckOnNonNullLocalVariable - * NonNullLocalVariableComparisonYieldsFalse - * IBM Corporation - added the following constants - * InvalidUsageOfTypeParametersForAnnotationDeclaration - * InvalidUsageOfTypeParametersForEnumDeclaration - * IBM Corporation - added the following constants - * RedundantSuperinterface - * Benjamin Muskalla - added the following constants - * MissingSynchronizedModifierInInheritedMethod - * Stephan Herrmann - added the following constants - * UnusedObjectAllocation - * PotentiallyUnclosedCloseable - * PotentiallyUnclosedCloseableAtExit - * UnclosedCloseable - * UnclosedCloseableAtExit - * ExplicitlyClosedAutoCloseable - * RequiredNonNullButProvidedNull - * RequiredNonNullButProvidedPotentialNull - * RequiredNonNullButProvidedUnknown - * NullAnnotationNameMustBeQualified - * IllegalReturnNullityRedefinition - * IllegalRedefinitionToNonNullParameter - * IllegalDefinitionToNonNullParameter - * ParameterLackingNonNullAnnotation - * ParameterLackingNullableAnnotation - * PotentialNullMessageSendReference - * RedundantNullCheckOnNonNullMessageSend - * CannotImplementIncompatibleNullness - * RedundantNullAnnotation - * RedundantNullDefaultAnnotation - * RedundantNullDefaultAnnotationPackage - * RedundantNullDefaultAnnotationType - * RedundantNullDefaultAnnotationMethod - * ContradictoryNullAnnotations - * IllegalAnnotationForBaseType - * RedundantNullCheckOnSpecdNonNullLocalVariable - * SpecdNonNullLocalVariableComparisonYieldsFalse - * RequiredNonNullButProvidedSpecdNullable - * MissingDefaultCase - * MissingEnumConstantCaseDespiteDefault - * UninitializedLocalVariableHintMissingDefault - * UninitializedBlankFinalFieldHintMissingDefault - * ShouldReturnValueHintMissingDefault - * IllegalModifierForInterfaceDefaultMethod - * InheritedDefaultMethodConflictsWithOtherInherited - * ConflictingNullAnnotations - * ConflictingInheritedNullAnnotations - * UnsafeElementTypeConversion - * ArrayReferencePotentialNullReference - * DereferencingNullableExpression - * NullityMismatchingTypeAnnotation - * NullityMismatchingTypeAnnotationSuperHint - * NullityUncheckedTypeAnnotationDetail - * NullityUncheckedTypeAnnotationDetailSuperHint - * NullableFieldReference - * UninitializedNonNullField - * UninitializedNonNullFieldHintMissingDefault - * NonNullMessageSendComparisonYieldsFalse - * RedundantNullCheckOnNonNullSpecdField - * NonNullSpecdFieldComparisonYieldsFalse - * NonNullExpressionComparisonYieldsFalse - * RedundantNullCheckOnNonNullExpression - * ReferenceExpressionParameterNullityMismatch - * ReferenceExpressionParameterNullityUnchecked - * ReferenceExpressionReturnNullRedef - * ReferenceExpressionReturnNullRedefUnchecked - * DuplicateInheritedDefaultMethods - * SuperAccessCannotBypassDirectSuper - * SuperCallCannotBypassOverride - * ConflictingNullAnnotations - * ConflictingInheritedNullAnnotations - * UnsafeElementTypeConversion - * PotentialNullUnboxing - * NullUnboxing - * NullExpressionReference - * PotentialNullExpressionReference - * RedundantNullCheckAgainstNonNullType - * NullAnnotationUnsupportedLocation - * NullAnnotationUnsupportedLocationAtType - * NullityMismatchTypeArgument - * ContradictoryNullAnnotationsOnBound - * UnsafeNullnessCast - * ContradictoryNullAnnotationsInferred - * NonNullDefaultDetailIsNotEvaluated - * NullNotCompatibleToFreeTypeVariable - * NullityMismatchAgainstFreeTypeVariable - * ImplicitObjectBoundNoNullDefault - * IllegalParameterNullityRedefinition - * ContradictoryNullAnnotationsInferredFunctionType - * IllegalReturnNullityRedefinitionFreeTypeVariable - * UnlikelyCollectionMethodArgumentType - * UnlikelyEqualsArgumentType - * Jesper S Moller - added the following constants - * TargetTypeNotAFunctionalInterface - * OuterLocalMustBeEffectivelyFinal - * IllegalModifiersForPackage - * DuplicateAnnotationNotMarkedRepeatable - * DisallowedTargetForContainerAnnotation - * RepeatedAnnotationWithContainerAnnotation - * ContainingAnnotationMustHaveValue - * ContainingAnnotationHasNonDefaultMembers - * ContainingAnnotationHasWrongValueType - * ContainingAnnotationHasShorterRetention - * RepeatableAnnotationHasTargets - * RepeatableAnnotationTargetMismatch - * RepeatableAnnotationIsDocumented - * RepeatableAnnotationIsInherited - * RepeatableAnnotationWithRepeatingContainerAnnotation - * VarLocalMultipleDeclarators - * VarLocalCannotBeArray - * VarLocalReferencesItself - * VarLocalWithoutInitizalier - * VarLocalInitializedToNull - * VarLocalCannotBeArrayInitalizers - * VarLocalCannotBeLambda - * VarLocalCannotBeMethodReference - * VarIsReserved - * VarIsReservedInFuture - * VarIsNotAllowedHere -******************************************************************************/ -package org.eclipse.jdt.core.compiler; - -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; - -/** - * Description of a Java problem, as detected by the compiler or some of the underlying - * technology reusing the compiler. - * A problem provides access to: - *
    - *
  • its location (originating source file name, source position, line number)
  • - *
  • its message description
  • - *
  • predicates to check its severity (error, warning, or info)
  • - *
  • its ID : a number identifying the very nature of this problem. All possible IDs are listed - * as constants on this interface.
  • - *
- * - * Note: the compiler produces IProblems internally, which are turned into markers by the JavaBuilder - * so as to persist problem descriptions. This explains why there is no API allowing to reach IProblem detected - * when compiling. However, the Java problem markers carry equivalent information to IProblem, in particular - * their ID (attribute "id") is set to one of the IDs defined on this interface. - * - * @since 2.0 - * @noimplement This interface is not intended to be implemented by clients. - * @noextend This interface is not intended to be extended by clients. - */ -public interface IProblem { - -/** - * Answer back the original arguments recorded into the problem. - * @return the original arguments recorded into the problem - */ -String[] getArguments(); - -/** - * Returns the problem id - * - * @return the problem id - */ -int getID(); - -/** - * Answer a localized, human-readable message string which describes the problem. - * - * @return a localized, human-readable message string which describes the problem - */ -String getMessage(); - -/** - * Answer the file name in which the problem was found. - * - * @return the file name in which the problem was found - */ -char[] getOriginatingFileName(); - -/** - * Answer the end position of the problem (inclusive), or -1 if unknown. - * - * @return the end position of the problem (inclusive), or -1 if unknown - */ -int getSourceEnd(); - -/** - * Answer the line number in source where the problem begins. - * - * @return the line number in source where the problem begins - */ -int getSourceLineNumber(); - -/** - * Answer the start position of the problem (inclusive), or -1 if unknown. - * - * @return the start position of the problem (inclusive), or -1 if unknown - */ -int getSourceStart(); - -/** - * Returns whether the severity of this problem is 'Error'. - * - * @return true if the severity of this problem is 'Error', false otherwise - */ -boolean isError(); - -/** - * Returns whether the severity of this problem is 'Warning'. - * - * @return true if the severity of this problem is 'Warning', false otherwise - */ -boolean isWarning(); - -/** - * Returns whether the severity of this problem is 'Info'. - * - * @return true if the severity of this problem is 'Info', false otherwise - * @since 3.12 - */ -boolean isInfo(); - -/** - * Set the end position of the problem (inclusive), or -1 if unknown. - * Used for shifting problem positions. - * - * @param sourceEnd the given end position - */ -void setSourceEnd(int sourceEnd); - -/** - * Set the line number in source where the problem begins. - * - * @param lineNumber the given line number - */ -void setSourceLineNumber(int lineNumber); - -/** - * Set the start position of the problem (inclusive), or -1 if unknown. - * Used for shifting problem positions. - * - * @param sourceStart the given start position - */ -void setSourceStart(int sourceStart); - - - /** - * Problem Categories - * The high bits of a problem ID contains information about the category of a problem. - * For example, (problemID & TypeRelated) != 0, indicates that this problem is type related. - * - * A problem category can help to implement custom problem filters. Indeed, when numerous problems - * are listed, focusing on import related problems first might be relevant. - * - * When a problem is tagged as Internal, it means that no change other than a local source code change - * can fix the corresponding problem. A type related problem could be addressed by changing the type - * involved in it. - */ - int TypeRelated = 0x01000000; - int FieldRelated = 0x02000000; - int MethodRelated = 0x04000000; - int ConstructorRelated = 0x08000000; - int ImportRelated = 0x10000000; - int Internal = 0x20000000; - int Syntax = 0x40000000; - /** @since 3.0 */ - int Javadoc = 0x80000000; - /** @since 3.14 */ - int ModuleRelated = 0x00800000; - /** @since 3.18 */ - int Compliance = 0x00400000; - /** @since 3.20 */ - int PreviewRelated = 0x00200000; - - /** - * Mask to use in order to filter out the category portion of the problem ID. - */ - int IgnoreCategoriesMask = 0x1FFFFF; - - /* - * Below are listed all available problem IDs. Note that this list could be augmented in the future, - * as new features are added to the Java core implementation. - * - * Problem IDs must be kept unique even when their mask is stripped, since - * the bare integer literal is used for message lookup in - * /org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties. - * Use this regex to find duplicates: (?s)(\+ \d+)\b.*\1\b - */ - - /** - * ID reserved for referencing an internal error inside the JavaCore implementation which - * may be surfaced as a problem associated with the compilation unit which caused it to occur. - */ - int Unclassified = 0; - - /** - * General type related problems - */ - int ObjectHasNoSuperclass = TypeRelated + 1; - int UndefinedType = TypeRelated + 2; - int NotVisibleType = TypeRelated + 3; - int AmbiguousType = TypeRelated + 4; - int UsingDeprecatedType = TypeRelated + 5; - int InternalTypeNameProvided = TypeRelated + 6; - /** @since 2.1 */ - int UnusedPrivateType = Internal + TypeRelated + 7; - - int IncompatibleTypesInEqualityOperator = TypeRelated + 15; - int IncompatibleTypesInConditionalOperator = TypeRelated + 16; - int TypeMismatch = TypeRelated + 17; - /** @since 3.0 */ - int IndirectAccessToStaticType = Internal + TypeRelated + 18; - - /** @since 3.10 */ - int ReturnTypeMismatch = TypeRelated + 19; - - /** - * Inner types related problems - */ - int MissingEnclosingInstanceForConstructorCall = TypeRelated + 20; - int MissingEnclosingInstance = TypeRelated + 21; - int IncorrectEnclosingInstanceReference = TypeRelated + 22; - int IllegalEnclosingInstanceSpecification = TypeRelated + 23; - int CannotDefineStaticInitializerInLocalType = Internal + 24; - int OuterLocalMustBeFinal = Internal + 25; - int CannotDefineInterfaceInLocalType = Internal + 26; - int IllegalPrimitiveOrArrayTypeForEnclosingInstance = TypeRelated + 27; - /** @since 2.1 */ - int EnclosingInstanceInConstructorCall = Internal + 28; - int AnonymousClassCannotExtendFinalClass = TypeRelated + 29; - /** @since 3.1 */ - int CannotDefineAnnotationInLocalType = Internal + 30; - /** @since 3.1 */ - int CannotDefineEnumInLocalType = Internal + 31; - /** @since 3.1 */ - int NonStaticContextForEnumMemberType = Internal + 32; - /** @since 3.3 */ - int TypeHidingType = TypeRelated + 33; - /** @since 3.11 */ - int NotAnnotationType = TypeRelated + 34; - - // variables - int UndefinedName = Internal + FieldRelated + 50; - int UninitializedLocalVariable = Internal + 51; - int VariableTypeCannotBeVoid = Internal + 52; - /** @deprecated - problem is no longer generated, use {@link #CannotAllocateVoidArray} instead */ - int VariableTypeCannotBeVoidArray = Internal + 53; - int CannotAllocateVoidArray = Internal + 54; - // local variables - int RedefinedLocal = Internal + 55; - int RedefinedArgument = Internal + 56; - // final local variables - int DuplicateFinalLocalInitialization = Internal + 57; - /** @since 2.1 */ - int NonBlankFinalLocalAssignment = Internal + 58; - /** @since 3.2 */ - int ParameterAssignment = Internal + 59; - int FinalOuterLocalAssignment = Internal + 60; - int LocalVariableIsNeverUsed = Internal + 61; - int ArgumentIsNeverUsed = Internal + 62; - int BytecodeExceeds64KLimit = Internal + 63; - int BytecodeExceeds64KLimitForClinit = Internal + 64; - int TooManyArgumentSlots = Internal + 65; - int TooManyLocalVariableSlots = Internal + 66; - /** @since 2.1 */ - int TooManySyntheticArgumentSlots = Internal + 67; - /** @since 2.1 */ - int TooManyArrayDimensions = Internal + 68; - /** @since 2.1 */ - int BytecodeExceeds64KLimitForConstructor = Internal + 69; - - // fields - int UndefinedField = FieldRelated + 70; - int NotVisibleField = FieldRelated + 71; - int AmbiguousField = FieldRelated + 72; - int UsingDeprecatedField = FieldRelated + 73; - int NonStaticFieldFromStaticInvocation = FieldRelated + 74; - int ReferenceToForwardField = FieldRelated + Internal + 75; - /** @since 2.1 */ - int NonStaticAccessToStaticField = Internal + FieldRelated + 76; - /** @since 2.1 */ - int UnusedPrivateField = Internal + FieldRelated + 77; - /** @since 3.0 */ - int IndirectAccessToStaticField = Internal + FieldRelated + 78; - /** @since 3.0 */ - int UnqualifiedFieldAccess = Internal + FieldRelated + 79; - int FinalFieldAssignment = FieldRelated + 80; - int UninitializedBlankFinalField = FieldRelated + 81; - int DuplicateBlankFinalFieldInitialization = FieldRelated + 82; - /** @since 3.6 */ - int UnresolvedVariable = FieldRelated + 83; - /** @since 3.10 */ - int NonStaticOrAlienTypeReceiver = MethodRelated + 84; - - /** @since 3.11 */ - int ExceptionParameterIsNeverUsed = Internal + 85; - /** @since 3.17 */ - int BytecodeExceeds64KLimitForSwitchTable = Internal + 86; - - // variable hiding - /** @since 3.0 */ - int LocalVariableHidingLocalVariable = Internal + 90; - /** @since 3.0 */ - int LocalVariableHidingField = Internal + FieldRelated + 91; - /** @since 3.0 */ - int FieldHidingLocalVariable = Internal + FieldRelated + 92; - /** @since 3.0 */ - int FieldHidingField = Internal + FieldRelated + 93; - /** @since 3.0 */ - int ArgumentHidingLocalVariable = Internal + 94; - /** @since 3.0 */ - int ArgumentHidingField = Internal + 95; - /** @since 3.1 */ - int MissingSerialVersion = Internal + 96; - /** @since 3.10 */ - int LambdaRedeclaresArgument = Internal + 97; - /** @since 3.10 */ - int LambdaRedeclaresLocal = Internal + 98; - /** @since 3.10 */ - int LambdaDescriptorMentionsUnmentionable = 99; - - // methods - int UndefinedMethod = MethodRelated + 100; - int NotVisibleMethod = MethodRelated + 101; - int AmbiguousMethod = MethodRelated + 102; - int UsingDeprecatedMethod = MethodRelated + 103; - int DirectInvocationOfAbstractMethod = MethodRelated + 104; - int VoidMethodReturnsValue = MethodRelated + 105; - int MethodReturnsVoid = MethodRelated + 106; - int MethodRequiresBody = Internal + MethodRelated + 107; - int ShouldReturnValue = Internal + MethodRelated + 108; - int MethodButWithConstructorName = MethodRelated + 110; - int MissingReturnType = TypeRelated + 111; - int BodyForNativeMethod = Internal + MethodRelated + 112; - int BodyForAbstractMethod = Internal + MethodRelated + 113; - int NoMessageSendOnBaseType = MethodRelated + 114; - int ParameterMismatch = MethodRelated + 115; - int NoMessageSendOnArrayType = MethodRelated + 116; - /** @since 2.1 */ - int NonStaticAccessToStaticMethod = Internal + MethodRelated + 117; - /** @since 2.1 */ - int UnusedPrivateMethod = Internal + MethodRelated + 118; - /** @since 3.0 */ - int IndirectAccessToStaticMethod = Internal + MethodRelated + 119; - /** @since 3.4 */ - int MissingTypeInMethod = MethodRelated + 120; - /** @since 3.7 */ - int MethodCanBeStatic = Internal + MethodRelated + 121; - /** @since 3.7 */ - int MethodCanBePotentiallyStatic = Internal + MethodRelated + 122; - /** @since 3.10 */ - int MethodReferenceSwingsBothWays = Internal + MethodRelated + 123; - /** @since 3.10 */ - int StaticMethodShouldBeAccessedStatically = Internal + MethodRelated + 124; - /** @since 3.10 */ - int InvalidArrayConstructorReference = Internal + MethodRelated + 125; - /** @since 3.10 */ - int ConstructedArrayIncompatible = Internal + MethodRelated + 126; - /** @since 3.10 */ - int DanglingReference = Internal + MethodRelated + 127; - /** @since 3.10 */ - int IncompatibleMethodReference = Internal + MethodRelated + 128; - - // constructors - /** @since 3.4 */ - int MissingTypeInConstructor = ConstructorRelated + 129; - int UndefinedConstructor = ConstructorRelated + 130; - int NotVisibleConstructor = ConstructorRelated + 131; - int AmbiguousConstructor = ConstructorRelated + 132; - int UsingDeprecatedConstructor = ConstructorRelated + 133; - /** @since 2.1 */ - int UnusedPrivateConstructor = Internal + MethodRelated + 134; - // explicit constructor calls - int InstanceFieldDuringConstructorInvocation = ConstructorRelated + 135; - int InstanceMethodDuringConstructorInvocation = ConstructorRelated + 136; - int RecursiveConstructorInvocation = ConstructorRelated + 137; - int ThisSuperDuringConstructorInvocation = ConstructorRelated + 138; - /** @since 3.0 */ - int InvalidExplicitConstructorCall = ConstructorRelated + Syntax + 139; - // implicit constructor calls - int UndefinedConstructorInDefaultConstructor = ConstructorRelated + 140; - int NotVisibleConstructorInDefaultConstructor = ConstructorRelated + 141; - int AmbiguousConstructorInDefaultConstructor = ConstructorRelated + 142; - int UndefinedConstructorInImplicitConstructorCall = ConstructorRelated + 143; - int NotVisibleConstructorInImplicitConstructorCall = ConstructorRelated + 144; - int AmbiguousConstructorInImplicitConstructorCall = ConstructorRelated + 145; - int UnhandledExceptionInDefaultConstructor = TypeRelated + 146; - int UnhandledExceptionInImplicitConstructorCall = TypeRelated + 147; - - // expressions - /** @since 3.6 */ - int UnusedObjectAllocation = Internal + 148; - /** @since 3.5 */ - int DeadCode = Internal + 149; - int ArrayReferenceRequired = Internal + 150; - int NoImplicitStringConversionForCharArrayExpression = Internal + 151; - // constant expressions - int StringConstantIsExceedingUtf8Limit = Internal + 152; - int NonConstantExpression = Internal + 153; - int NumericValueOutOfRange = Internal + 154; - // cast expressions - int IllegalCast = TypeRelated + 156; - // allocations - int InvalidClassInstantiation = TypeRelated + 157; - int CannotDefineDimensionExpressionsWithInit = Internal + 158; - int MustDefineEitherDimensionExpressionsOrInitializer = Internal + 159; - // operators - int InvalidOperator = Internal + 160; - // statements - int CodeCannotBeReached = Internal + 161; - int CannotReturnInInitializer = Internal + 162; - int InitializerMustCompleteNormally = Internal + 163; - // assert - int InvalidVoidExpression = Internal + 164; - // try - int MaskedCatch = TypeRelated + 165; - int DuplicateDefaultCase = Internal + 166; - int UnreachableCatch = TypeRelated + MethodRelated + 167; - int UnhandledException = TypeRelated + 168; - // switch - int IncorrectSwitchType = TypeRelated + 169; - int DuplicateCase = FieldRelated + 170; - - // labelled - int DuplicateLabel = Internal + 171; - int InvalidBreak = Internal + 172; - int InvalidContinue = Internal + 173; - int UndefinedLabel = Internal + 174; - //synchronized - int InvalidTypeToSynchronized = Internal + 175; - int InvalidNullToSynchronized = Internal + 176; - // throw - int CannotThrowNull = Internal + 177; - // assignment - /** @since 2.1 */ - int AssignmentHasNoEffect = Internal + 178; - /** @since 3.0 */ - int PossibleAccidentalBooleanAssignment = Internal + 179; - /** @since 3.0 */ - int SuperfluousSemicolon = Internal + 180; - /** @since 3.0 */ - int UnnecessaryCast = Internal + TypeRelated + 181; - /** @deprecated - no longer generated, use {@link #UnnecessaryCast} instead - * @since 3.0 */ - int UnnecessaryArgumentCast = Internal + TypeRelated + 182; - /** @since 3.0 */ - int UnnecessaryInstanceof = Internal + TypeRelated + 183; - /** @since 3.0 */ - int FinallyMustCompleteNormally = Internal + 184; - /** @since 3.0 */ - int UnusedMethodDeclaredThrownException = Internal + 185; - /** @since 3.0 */ - int UnusedConstructorDeclaredThrownException = Internal + 186; - /** @since 3.0 */ - int InvalidCatchBlockSequence = Internal + TypeRelated + 187; - /** @since 3.0 */ - int EmptyControlFlowStatement = Internal + TypeRelated + 188; - /** @since 3.0 */ - int UnnecessaryElse = Internal + 189; - - // inner emulation - int NeedToEmulateFieldReadAccess = FieldRelated + 190; - int NeedToEmulateFieldWriteAccess = FieldRelated + 191; - int NeedToEmulateMethodAccess = MethodRelated + 192; - int NeedToEmulateConstructorAccess = MethodRelated + 193; - - /** @since 3.2 */ - int FallthroughCase = Internal + 194; - - //inherited name hides enclosing name (sort of ambiguous) - int InheritedMethodHidesEnclosingName = MethodRelated + 195; - int InheritedFieldHidesEnclosingName = FieldRelated + 196; - int InheritedTypeHidesEnclosingName = TypeRelated + 197; - - /** @since 3.1 */ - int IllegalUsageOfQualifiedTypeReference = Internal + Syntax + 198; - - // miscellaneous - /** @since 3.2 */ - int UnusedLabel = Internal + 199; - int ThisInStaticContext = Internal + 200; - int StaticMethodRequested = Internal + MethodRelated + 201; - int IllegalDimension = Internal + 202; - /** @deprecated - problem is no longer generated */ - int InvalidTypeExpression = Internal + 203; - int ParsingError = Syntax + Internal + 204; - int ParsingErrorNoSuggestion = Syntax + Internal + 205; - int InvalidUnaryExpression = Syntax + Internal + 206; - - // syntax errors - int InterfaceCannotHaveConstructors = Syntax + Internal + 207; - int ArrayConstantsOnlyInArrayInitializers = Syntax + Internal + 208; - int ParsingErrorOnKeyword = Syntax + Internal + 209; - int ParsingErrorOnKeywordNoSuggestion = Syntax + Internal + 210; - - /** @since 3.5 */ - int ComparingIdentical = Internal + 211; - - /** @since 3.22 - * @noreference preview feature error */ - int UnsafeCast = TypeRelated + 212; - - int UnmatchedBracket = Syntax + Internal + 220; - int NoFieldOnBaseType = FieldRelated + 221; - int InvalidExpressionAsStatement = Syntax + Internal + 222; - /** @since 2.1 */ - int ExpressionShouldBeAVariable = Syntax + Internal + 223; - /** @since 2.1 */ - int MissingSemiColon = Syntax + Internal + 224; - /** @since 2.1 */ - int InvalidParenthesizedExpression = Syntax + Internal + 225; - - /** @since 3.10 */ - int NoSuperInInterfaceContext = Syntax + Internal + 226; - - /** @since 3.0 */ - int ParsingErrorInsertTokenBefore = Syntax + Internal + 230; - /** @since 3.0 */ - int ParsingErrorInsertTokenAfter = Syntax + Internal + 231; - /** @since 3.0 */ - int ParsingErrorDeleteToken = Syntax + Internal + 232; - /** @since 3.0 */ - int ParsingErrorDeleteTokens = Syntax + Internal + 233; - /** @since 3.0 */ - int ParsingErrorMergeTokens = Syntax + Internal + 234; - /** @since 3.0 */ - int ParsingErrorInvalidToken = Syntax + Internal + 235; - /** @since 3.0 */ - int ParsingErrorMisplacedConstruct = Syntax + Internal + 236; - /** @since 3.0 */ - int ParsingErrorReplaceTokens = Syntax + Internal + 237; - /** @since 3.0 */ - int ParsingErrorNoSuggestionForTokens = Syntax + Internal + 238; - /** @since 3.0 */ - int ParsingErrorUnexpectedEOF = Syntax + Internal + 239; - /** @since 3.0 */ - int ParsingErrorInsertToComplete = Syntax + Internal + 240; - /** @since 3.0 */ - int ParsingErrorInsertToCompleteScope = Syntax + Internal + 241; - /** @since 3.0 */ - int ParsingErrorInsertToCompletePhrase = Syntax + Internal + 242; - - // scanner errors - int EndOfSource = Syntax + Internal + 250; - int InvalidHexa = Syntax + Internal + 251; - int InvalidOctal = Syntax + Internal + 252; - int InvalidCharacterConstant = Syntax + Internal + 253; - int InvalidEscape = Syntax + Internal + 254; - int InvalidInput = Syntax + Internal + 255; - int InvalidUnicodeEscape = Syntax + Internal + 256; - int InvalidFloat = Syntax + Internal + 257; - int NullSourceString = Syntax + Internal + 258; - int UnterminatedString = Syntax + Internal + 259; - int UnterminatedComment = Syntax + Internal + 260; - int NonExternalizedStringLiteral = Internal + 261; - /** @since 3.1 */ - int InvalidDigit = Syntax + Internal + 262; - /** @since 3.1 */ - int InvalidLowSurrogate = Syntax + Internal + 263; - /** @since 3.1 */ - int InvalidHighSurrogate = Syntax + Internal + 264; - /** @since 3.2 */ - int UnnecessaryNLSTag = Internal + 265; - /** @since 3.7.1 */ - int InvalidBinary = Syntax + Internal + 266; - /** @since 3.7.1 */ - int BinaryLiteralNotBelow17 = Syntax + Internal + 267; - /** @since 3.7.1 */ - int IllegalUnderscorePosition = Syntax + Internal + 268; - /** @since 3.7.1 */ - int UnderscoresInLiteralsNotBelow17 = Syntax + Internal + 269; - /** @since 3.7.1 */ - int IllegalHexaLiteral = Syntax + Internal + 270; - - /** @since 3.10 */ - int MissingTypeInLambda = MethodRelated + 271; - /** @since 3.23 */ - int UnterminatedTextBlock = PreviewRelated + 272; - // type related problems - /** @since 3.1 */ - int DiscouragedReference = TypeRelated + 280; - - int InterfaceCannotHaveInitializers = TypeRelated + 300; - int DuplicateModifierForType = TypeRelated + 301; - int IllegalModifierForClass = TypeRelated + 302; - int IllegalModifierForInterface = TypeRelated + 303; - int IllegalModifierForMemberClass = TypeRelated + 304; - int IllegalModifierForMemberInterface = TypeRelated + 305; - int IllegalModifierForLocalClass = TypeRelated + 306; - /** @since 3.1 */ - int ForbiddenReference = TypeRelated + 307; - int IllegalModifierCombinationFinalAbstractForClass = TypeRelated + 308; - int IllegalVisibilityModifierForInterfaceMemberType = TypeRelated + 309; - int IllegalVisibilityModifierCombinationForMemberType = TypeRelated + 310; - int IllegalStaticModifierForMemberType = TypeRelated + 311; - int SuperclassMustBeAClass = TypeRelated + 312; - int ClassExtendFinalClass = TypeRelated + 313; - int DuplicateSuperInterface = TypeRelated + 314; - int SuperInterfaceMustBeAnInterface = TypeRelated + 315; - int HierarchyCircularitySelfReference = TypeRelated + 316; - int HierarchyCircularity = TypeRelated + 317; - int HidingEnclosingType = TypeRelated + 318; - int DuplicateNestedType = TypeRelated + 319; - int CannotThrowType = TypeRelated + 320; - int PackageCollidesWithType = TypeRelated + 321; - int TypeCollidesWithPackage = TypeRelated + 322; - int DuplicateTypes = TypeRelated + 323; - int IsClassPathCorrect = TypeRelated + 324; // see also IsClasspathCorrectWithReferencingType below - int PublicClassMustMatchFileName = TypeRelated + 325; - /** @deprecated - problem is no longer generated */ - int MustSpecifyPackage = Internal + 326; - int HierarchyHasProblems = TypeRelated + 327; - int PackageIsNotExpectedPackage = Internal + 328; - /** @since 2.1 */ - int ObjectCannotHaveSuperTypes = Internal + 329; - /** @since 3.1 */ - int ObjectMustBeClass = Internal + 330; - /** @since 3.4 */ - int RedundantSuperinterface = TypeRelated + 331; - /** @since 3.5 */ - int ShouldImplementHashcode = TypeRelated + 332; - /** @since 3.5 */ - int AbstractMethodsInConcreteClass = TypeRelated + 333; - - /** @deprecated - problem is no longer generated, use {@link #UndefinedType} instead */ - int SuperclassNotFound = TypeRelated + 329 + ProblemReasons.NotFound; // TypeRelated + 330 - /** @deprecated - problem is no longer generated, use {@link #NotVisibleType} instead */ - int SuperclassNotVisible = TypeRelated + 329 + ProblemReasons.NotVisible; // TypeRelated + 331 - /** @deprecated - problem is no longer generated, use {@link #AmbiguousType} instead */ - int SuperclassAmbiguous = TypeRelated + 329 + ProblemReasons.Ambiguous; // TypeRelated + 332 - /** @deprecated - problem is no longer generated, use {@link #InternalTypeNameProvided} instead */ - int SuperclassInternalNameProvided = TypeRelated + 329 + ProblemReasons.InternalNameProvided; // TypeRelated + 333 - /** @deprecated - problem is no longer generated, use {@link #InheritedTypeHidesEnclosingName} instead */ - int SuperclassInheritedNameHidesEnclosingName = TypeRelated + 329 + ProblemReasons.InheritedNameHidesEnclosingName; // TypeRelated + 334 - - /** @deprecated - problem is no longer generated, use {@link #UndefinedType} instead */ - int InterfaceNotFound = TypeRelated + 334 + ProblemReasons.NotFound; // TypeRelated + 335 - /** @deprecated - problem is no longer generated, use {@link #NotVisibleType} instead */ - int InterfaceNotVisible = TypeRelated + 334 + ProblemReasons.NotVisible; // TypeRelated + 336 - /** @deprecated - problem is no longer generated, use {@link #AmbiguousType} instead */ - int InterfaceAmbiguous = TypeRelated + 334 + ProblemReasons.Ambiguous; // TypeRelated + 337 - /** @deprecated - problem is no longer generated, use {@link #InternalTypeNameProvided} instead */ - int InterfaceInternalNameProvided = TypeRelated + 334 + ProblemReasons.InternalNameProvided; // TypeRelated + 338 - /** @deprecated - problem is no longer generated, use {@link #InheritedTypeHidesEnclosingName} instead */ - int InterfaceInheritedNameHidesEnclosingName = TypeRelated + 334 + ProblemReasons.InheritedNameHidesEnclosingName; // TypeRelated + 339 - - // field related problems - int DuplicateField = FieldRelated + 340; - int DuplicateModifierForField = FieldRelated + 341; - int IllegalModifierForField = FieldRelated + 342; - int IllegalModifierForInterfaceField = FieldRelated + 343; - int IllegalVisibilityModifierCombinationForField = FieldRelated + 344; - int IllegalModifierCombinationFinalVolatileForField = FieldRelated + 345; - int UnexpectedStaticModifierForField = FieldRelated + 346; - /** @since 3.32 */ - int IsClassPathCorrectWithReferencingType = TypeRelated + 347; - - /** @deprecated - problem is no longer generated, use {@link #UndefinedType} instead */ - int FieldTypeNotFound = FieldRelated + 349 + ProblemReasons.NotFound; // FieldRelated + 350 - /** @deprecated - problem is no longer generated, use {@link #NotVisibleType} instead */ - int FieldTypeNotVisible = FieldRelated + 349 + ProblemReasons.NotVisible; // FieldRelated + 351 - /** @deprecated - problem is no longer generated, use {@link #AmbiguousType} instead */ - int FieldTypeAmbiguous = FieldRelated + 349 + ProblemReasons.Ambiguous; // FieldRelated + 352 - /** @deprecated - problem is no longer generated, use {@link #InternalTypeNameProvided} instead */ - int FieldTypeInternalNameProvided = FieldRelated + 349 + ProblemReasons.InternalNameProvided; // FieldRelated + 353 - /** @deprecated - problem is no longer generated, use {@link #InheritedTypeHidesEnclosingName} instead */ - int FieldTypeInheritedNameHidesEnclosingName = FieldRelated + 349 + ProblemReasons.InheritedNameHidesEnclosingName; // FieldRelated + 354 - - // method related problems - int DuplicateMethod = MethodRelated + 355; - int IllegalModifierForArgument = MethodRelated + 356; - int DuplicateModifierForMethod = MethodRelated + 357; - int IllegalModifierForMethod = MethodRelated + 358; - int IllegalModifierForInterfaceMethod = MethodRelated + 359; - int IllegalVisibilityModifierCombinationForMethod = MethodRelated + 360; - int UnexpectedStaticModifierForMethod = MethodRelated + 361; - int IllegalAbstractModifierCombinationForMethod = MethodRelated + 362; - int AbstractMethodInAbstractClass = MethodRelated + 363; - int ArgumentTypeCannotBeVoid = MethodRelated + 364; - /** @deprecated - problem is no longer generated, use {@link #CannotAllocateVoidArray} instead */ - int ArgumentTypeCannotBeVoidArray = MethodRelated + 365; - /** @deprecated - problem is no longer generated, use {@link #CannotAllocateVoidArray} instead */ - int ReturnTypeCannotBeVoidArray = MethodRelated + 366; - int NativeMethodsCannotBeStrictfp = MethodRelated + 367; - int DuplicateModifierForArgument = MethodRelated + 368; - /** @since 3.5 */ - int IllegalModifierForConstructor = MethodRelated + 369; - - /** @deprecated - problem is no longer generated, use {@link #UndefinedType} instead */ - int ArgumentTypeNotFound = MethodRelated + 369 + ProblemReasons.NotFound; // MethodRelated + 370 - /** @deprecated - problem is no longer generated, use {@link #NotVisibleType} instead */ - int ArgumentTypeNotVisible = MethodRelated + 369 + ProblemReasons.NotVisible; // MethodRelated + 371 - /** @deprecated - problem is no longer generated, use {@link #AmbiguousType} instead */ - int ArgumentTypeAmbiguous = MethodRelated + 369 + ProblemReasons.Ambiguous; // MethodRelated + 372 - /** @deprecated - problem is no longer generated, use {@link #InternalTypeNameProvided} instead */ - int ArgumentTypeInternalNameProvided = MethodRelated + 369 + ProblemReasons.InternalNameProvided; // MethodRelated + 373 - /** @deprecated - problem is no longer generated, use {@link #InheritedTypeHidesEnclosingName} instead */ - int ArgumentTypeInheritedNameHidesEnclosingName = MethodRelated + 369 + ProblemReasons.InheritedNameHidesEnclosingName; // MethodRelated + 374 - - /** @deprecated - problem is no longer generated, use {@link #UndefinedType} instead */ - int ExceptionTypeNotFound = MethodRelated + 374 + ProblemReasons.NotFound; // MethodRelated + 375 - /** @deprecated - problem is no longer generated, use {@link #NotVisibleType} instead */ - int ExceptionTypeNotVisible = MethodRelated + 374 + ProblemReasons.NotVisible; // MethodRelated + 376 - /** @deprecated - problem is no longer generated, use {@link #AmbiguousType} instead */ - int ExceptionTypeAmbiguous = MethodRelated + 374 + ProblemReasons.Ambiguous; // MethodRelated + 377 - /** @deprecated - problem is no longer generated, use {@link #InternalTypeNameProvided} instead */ - int ExceptionTypeInternalNameProvided = MethodRelated + 374 + ProblemReasons.InternalNameProvided; // MethodRelated + 378 - /** @deprecated - problem is no longer generated, use {@link #InheritedTypeHidesEnclosingName} instead */ - int ExceptionTypeInheritedNameHidesEnclosingName = MethodRelated + 374 + ProblemReasons.InheritedNameHidesEnclosingName; // MethodRelated + 379 - - /** @deprecated - problem is no longer generated, use {@link #UndefinedType} instead */ - int ReturnTypeNotFound = MethodRelated + 379 + ProblemReasons.NotFound; // MethodRelated + 380 - /** @deprecated - problem is no longer generated, use {@link #NotVisibleType} instead */ - int ReturnTypeNotVisible = MethodRelated + 379 + ProblemReasons.NotVisible; // MethodRelated + 381 - /** @deprecated - problem is no longer generated, use {@link #AmbiguousType} instead */ - int ReturnTypeAmbiguous = MethodRelated + 379 + ProblemReasons.Ambiguous; // MethodRelated + 382 - /** @deprecated - problem is no longer generated, use {@link #InternalTypeNameProvided} instead */ - int ReturnTypeInternalNameProvided = MethodRelated + 379 + ProblemReasons.InternalNameProvided; // MethodRelated + 383 - /** @deprecated - problem is no longer generated, use {@link #InheritedTypeHidesEnclosingName} instead */ - int ReturnTypeInheritedNameHidesEnclosingName = MethodRelated + 379 + ProblemReasons.InheritedNameHidesEnclosingName; // MethodRelated + 384 - - // import related problems - int ConflictingImport = ImportRelated + 385; - int DuplicateImport = ImportRelated + 386; - int CannotImportPackage = ImportRelated + 387; - int UnusedImport = ImportRelated + 388; - - int ImportNotFound = ImportRelated + 389 + ProblemReasons.NotFound; // ImportRelated + 390 - /** @deprecated - problem is no longer generated, use {@link #NotVisibleType} instead */ - int ImportNotVisible = ImportRelated + 389 + ProblemReasons.NotVisible; // ImportRelated + 391 - /** @deprecated - problem is no longer generated, use {@link #AmbiguousType} instead */ - int ImportAmbiguous = ImportRelated + 389 + ProblemReasons.Ambiguous; // ImportRelated + 392 - /** @deprecated - problem is no longer generated, use {@link #InternalTypeNameProvided} instead */ - int ImportInternalNameProvided = ImportRelated + 389 + ProblemReasons.InternalNameProvided; // ImportRelated + 393 - /** @deprecated - problem is no longer generated, use {@link #InheritedTypeHidesEnclosingName} instead */ - int ImportInheritedNameHidesEnclosingName = ImportRelated + 389 + ProblemReasons.InheritedNameHidesEnclosingName; // ImportRelated + 394 - - /** @since 3.1 */ - int InvalidTypeForStaticImport = ImportRelated + 391; - - // local variable related problems - int DuplicateModifierForVariable = MethodRelated + 395; - int IllegalModifierForVariable = MethodRelated + 396; - /** @deprecated - problem is no longer generated, use {@link #RedundantNullCheckOnNonNullLocalVariable} instead */ - int LocalVariableCannotBeNull = Internal + 397; // since 3.3: semantics are LocalVariableRedundantCheckOnNonNull - /** @deprecated - problem is no longer generated, use {@link #NullLocalVariableReference}, {@link #RedundantNullCheckOnNullLocalVariable} or {@link #RedundantLocalVariableNullAssignment} instead */ - int LocalVariableCanOnlyBeNull = Internal + 398; // since 3.3: split with LocalVariableRedundantCheckOnNull depending on context - /** @deprecated - problem is no longer generated, use {@link #PotentialNullLocalVariableReference} instead */ - int LocalVariableMayBeNull = Internal + 399; - - // method verifier problems - int AbstractMethodMustBeImplemented = MethodRelated + 400; - int FinalMethodCannotBeOverridden = MethodRelated + 401; - int IncompatibleExceptionInThrowsClause = MethodRelated + 402; - int IncompatibleExceptionInInheritedMethodThrowsClause = MethodRelated + 403; - int IncompatibleReturnType = MethodRelated + 404; - int InheritedMethodReducesVisibility = MethodRelated + 405; - int CannotOverrideAStaticMethodWithAnInstanceMethod = MethodRelated + 406; - int CannotHideAnInstanceMethodWithAStaticMethod = MethodRelated + 407; - int StaticInheritedMethodConflicts = MethodRelated + 408; - int MethodReducesVisibility = MethodRelated + 409; - int OverridingNonVisibleMethod = MethodRelated + 410; - int AbstractMethodCannotBeOverridden = MethodRelated + 411; - int OverridingDeprecatedMethod = MethodRelated + 412; - /** @since 2.1 */ - int IncompatibleReturnTypeForNonInheritedInterfaceMethod = MethodRelated + 413; - /** @since 2.1 */ - int IncompatibleExceptionInThrowsClauseForNonInheritedInterfaceMethod = MethodRelated + 414; - /** @since 3.1 */ - int IllegalVararg = MethodRelated + 415; - /** @since 3.3 */ - int OverridingMethodWithoutSuperInvocation = MethodRelated + 416; - /** @since 3.5 */ - int MissingSynchronizedModifierInInheritedMethod= MethodRelated + 417; - /** @since 3.5 */ - int AbstractMethodMustBeImplementedOverConcreteMethod = MethodRelated + 418; - /** @since 3.5 */ - int InheritedIncompatibleReturnType = MethodRelated + 419; - - // code snippet support - int CodeSnippetMissingClass = Internal + 420; - int CodeSnippetMissingMethod = Internal + 421; - int CannotUseSuperInCodeSnippet = Internal + 422; - - //constant pool - int TooManyConstantsInConstantPool = Internal + 430; - /** @since 2.1 */ - int TooManyBytesForStringConstant = Internal + 431; - - // static constraints - /** @since 2.1 */ - int TooManyFields = Internal + 432; - /** @since 2.1 */ - int TooManyMethods = Internal + 433; - /** @since 3.7 */ - int TooManyParametersForSyntheticMethod = Internal + 434; - - // 1.4 features - // assertion warning - int UseAssertAsAnIdentifier = Internal + 440; - - // 1.5 features - int UseEnumAsAnIdentifier = Internal + 441; - /** @since 3.2 */ - int EnumConstantsCannotBeSurroundedByParenthesis = Syntax + Internal + 442; - - /** @since 3.10 */ - int IllegalUseOfUnderscoreAsAnIdentifier = Syntax + Internal + 443; - /** @since 3.10 */ - int UninternedIdentityComparison = Syntax + Internal + 444; - /** @since 3.24 */ - int ErrorUseOfUnderscoreAsAnIdentifier = Syntax + Internal + 445; - - // detected task - /** @since 2.1 */ - int Task = Internal + 450; - - // local variables related problems, cont'd - /** @since 3.3 */ - int NullLocalVariableReference = Internal + 451; - /** @since 3.3 */ - int PotentialNullLocalVariableReference = Internal + 452; - /** @since 3.3 */ - int RedundantNullCheckOnNullLocalVariable = Internal + 453; - /** @since 3.3 */ - int NullLocalVariableComparisonYieldsFalse = Internal + 454; - /** @since 3.3 */ - int RedundantLocalVariableNullAssignment = Internal + 455; - /** @since 3.3 */ - int NullLocalVariableInstanceofYieldsFalse = Internal + 456; - /** @since 3.3 */ - int RedundantNullCheckOnNonNullLocalVariable = Internal + 457; - /** @since 3.3 */ - int NonNullLocalVariableComparisonYieldsFalse = Internal + 458; - /** @since 3.9 */ - int PotentialNullUnboxing = Internal + 459; - /** @since 3.9 */ - int NullUnboxing = Internal + 461; - - // block - /** @since 3.0 */ - int UndocumentedEmptyBlock = Internal + 460; - - /* - * Javadoc comments - */ - /** - * Problem signaled on an invalid URL reference. - * Valid syntax example: @see "http://www.eclipse.org/" - * @since 3.4 - */ - int JavadocInvalidSeeUrlReference = Javadoc + Internal + 462; - /** - * Problem warned on missing tag description. - * @since 3.4 - */ - int JavadocMissingTagDescription = Javadoc + Internal + 463; - /** - * Problem warned on duplicated tag. - * @since 3.3 - */ - int JavadocDuplicateTag = Javadoc + Internal + 464; - /** - * Problem signaled on an hidden reference due to a too low visibility level. - * @since 3.3 - */ - int JavadocHiddenReference = Javadoc + Internal + 465; - /** - * Problem signaled on an invalid qualification for member type reference. - * @since 3.3 - */ - int JavadocInvalidMemberTypeQualification = Javadoc + Internal + 466; - /** @since 3.2 */ - int JavadocMissingIdentifier = Javadoc + Internal + 467; - /** @since 3.2 */ - int JavadocNonStaticTypeFromStaticInvocation = Javadoc + Internal + 468; - /** @since 3.1 */ - int JavadocInvalidParamTagTypeParameter = Javadoc + Internal + 469; - /** @since 3.0 */ - int JavadocUnexpectedTag = Javadoc + Internal + 470; - /** @since 3.0 */ - int JavadocMissingParamTag = Javadoc + Internal + 471; - /** @since 3.0 */ - int JavadocMissingParamName = Javadoc + Internal + 472; - /** @since 3.0 */ - int JavadocDuplicateParamName = Javadoc + Internal + 473; - /** @since 3.0 */ - int JavadocInvalidParamName = Javadoc + Internal + 474; - /** @since 3.0 */ - int JavadocMissingReturnTag = Javadoc + Internal + 475; - /** @since 3.0 */ - int JavadocDuplicateReturnTag = Javadoc + Internal + 476; - /** @since 3.0 */ - int JavadocMissingThrowsTag = Javadoc + Internal + 477; - /** @since 3.0 */ - int JavadocMissingThrowsClassName = Javadoc + Internal + 478; - /** @since 3.0 */ - int JavadocInvalidThrowsClass = Javadoc + Internal + 479; - /** @since 3.0 */ - int JavadocDuplicateThrowsClassName = Javadoc + Internal + 480; - /** @since 3.0 */ - int JavadocInvalidThrowsClassName = Javadoc + Internal + 481; - /** @since 3.0 */ - int JavadocMissingSeeReference = Javadoc + Internal + 482; - /** @since 3.0 */ - int JavadocInvalidSeeReference = Javadoc + Internal + 483; - /** - * Problem signaled on an invalid URL reference that does not conform to the href syntax. - * Valid syntax example: @see Eclipse Home Page - * @since 3.0 - */ - int JavadocInvalidSeeHref = Javadoc + Internal + 484; - /** @since 3.0 */ - int JavadocInvalidSeeArgs = Javadoc + Internal + 485; - /** @since 3.0 */ - int JavadocMissing = Javadoc + Internal + 486; - /** @since 3.0 */ - int JavadocInvalidTag = Javadoc + Internal + 487; - /* - * ID for field errors in Javadoc - */ - /** @since 3.0 */ - int JavadocUndefinedField = Javadoc + Internal + 488; - /** @since 3.0 */ - int JavadocNotVisibleField = Javadoc + Internal + 489; - /** @since 3.0 */ - int JavadocAmbiguousField = Javadoc + Internal + 490; - /** @since 3.0 */ - int JavadocUsingDeprecatedField = Javadoc + Internal + 491; - /* - * IDs for constructor errors in Javadoc - */ - /** @since 3.0 */ - int JavadocUndefinedConstructor = Javadoc + Internal + 492; - /** @since 3.0 */ - int JavadocNotVisibleConstructor = Javadoc + Internal + 493; - /** @since 3.0 */ - int JavadocAmbiguousConstructor = Javadoc + Internal + 494; - /** @since 3.0 */ - int JavadocUsingDeprecatedConstructor = Javadoc + Internal + 495; - /* - * IDs for method errors in Javadoc - */ - /** @since 3.0 */ - int JavadocUndefinedMethod = Javadoc + Internal + 496; - /** @since 3.0 */ - int JavadocNotVisibleMethod = Javadoc + Internal + 497; - /** @since 3.0 */ - int JavadocAmbiguousMethod = Javadoc + Internal + 498; - /** @since 3.0 */ - int JavadocUsingDeprecatedMethod = Javadoc + Internal + 499; - /** @since 3.0 */ - int JavadocNoMessageSendOnBaseType = Javadoc + Internal + 500; - /** @since 3.0 */ - int JavadocParameterMismatch = Javadoc + Internal + 501; - /** @since 3.0 */ - int JavadocNoMessageSendOnArrayType = Javadoc + Internal + 502; - /* - * IDs for type errors in Javadoc - */ - /** @since 3.0 */ - int JavadocUndefinedType = Javadoc + Internal + 503; - /** @since 3.0 */ - int JavadocNotVisibleType = Javadoc + Internal + 504; - /** @since 3.0 */ - int JavadocAmbiguousType = Javadoc + Internal + 505; - /** @since 3.0 */ - int JavadocUsingDeprecatedType = Javadoc + Internal + 506; - /** @since 3.0 */ - int JavadocInternalTypeNameProvided = Javadoc + Internal + 507; - /** @since 3.0 */ - int JavadocInheritedMethodHidesEnclosingName = Javadoc + Internal + 508; - /** @since 3.0 */ - int JavadocInheritedFieldHidesEnclosingName = Javadoc + Internal + 509; - /** @since 3.0 */ - int JavadocInheritedNameHidesEnclosingTypeName = Javadoc + Internal + 510; - /** @since 3.0 */ - int JavadocAmbiguousMethodReference = Javadoc + Internal + 511; - /** @since 3.0 */ - int JavadocUnterminatedInlineTag = Javadoc + Internal + 512; - /** @since 3.0 */ - int JavadocMalformedSeeReference = Javadoc + Internal + 513; - /** @since 3.0 */ - int JavadocMessagePrefix = Internal + 514; - - /** @since 3.1 */ - int JavadocMissingHashCharacter = Javadoc + Internal + 515; - /** @since 3.1 */ - int JavadocEmptyReturnTag = Javadoc + Internal + 516; - /** @since 3.1 */ - int JavadocInvalidValueReference = Javadoc + Internal + 517; - /** @since 3.1 */ - int JavadocUnexpectedText = Javadoc + Internal + 518; - /** @since 3.1 */ - int JavadocInvalidParamTagName = Javadoc + Internal + 519; - - // see also JavadocNotAccessibleType below - - /* - * IDs for module errors in Javadoc - */ - /** @since 3.20 */ - int JavadocMissingUsesTag = Javadoc + Internal + 1800; - /** @since 3.20 */ - int JavadocDuplicateUsesTag = Javadoc + Internal + 1801; - /** @since 3.20 */ - int JavadocMissingUsesClassName = Javadoc + Internal + 1802; - /** @since 3.20 */ - int JavadocInvalidUsesClassName = Javadoc + Internal + 1803; - /** @since 3.20 */ - int JavadocInvalidUsesClass = Javadoc + Internal + 1804; - /** @since 3.20 */ - int JavadocMissingProvidesTag = Javadoc + Internal + 1805; - /** @since 3.20 */ - int JavadocDuplicateProvidesTag = Javadoc + Internal + 1806; - /** @since 3.20 */ - int JavadocMissingProvidesClassName = Javadoc + Internal + 1807; - /** @since 3.20 */ - int JavadocInvalidProvidesClassName = Javadoc + Internal + 1808; - /** @since 3.20 */ - int JavadocInvalidProvidesClass = Javadoc + Internal + 1809; - /** @since 3.24*/ - int JavadocInvalidModuleQualification = Javadoc + Internal + 1810; - /** @since 3.29*/ - int JavadocInvalidModule = Javadoc + Internal + 1811; - /** @since 3.30*/ - int JavadocInvalidSnippet = Javadoc + Internal + 1812; - /** @since 3.30 */ - int JavadocInvalidSnippetMissingColon = Javadoc + Internal + 1813; - /** @since 3.30 */ - int JavadocInvalidSnippetContentNewLine = Javadoc + Internal + 1814; - /** @since 3.30 */ - int JavadocInvalidSnippetRegionNotClosed = Javadoc + Internal + 1815; - /** @since 3.30 */ - int JavadocInvalidSnippetRegexSubstringTogether = Javadoc + Internal + 1816; - /** @since 3.30 */ - int JavadocInvalidSnippetDuplicateRegions = Javadoc + Internal + 1817; - - /** - * Generics - */ - /** @since 3.1 */ - int DuplicateTypeVariable = Internal + 520; - /** @since 3.1 */ - int IllegalTypeVariableSuperReference = Internal + 521; - /** @since 3.1 */ - int NonStaticTypeFromStaticInvocation = Internal + 522; - /** @since 3.1 */ - int ObjectCannotBeGeneric = Internal + 523; - /** @since 3.1 */ - int NonGenericType = TypeRelated + 524; - /** @since 3.1 */ - int IncorrectArityForParameterizedType = TypeRelated + 525; - /** @since 3.1 */ - int TypeArgumentMismatch = TypeRelated + 526; - /** @since 3.1 */ - int DuplicateMethodErasure = TypeRelated + 527; - /** @since 3.1 */ - int ReferenceToForwardTypeVariable = TypeRelated + 528; - /** @since 3.1 */ - int BoundMustBeAnInterface = TypeRelated + 529; - /** @since 3.1 */ - int UnsafeRawConstructorInvocation = TypeRelated + 530; - /** @since 3.1 */ - int UnsafeRawMethodInvocation = TypeRelated + 531; - /** @since 3.1 */ - int UnsafeTypeConversion = TypeRelated + 532; - /** @since 3.1 */ - int InvalidTypeVariableExceptionType = TypeRelated + 533; - /** @since 3.1 */ - int InvalidParameterizedExceptionType = TypeRelated + 534; - /** @since 3.1 */ - int IllegalGenericArray = TypeRelated + 535; - /** @since 3.1 */ - int UnsafeRawFieldAssignment = TypeRelated + 536; - /** @since 3.1 */ - int FinalBoundForTypeVariable = TypeRelated + 537; - /** @since 3.1 */ - int UndefinedTypeVariable = Internal + 538; - /** @since 3.1 */ - int SuperInterfacesCollide = TypeRelated + 539; - /** @since 3.1 */ - int WildcardConstructorInvocation = TypeRelated + 540; - /** @since 3.1 */ - int WildcardMethodInvocation = TypeRelated + 541; - /** @since 3.1 */ - int WildcardFieldAssignment = TypeRelated + 542; - /** @since 3.1 */ - int GenericMethodTypeArgumentMismatch = TypeRelated + 543; - /** @since 3.1 */ - int GenericConstructorTypeArgumentMismatch = TypeRelated + 544; - /** @since 3.1 */ - int UnsafeGenericCast = TypeRelated + 545; - /** @since 3.1 */ - int IllegalInstanceofParameterizedType = Internal + 546; - /** @since 3.1 */ - int IllegalInstanceofTypeParameter = Internal + 547; - /** @since 3.1 */ - int NonGenericMethod = TypeRelated + 548; - /** @since 3.1 */ - int IncorrectArityForParameterizedMethod = TypeRelated + 549; - /** @since 3.1 */ - int ParameterizedMethodArgumentTypeMismatch = TypeRelated + 550; - /** @since 3.1 */ - int NonGenericConstructor = TypeRelated + 551; - /** @since 3.1 */ - int IncorrectArityForParameterizedConstructor = TypeRelated + 552; - /** @since 3.1 */ - int ParameterizedConstructorArgumentTypeMismatch = TypeRelated + 553; - /** @since 3.1 */ - int TypeArgumentsForRawGenericMethod = TypeRelated + 554; - /** @since 3.1 */ - int TypeArgumentsForRawGenericConstructor = TypeRelated + 555; - /** @since 3.1 */ - int SuperTypeUsingWildcard = TypeRelated + 556; - /** @since 3.1 */ - int GenericTypeCannotExtendThrowable = TypeRelated + 557; - /** @since 3.1 */ - int IllegalClassLiteralForTypeVariable = TypeRelated + 558; - /** @since 3.1 */ - int UnsafeReturnTypeOverride = MethodRelated + 559; - /** @since 3.1 */ - int MethodNameClash = MethodRelated + 560; - /** @since 3.1 */ - int RawMemberTypeCannotBeParameterized = TypeRelated + 561; - /** @since 3.1 */ - int MissingArgumentsForParameterizedMemberType = TypeRelated + 562; - /** @since 3.1 */ - int StaticMemberOfParameterizedType = TypeRelated + 563; - /** @since 3.1 */ - int BoundHasConflictingArguments = TypeRelated + 564; - /** @since 3.1 */ - int DuplicateParameterizedMethods = MethodRelated + 565; - /** @since 3.1 */ - int IllegalQualifiedParameterizedTypeAllocation = TypeRelated + 566; - /** @since 3.1 */ - int DuplicateBounds = TypeRelated + 567; - /** @since 3.1 */ - int BoundCannotBeArray = TypeRelated + 568; - /** @since 3.1 */ - int UnsafeRawGenericConstructorInvocation = TypeRelated + 569; - /** @since 3.1 */ - int UnsafeRawGenericMethodInvocation = TypeRelated + 570; - /** @since 3.1 */ - int TypeParameterHidingType = TypeRelated + 571; - /** @since 3.2 */ - int RawTypeReference = TypeRelated + 572; - /** @since 3.2 */ - int NoAdditionalBoundAfterTypeVariable = TypeRelated + 573; - /** @since 3.2 */ - int UnsafeGenericArrayForVarargs = MethodRelated + 574; - /** @since 3.2 */ - int IllegalAccessFromTypeVariable = TypeRelated + 575; - /** @since 3.3 */ - int TypeHidingTypeParameterFromType = TypeRelated + 576; - /** @since 3.3 */ - int TypeHidingTypeParameterFromMethod = TypeRelated + 577; - /** @since 3.3 */ - int InvalidUsageOfWildcard = Syntax + Internal + 578; - /** @since 3.4 */ - int UnusedTypeArgumentsForMethodInvocation = MethodRelated + 579; - - /** - * Foreach - */ - /** @since 3.1 */ - int IncompatibleTypesInForeach = TypeRelated + 580; - /** @since 3.1 */ - int InvalidTypeForCollection = Internal + 581; - /** @since 3.6*/ - int InvalidTypeForCollectionTarget14 = Internal + 582; - - /** @since 3.7.1 */ - int DuplicateInheritedMethods = MethodRelated + 583; - /** @since 3.8 */ - int MethodNameClashHidden = MethodRelated + 584; - - /** @since 3.9 */ - int UnsafeElementTypeConversion = TypeRelated + 585; - /** @since 3.11 */ - int InvalidTypeArguments = MethodRelated + TypeRelated + 586; - - /** - * 1.5 Syntax errors (when source level < 1.5) - */ - /** @since 3.1 */ - int InvalidUsageOfTypeParameters = Syntax + Internal + 590; - /** @since 3.1 */ - int InvalidUsageOfStaticImports = Syntax + Internal + 591; - /** @since 3.1 */ - int InvalidUsageOfForeachStatements = Syntax + Internal + 592; - /** @since 3.1 */ - int InvalidUsageOfTypeArguments = Syntax + Internal + 593; - /** @since 3.1 */ - int InvalidUsageOfEnumDeclarations = Syntax + Internal + 594; - /** @since 3.1 */ - int InvalidUsageOfVarargs = Syntax + Internal + 595; - /** @since 3.1 */ - int InvalidUsageOfAnnotations = Syntax + Internal + 596; - /** @since 3.1 */ - int InvalidUsageOfAnnotationDeclarations = Syntax + Internal + 597; - /** @since 3.4 */ - int InvalidUsageOfTypeParametersForAnnotationDeclaration = Syntax + Internal + 598; - /** @since 3.4 */ - int InvalidUsageOfTypeParametersForEnumDeclaration = Syntax + Internal + 599; - /** - * Annotation - */ - /** @since 3.1 */ - int IllegalModifierForAnnotationMethod = MethodRelated + 600; - /** @since 3.1 */ - int IllegalExtendedDimensions = MethodRelated + 601; - /** @since 3.1 */ - int InvalidFileNameForPackageAnnotations = Syntax + Internal + 602; - /** @since 3.1 */ - int IllegalModifierForAnnotationType = TypeRelated + 603; - /** @since 3.1 */ - int IllegalModifierForAnnotationMemberType = TypeRelated + 604; - /** @since 3.1 */ - int InvalidAnnotationMemberType = TypeRelated + 605; - /** @since 3.1 */ - int AnnotationCircularitySelfReference = TypeRelated + 606; - /** @since 3.1 */ - int AnnotationCircularity = TypeRelated + 607; - /** @since 3.1 */ - int DuplicateAnnotation = TypeRelated + 608; - /** @since 3.1 */ - int MissingValueForAnnotationMember = TypeRelated + 609; - /** @since 3.1 */ - int DuplicateAnnotationMember = Internal + 610; - /** @since 3.1 */ - int UndefinedAnnotationMember = MethodRelated + 611; - /** @since 3.1 */ - int AnnotationValueMustBeClassLiteral = Internal + 612; - /** @since 3.1 */ - int AnnotationValueMustBeConstant = Internal + 613; - /** @deprecated - problem is no longer generated (code is legite) - * @since 3.1 */ - int AnnotationFieldNeedConstantInitialization = Internal + 614; - /** @since 3.1 */ - int IllegalModifierForAnnotationField = Internal + 615; - /** @since 3.1 */ - int AnnotationCannotOverrideMethod = MethodRelated + 616; - /** @since 3.1 */ - int AnnotationMembersCannotHaveParameters = Syntax + Internal + 617; - /** @since 3.1 */ - int AnnotationMembersCannotHaveTypeParameters = Syntax + Internal + 618; - /** @since 3.1 */ - int AnnotationTypeDeclarationCannotHaveSuperclass = Syntax + Internal + 619; - /** @since 3.1 */ - int AnnotationTypeDeclarationCannotHaveSuperinterfaces = Syntax + Internal + 620; - /** @since 3.1 */ - int DuplicateTargetInTargetAnnotation = Internal + 621; - /** @since 3.1 */ - int DisallowedTargetForAnnotation = TypeRelated + 622; - /** @since 3.1 */ - int MethodMustOverride = MethodRelated + 623; - /** @since 3.1 */ - int AnnotationTypeDeclarationCannotHaveConstructor = Syntax + Internal + 624; - /** @since 3.1 */ - int AnnotationValueMustBeAnnotation = Internal + 625; - /** @since 3.1 */ - int AnnotationTypeUsedAsSuperInterface = TypeRelated + 626; - /** @since 3.1 */ - int MissingOverrideAnnotation = MethodRelated + 627; - /** @since 3.1 */ - int FieldMissingDeprecatedAnnotation = Internal + 628; - /** @since 3.1 */ - int MethodMissingDeprecatedAnnotation = Internal + 629; - /** @since 3.1 */ - int TypeMissingDeprecatedAnnotation = Internal + 630; - /** @since 3.1 */ - int UnhandledWarningToken = Internal + 631; - /** @since 3.2 */ - int AnnotationValueMustBeArrayInitializer = Internal + 632; - /** @since 3.3 */ - int AnnotationValueMustBeAnEnumConstant = Internal + 633; - /** @since 3.3 */ - int MethodMustOverrideOrImplement = MethodRelated + 634; - /** @since 3.4 */ - int UnusedWarningToken = Internal + 635; - /** @since 3.6 */ - int MissingOverrideAnnotationForInterfaceMethodImplementation = MethodRelated + 636; - /** @since 3.10 */ - int InvalidUsageOfTypeAnnotations = Syntax + Internal + 637; - /** @since 3.10 */ - int DisallowedExplicitThisParameter = Syntax + Internal + 638; - /** @since 3.10 */ - int MisplacedTypeAnnotations = Syntax + Internal + 639; - /** @since 3.10 */ - int IllegalTypeAnnotationsInStaticMemberAccess = Internal + Syntax + 640; - /** @since 3.10 */ - int IllegalUsageOfTypeAnnotations = Internal + Syntax + 641; - /** @since 3.10 */ - int IllegalDeclarationOfThisParameter = Internal + Syntax + 642; - /** @since 3.10 */ - int ExplicitThisParameterNotBelow18 = Internal + Syntax + 643; - /** @since 3.10 */ - int DefaultMethodNotBelow18 = Internal + Syntax + 644; - /** @since 3.10 */ - int LambdaExpressionNotBelow18 = Internal + Syntax + 645; - /** @since 3.10 */ - int MethodReferenceNotBelow18 = Internal + Syntax + 646; - /** @since 3.10 */ - int ConstructorReferenceNotBelow18 = Internal + Syntax + 647; - /** @since 3.10 */ - int ExplicitThisParameterNotInLambda = Internal + Syntax + 648; - /** @since 3.10 */ - int ExplicitAnnotationTargetRequired = TypeRelated + 649; - /** @since 3.10 */ - int IllegalTypeForExplicitThis = Internal + Syntax + 650; - /** @since 3.10 */ - int IllegalQualifierForExplicitThis = Internal + Syntax + 651; - /** @since 3.10 */ - int IllegalQualifierForExplicitThis2 = Internal + Syntax + 652; - /** @since 3.10 */ - int TargetTypeNotAFunctionalInterface = Internal + TypeRelated + 653; - /** @since 3.10 */ - int IllegalVarargInLambda = Internal + TypeRelated + 654; - /** @since 3.10 */ - int illFormedParameterizationOfFunctionalInterface = Internal + TypeRelated + 655; - /** @since 3.10 */ - int lambdaSignatureMismatched = Internal + TypeRelated + 656; - /** @since 3.10 */ - int lambdaParameterTypeMismatched = Internal + TypeRelated + 657; - /** @since 3.10 */ - int IncompatibleLambdaParameterType = Internal + TypeRelated + 658; - /** @since 3.10 */ - int NoGenericLambda = Internal + TypeRelated + 659; - /** - * More problems in generics - */ - /** @since 3.4 */ - int UnusedTypeArgumentsForConstructorInvocation = MethodRelated + 660; - /** @since 3.9 */ - int UnusedTypeParameter = TypeRelated + 661; - /** @since 3.9 */ - int IllegalArrayOfUnionType = TypeRelated + 662; - /** @since 3.10 */ - int OuterLocalMustBeEffectivelyFinal = Internal + 663; - /** @since 3.10 */ - int InterfaceNotFunctionalInterface = Internal + TypeRelated + 664; - /** @since 3.10 */ - int ConstructionTypeMismatch = Internal + TypeRelated + 665; - /** @since 3.10 */ - int ToleratedMisplacedTypeAnnotations = Syntax + Internal + 666; - /** @since 3.13*/ - int InterfaceSuperInvocationNotBelow18 = Internal + Syntax + 667; - /** @since 3.13*/ - int InterfaceStaticMethodInvocationNotBelow18 = Internal + Syntax + 668; - /** @since 3.14 */ - int FieldMustBeFinal = Internal + 669; - - - /** - * Null analysis for other kinds of expressions, syntactically nonnull - */ - /** @since 3.9 */ - int NonNullExpressionComparisonYieldsFalse = Internal + 670; - /** @since 3.9 */ - int RedundantNullCheckOnNonNullExpression = Internal + 671; - /** @since 3.9 */ - int NullExpressionReference = Internal + 672; - /** @since 3.9 */ - int PotentialNullExpressionReference = Internal + 673; - - /** - * Corrupted binaries - */ - /** @since 3.1 */ - int CorruptedSignature = Internal + 700; - /** - * Corrupted source - */ - /** @since 3.2 */ - int InvalidEncoding = Internal + 701; - /** @since 3.2 */ - int CannotReadSource = Internal + 702; - - /** - * Autoboxing - */ - /** @since 3.1 */ - int BoxingConversion = Internal + 720; - /** @since 3.1 */ - int UnboxingConversion = Internal + 721; - - /** - * Modifiers - * @since 3.28 - */ - int StrictfpNotRequired = Syntax + Internal + 741; - - /** - * Enum - */ - /** @since 3.1 */ - int IllegalModifierForEnum = TypeRelated + 750; - /** @since 3.1 */ - int IllegalModifierForEnumConstant = FieldRelated + 751; - /** @deprecated - problem could not be reported, enums cannot be local takes precedence - * @since 3.1 */ - int IllegalModifierForLocalEnum = TypeRelated + 752; - /** @since 3.1 */ - int IllegalModifierForMemberEnum = TypeRelated + 753; - /** @since 3.1 */ - int CannotDeclareEnumSpecialMethod = MethodRelated + 754; - /** @since 3.1 */ - int IllegalQualifiedEnumConstantLabel = FieldRelated + 755; - /** @since 3.1 */ - int CannotExtendEnum = TypeRelated + 756; - /** @since 3.1 */ - int CannotInvokeSuperConstructorInEnum = MethodRelated + 757; - /** @since 3.1 */ - int EnumAbstractMethodMustBeImplemented = MethodRelated + 758; - /** @since 3.1 */ - int EnumSwitchCannotTargetField = FieldRelated + 759; - /** @since 3.1 */ - int IllegalModifierForEnumConstructor = MethodRelated + 760; - /** @since 3.1 */ - int MissingEnumConstantCase = FieldRelated + 761; - /** @since 3.2 */ // TODO need to fix 3.1.1 contribution (inline this constant on client side) - int EnumStaticFieldInInInitializerContext = FieldRelated + 762; - /** @since 3.4 */ - int EnumConstantMustImplementAbstractMethod = MethodRelated + 763; - /** @since 3.5 */ - int EnumConstantCannotDefineAbstractMethod = MethodRelated + 764; - /** @since 3.5 */ - int AbstractMethodInEnum = MethodRelated + 765; - /** @since 3.8 */ - int MissingEnumDefaultCase = Internal + 766; - /** @since 3.8 */ - int MissingDefaultCase = Internal + 767; - /** @since 3.8 */ - int MissingEnumConstantCaseDespiteDefault = FieldRelated + 768; - /** @since 3.8 */ - int UninitializedLocalVariableHintMissingDefault = Internal + 769; - /** @since 3.8 */ - int UninitializedBlankFinalFieldHintMissingDefault = FieldRelated + 770; - /** @since 3.8 */ - int ShouldReturnValueHintMissingDefault = MethodRelated + 771; - - /** - * Var args - */ - /** @since 3.1 */ - int IllegalExtendedDimensionsForVarArgs = Syntax + Internal + 800; - /** @since 3.1 */ - int MethodVarargsArgumentNeedCast = MethodRelated + 801; - /** @since 3.1 */ - int ConstructorVarargsArgumentNeedCast = ConstructorRelated + 802; - /** @since 3.1 */ - int VarargsConflict = MethodRelated + 803; - /** @since 3.7.1 */ - int SafeVarargsOnFixedArityMethod = MethodRelated + 804; - /** @since 3.7.1 */ - int SafeVarargsOnNonFinalInstanceMethod = MethodRelated + 805; - /** @since 3.7.1 */ - int PotentialHeapPollutionFromVararg = MethodRelated + 806; - /** @since 3.8 */ - int VarargsElementTypeNotVisible = MethodRelated + 807; - /** @since 3.8 */ - int VarargsElementTypeNotVisibleForConstructor = ConstructorRelated + 808; - /** @since 3.10 */ - int ApplicableMethodOverriddenByInapplicable = MethodRelated + 809; - - /** - * Javadoc Generic - */ - /** @since 3.1 */ - int JavadocGenericMethodTypeArgumentMismatch = Javadoc + Internal + 850; - /** @since 3.1 */ - int JavadocNonGenericMethod = Javadoc + Internal + 851; - /** @since 3.1 */ - int JavadocIncorrectArityForParameterizedMethod = Javadoc + Internal + 852; - /** @since 3.1 */ - int JavadocParameterizedMethodArgumentTypeMismatch = Javadoc + Internal + 853; - /** @since 3.1 */ - int JavadocTypeArgumentsForRawGenericMethod = Javadoc + Internal + 854; - /** @since 3.1 */ - int JavadocGenericConstructorTypeArgumentMismatch = Javadoc + Internal + 855; - /** @since 3.1 */ - int JavadocNonGenericConstructor = Javadoc + Internal + 856; - /** @since 3.1 */ - int JavadocIncorrectArityForParameterizedConstructor = Javadoc + Internal + 857; - /** @since 3.1 */ - int JavadocParameterizedConstructorArgumentTypeMismatch = Javadoc + Internal + 858; - /** @since 3.1 */ - int JavadocTypeArgumentsForRawGenericConstructor = Javadoc + Internal + 859; - - /** - * Java 7 errors - */ - /** @since 3.7.1 */ - int AssignmentToMultiCatchParameter = Internal + 870; - /** @since 3.7.1 */ - int ResourceHasToImplementAutoCloseable = TypeRelated + 871; - /** @since 3.7.1 */ - int AssignmentToResource = Internal + 872; - /** @since 3.7.1 */ - int InvalidUnionTypeReferenceSequence = Internal + TypeRelated + 873; - /** @since 3.7.1 */ - int AutoManagedResourceNotBelow17 = Syntax + Internal + 874; - /** @since 3.7.1 */ - int MultiCatchNotBelow17 = Syntax + Internal + 875; - /** @since 3.7.1 */ - int PolymorphicMethodNotBelow17 = MethodRelated + 876; - /** @since 3.7.1 */ - int IncorrectSwitchType17 = TypeRelated + 877; - /** @since 3.7.1 */ - int CannotInferElidedTypes = TypeRelated + 878; - /** @since 3.7.1 */ - int CannotUseDiamondWithExplicitTypeArguments = TypeRelated + 879; - /** @since 3.7.1 */ - int CannotUseDiamondWithAnonymousClasses = TypeRelated + 880; - /** @since 3.7.1 */ - int SwitchOnStringsNotBelow17 = TypeRelated + 881; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=348492 - /** @since 3.7.1 */ - int UnhandledExceptionOnAutoClose = TypeRelated + 882; - /** @since 3.7.1 */ - 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 - /** @since 3.10 */ - int IntersectionCastNotBelow18 = TypeRelated + 891; - /** @since 3.10 */ - int IllegalBasetypeInIntersectionCast = TypeRelated + 892; - /** @since 3.10 */ - int IllegalArrayTypeInIntersectionCast = TypeRelated + 893; - /** @since 3.10 */ - int DuplicateBoundInIntersectionCast = TypeRelated + 894; - /** @deprecated This problem is no longer reported; number Of functional interface is not an issue, number of abstract methods is. - * @since 3.10 */ - int MultipleFunctionalInterfaces = TypeRelated + 895; - /** @since 3.10 */ - int StaticInterfaceMethodNotBelow18 = Internal + Syntax + 896; - /** @since 3.10 */ - int DuplicateAnnotationNotMarkedRepeatable = TypeRelated + 897; - /** @since 3.10 */ - int DisallowedTargetForContainerAnnotationType = TypeRelated + 898; - /** @since 3.10 */ - int RepeatedAnnotationWithContainerAnnotation = TypeRelated + 899; - - /** @since 3.14 */ - int AutoManagedVariableResourceNotBelow9 = Syntax + Internal + 1351; - /** - * External problems -- These are problems defined by other plugins - */ - - /** @since 3.2 */ - int ExternalProblemNotFixable = 900; - - // indicates an externally defined problem that has a quick-assist processor - // associated with it - /** @since 3.2 */ - int ExternalProblemFixable = 901; - - /** @since 3.10 */ - int ContainerAnnotationTypeHasWrongValueType = TypeRelated + 902; - /** @since 3.10 */ - int ContainerAnnotationTypeMustHaveValue = TypeRelated + 903; - /** @since 3.10 */ - int ContainerAnnotationTypeHasNonDefaultMembers = TypeRelated + 904; - /** @since 3.10 */ - int ContainerAnnotationTypeHasShorterRetention = TypeRelated + 905; - /** @since 3.10 */ - int RepeatableAnnotationTypeTargetMismatch = TypeRelated + 906; - /** @since 3.10 */ - int RepeatableAnnotationTypeIsDocumented = TypeRelated + 907; - /** @since 3.10 */ - int RepeatableAnnotationTypeIsInherited = TypeRelated + 908; - /** @since 3.10 */ - int RepeatableAnnotationWithRepeatingContainerAnnotation = TypeRelated + 909; - - /** - * Errors/warnings from annotation based null analysis - */ - /** @since 3.8 */ - int RequiredNonNullButProvidedNull = TypeRelated + 910; - /** @since 3.8 */ - int RequiredNonNullButProvidedPotentialNull = TypeRelated + 911; - /** @since 3.8 */ - int RequiredNonNullButProvidedUnknown = TypeRelated + 912; - /** @since 3.8 */ - int MissingNonNullByDefaultAnnotationOnPackage = Internal + 913; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=372012 - /** @since 3.8 */ - int IllegalReturnNullityRedefinition = MethodRelated + 914; - /** @since 3.8 */ - int IllegalRedefinitionToNonNullParameter = MethodRelated + 915; - /** @since 3.8 */ - int IllegalDefinitionToNonNullParameter = MethodRelated + 916; - /** @since 3.8 */ - int ParameterLackingNonNullAnnotation = MethodRelated + 917; - /** @since 3.8 */ - int ParameterLackingNullableAnnotation = MethodRelated + 918; - /** @since 3.8 */ - int PotentialNullMessageSendReference = Internal + 919; - /** @since 3.8 */ - int RedundantNullCheckOnNonNullMessageSend = Internal + 920; - /** @since 3.8 */ - int CannotImplementIncompatibleNullness = Internal + 921; - /** @since 3.8 */ - int RedundantNullAnnotation = MethodRelated + 922; - /** @since 3.8 */ - int IllegalAnnotationForBaseType = TypeRelated + 923; - /** @since 3.9 */ - int NullableFieldReference = FieldRelated + 924; - /** @since 3.8 */ - int RedundantNullDefaultAnnotation = Internal + 925; // shouldn't actually occur any more after bug 366063 - /** @since 3.8 */ - int RedundantNullDefaultAnnotationPackage = Internal + 926; - /** @since 3.8 */ - int RedundantNullDefaultAnnotationType = Internal + 927; - /** @since 3.8 */ - int RedundantNullDefaultAnnotationMethod = Internal + 928; - /** @since 3.8 */ - int ContradictoryNullAnnotations = Internal + 929; - /** @since 3.8 */ - int MissingNonNullByDefaultAnnotationOnType = Internal + 930; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=372012 - /** @since 3.8 */ - int RedundantNullCheckOnSpecdNonNullLocalVariable = Internal + 931; - /** @since 3.8 */ - int SpecdNonNullLocalVariableComparisonYieldsFalse = Internal + 932; - /** @since 3.8 */ - int RequiredNonNullButProvidedSpecdNullable = Internal + 933; - /** @since 3.9 */ - int UninitializedNonNullField = FieldRelated + 934; - /** @since 3.9 */ - int UninitializedNonNullFieldHintMissingDefault = FieldRelated + 935; - /** @since 3.9 */ - int NonNullMessageSendComparisonYieldsFalse = Internal + 936; - /** @since 3.9 */ - int RedundantNullCheckOnNonNullSpecdField = Internal + 937; - /** @since 3.9 */ - int NonNullSpecdFieldComparisonYieldsFalse = Internal + 938; - /** @since 3.9 */ - int ConflictingNullAnnotations = MethodRelated + 939; - /** @since 3.9 */ - int ConflictingInheritedNullAnnotations = MethodRelated + 940; - /** @since 3.10 */ - int RedundantNullCheckOnField = Internal + 941; - /** @since 3.10 */ - int FieldComparisonYieldsFalse = Internal + 942; - /** @since 3.14 */ - int RedundantNullDefaultAnnotationModule = Internal + 943; - /** @since 3.19 */ - int RedundantNullCheckOnConstNonNullField = Internal + 944; - /** @since 3.20 */ - int ConstNonNullFieldComparisonYieldsFalse = Internal + 945; - /** @since 3.21 */ - int InheritedParameterLackingNonNullAnnotation = MethodRelated + 946; - - /** @since 3.10 */ - int ArrayReferencePotentialNullReference = Internal + 951; - /** @since 3.10 */ - int DereferencingNullableExpression = Internal + 952; - /** @since 3.10 */ - int NullityMismatchingTypeAnnotation = Internal + 953; - /** @since 3.10 */ - int NullityMismatchingTypeAnnotationSuperHint = Internal + 954; - /** @since 3.10 */ - int NullityUncheckedTypeAnnotationDetail = Internal + 955; // see also NullityUncheckedTypeAnnotation - /** @since 3.10 */ - int NullityUncheckedTypeAnnotationDetailSuperHint = Internal + 956; - /** @since 3.10 */ - int ReferenceExpressionParameterNullityMismatch = MethodRelated + 957; - /** @since 3.10 */ - int ReferenceExpressionParameterNullityUnchecked = MethodRelated + 958; - /** @since 3.10 */ - int ReferenceExpressionReturnNullRedef = MethodRelated + 959; - /** @since 3.10 */ - int ReferenceExpressionReturnNullRedefUnchecked = MethodRelated + 960; - /** @since 3.10 */ - int RedundantNullCheckAgainstNonNullType = Internal + 961; - /** @since 3.10 */ - int NullAnnotationUnsupportedLocation = Internal + 962; - /** @since 3.10 */ - int NullAnnotationUnsupportedLocationAtType = Internal + 963; - /** @since 3.10 */ - int NullityMismatchTypeArgument = Internal + 964; - /** @since 3.10 */ - int ContradictoryNullAnnotationsOnBound = Internal + 965; - /** @since 3.10 */ - int ContradictoryNullAnnotationsInferred = Internal + 966; - /** @since 3.10 */ - int UnsafeNullnessCast = Internal + 967; - /** @since 3.10 */ - int NonNullDefaultDetailIsNotEvaluated = 968; // no longer reported - /** @since 3.10 */ - int NullNotCompatibleToFreeTypeVariable = 969; - /** @since 3.10 */ - int NullityMismatchAgainstFreeTypeVariable = 970; - /** @since 3.11 */ - int ImplicitObjectBoundNoNullDefault = 971; - /** @since 3.11 */ - int IllegalParameterNullityRedefinition = MethodRelated + 972; - /** @since 3.11 */ - int ContradictoryNullAnnotationsInferredFunctionType = MethodRelated + 973; - /** @since 3.11 */ - int IllegalReturnNullityRedefinitionFreeTypeVariable = MethodRelated + 974; - /** @since 3.12 */ - int IllegalRedefinitionOfTypeVariable = 975; - /** @since 3.12 */ - int UncheckedAccessOfValueOfFreeTypeVariable = 976; - /** @since 3.12 */ - int UninitializedFreeTypeVariableField = 977; - /** @since 3.12 */ - int UninitializedFreeTypeVariableFieldHintMissingDefault = 978; - /** @since 3.12 */ - int RequiredNonNullButProvidedFreeTypeVariable = TypeRelated + 979; - /** @since 3.12 */ - int NonNullTypeVariableFromLegacyMethod = TypeRelated + 980; - /** @since 3.12 */ - int NonNullMethodTypeVariableFromLegacyMethod = TypeRelated + 981; - /** @since 3.21 */ - int MissingNullAnnotationImplicitlyUsed = Internal + 982; - /** @since 3.21 */ - int AnnotatedTypeArgumentToUnannotated = Internal + 983; - /** @since 3.21 */ - int AnnotatedTypeArgumentToUnannotatedSuperHint = Internal + 984; - /** @since 3.32 */ - int NonNullArrayContentNotInitialized = Internal + 985; - /** - * Both {@link #NullityUncheckedTypeAnnotationDetail} and {@link #NullityUncheckedTypeAnnotation} - * signal that unchecked conversion is needed to pass a value between annotated and un-annotated code. - * In the case of {@link #NullityUncheckedTypeAnnotationDetail} the mismatch was observed only on some - * detail of the types involved (type arguments or array components), for which the UI does not (yet) - * offer a quick fix, whereas {@link #NullityUncheckedTypeAnnotation} affects the toplevel type and thus - * can be easily fixed by adding the appropriate null annotation. - * - * @since 3.36 - */ - int NullityUncheckedTypeAnnotation = Internal + 986; - - - // Java 8 work - /** @since 3.10 */ - int IllegalModifiersForElidedType = Internal + 1001; - /** @since 3.10 */ - int IllegalModifiers = Internal + 1002; - - /** @since 3.10 */ - int IllegalTypeArgumentsInRawConstructorReference = TypeRelated + 1003; - - // more on lambdas: - /** @since 3.18 */ - int MissingValueFromLambda = Internal + 1004; - - // default methods: - /** @since 3.10 */ - int IllegalModifierForInterfaceMethod18 = MethodRelated + 1050; - - /** @since 3.10 */ - int DefaultMethodOverridesObjectMethod = MethodRelated + 1051; - - /** @since 3.10 */ - int InheritedDefaultMethodConflictsWithOtherInherited = MethodRelated + 1052; - - /** @since 3.10 */ - int DuplicateInheritedDefaultMethods = MethodRelated + 1053; - - /** @since 3.10 */ - int SuperAccessCannotBypassDirectSuper = TypeRelated + 1054; - /** @since 3.10 */ - int SuperCallCannotBypassOverride = MethodRelated + 1055; - /** @since 3.10 */ - int IllegalModifierCombinationForInterfaceMethod = MethodRelated + 1056; - /** @since 3.10 */ - int IllegalStrictfpForAbstractInterfaceMethod = MethodRelated + 1057; - /** @since 3.10 */ - int IllegalDefaultModifierSpecification = MethodRelated + 1058; - /** @since 3.13 */ - int CannotInferInvocationType = TypeRelated + 1059; - - - /** @since 3.13 */ - int TypeAnnotationAtQualifiedName = Internal + Syntax + 1060; - - /** @since 3.13 */ - int NullAnnotationAtQualifyingType = Internal + Syntax + 1061; - - /** @since 3.14*/ - int IllegalModifierForInterfaceMethod9 = MethodRelated + 1071; - /** @since 3.14*/ - int IllegalModifierCombinationForPrivateInterfaceMethod9 = MethodRelated + 1070; - /** @since 3.14 */ - int UndefinedModule = ModuleRelated + 1300; - /** @since 3.14 */ - int DuplicateRequires = ModuleRelated + 1301; - /** @since 3.14 */ - int DuplicateExports = ModuleRelated + 1302; - /** @since 3.14 */ - int DuplicateUses = ModuleRelated + 1303; - /** @since 3.14 */ - int DuplicateServices = ModuleRelated + 1304; - /** @since 3.14 */ - int CyclicModuleDependency = ModuleRelated + 1305; - /** @since 3.14 */ - int AbstractServiceImplementation = TypeRelated + 1306; - /** @since 3.14 */ - int ProviderMethodOrConstructorRequiredForServiceImpl = TypeRelated + 1307; - /** @since 3.14 */ - int ServiceImplDefaultConstructorNotPublic = TypeRelated + 1308; - /** @since 3.14 */ - int NestedServiceImpl = TypeRelated + 1309; - /** @since 3.14 */ - int ServiceImplNotDefinedByModule = TypeRelated + 1310; - /** @since 3.14 */ - int PackageDoesNotExistOrIsEmpty = ModuleRelated + 1311; - /** @since 3.14 */ - int NonDenotableTypeArgumentForAnonymousDiamond = TypeRelated + 1312; - /** @since 3.14 */ - int DuplicateOpens = ModuleRelated + 1313; - /** @since 3.14 */ - int DuplicateModuleRef = ModuleRelated + 1314; - /** @since 3.14 */ - int InvalidOpensStatement = ModuleRelated + 1315; - /** @since 3.14 */ - int InvalidServiceIntfType = ModuleRelated + 1316; - /** @since 3.14 */ - int InvalidServiceImplType = ModuleRelated + 1317; - /** @since 3.14 */ - int IllegalModifierForModule = ModuleRelated + 1318; - /** @since 3.18 */ - int UndefinedModuleAddReads = ModuleRelated + 1319; - /** @since 3.20 */ - int ExportingForeignPackage = ModuleRelated + 1320; - - - /** @since 3.14 */ - int DuplicateResource = Internal + 1251; - - /** @since 3.37 */ - int ShouldMarkMethodAsOwning = Internal + 1260; - /** @since 3.37 */ - int MandatoryCloseNotShown = Internal + 1261; - /** @since 3.37 */ - int MandatoryCloseNotShownAtExit = Internal + 1262; - /** @since 3.37 */ - int NotOwningResourceField = Internal + 1263; - /** @since 3.37 */ - int OwningFieldInNonResourceClass = Internal + 1264; - /** @since 3.37 */ - int OwningFieldShouldImplementClose = Internal + 1265; - /** @since 3.37 */ - int OverrideReducingParamterOwning = Internal + 1266; - /** @since 3.37 */ - int OverrideAddingReturnOwning = Internal + 1267; - - // terminally - /** @since 3.14 */ - int UsingTerminallyDeprecatedType = TypeRelated + 1400; - /** @since 3.14 */ - int UsingTerminallyDeprecatedMethod = MethodRelated + 1401; - /** @since 3.14 */ - int UsingTerminallyDeprecatedConstructor = MethodRelated + 1402; - /** @since 3.14 */ - int UsingTerminallyDeprecatedField = FieldRelated + 1403; - /** @since 3.14 */ - int OverridingTerminallyDeprecatedMethod = MethodRelated + 1404; - // with since - /** @since 3.14 */ - int UsingDeprecatedSinceVersionType = TypeRelated + 1405; - /** @since 3.14 */ - int UsingDeprecatedSinceVersionMethod = MethodRelated + 1406; - /** @since 3.14 */ - int UsingDeprecatedSinceVersionConstructor = MethodRelated + 1407; - /** @since 3.14 */ - int UsingDeprecatedSinceVersionField = FieldRelated + 1408; - /** @since 3.14 */ - int OverridingDeprecatedSinceVersionMethod = MethodRelated + 1409; - // terminally with since - /** @since 3.14 */ - int UsingTerminallyDeprecatedSinceVersionType = TypeRelated + 1410; - /** @since 3.14 */ - int UsingTerminallyDeprecatedSinceVersionMethod = MethodRelated + 1411; - /** @since 3.14 */ - int UsingTerminallyDeprecatedSinceVersionConstructor = MethodRelated + 1412; - /** @since 3.14 */ - int UsingTerminallyDeprecatedSinceVersionField = FieldRelated + 1413; - /** @since 3.14 */ - int OverridingTerminallyDeprecatedSinceVersionMethod = MethodRelated + 1414; - - // unused constants: - /** @since 3.14 */ - int UsingDeprecatedPackage = ModuleRelated + 1425; - /** @since 3.14 */ - int UsingDeprecatedSinceVersionPackage = ModuleRelated + 1426; - /** @since 3.14 */ - int UsingTerminallyDeprecatedPackage = ModuleRelated + 1427; - /** @since 3.14 */ - int UsingTerminallyDeprecatedSinceVersionPackage = ModuleRelated + 1428; - // deprecation of modules: - /** @since 3.14 */ - int UsingDeprecatedModule = ModuleRelated + 1429; - /** @since 3.14 */ - int UsingDeprecatedSinceVersionModule = ModuleRelated + 1430; - /** @since 3.14 */ - int UsingTerminallyDeprecatedModule = ModuleRelated + 1431; - /** @since 3.14 */ - int UsingTerminallyDeprecatedSinceVersionModule = ModuleRelated + 1432; - - /** @since 3.14 */ - int NotAccessibleType = TypeRelated + 1450; - /** @since 3.14 */ - int NotAccessibleField = FieldRelated + 1451; - /** @since 3.14 */ - int NotAccessibleMethod = MethodRelated + 1452; - /** @since 3.14 */ - int NotAccessibleConstructor = MethodRelated + 1453; - /** @since 3.14 */ - int NotAccessiblePackage = ImportRelated + 1454; - /** @since 3.14 */ - int ConflictingPackageFromModules = ModuleRelated + 1455; - /** @since 3.14 */ - int ConflictingPackageFromOtherModules = ModuleRelated + 1456; - /** @since 3.14 */ - int NonPublicTypeInAPI = ModuleRelated + 1457; - /** @since 3.14 */ - int NotExportedTypeInAPI = ModuleRelated + 1458; - /** @since 3.14 */ - int MissingRequiresTransitiveForTypeInAPI = ModuleRelated + 1459; - /** @since 3.14 */ - int UnnamedPackageInNamedModule = ModuleRelated + 1460; - /** @since 3.14 */ - int UnstableAutoModuleName = ModuleRelated + 1461; - /** @since 3.24 */ - int ConflictingPackageInModules = ModuleRelated + 1462; - - // doc variant of an above constant: - /** @since 3.22 */ - int JavadocNotAccessibleType = Javadoc + NotAccessibleType; - - /** @since 3.13 */ - int RedundantNullDefaultAnnotationLocal = Internal + 1062; - - /** @since 3.13 */ - int RedundantNullDefaultAnnotationField = Internal + 1063; - - /** @since 3.10 */ - int GenericInferenceError = 1100; // FIXME: This is just a stop-gap measure, be more specific via https://bugs.eclipse.org/404675 - - /** @deprecated - problem is no longer generated (implementation issue has been resolved) - * @since 3.10 */ - int LambdaShapeComputationError = 1101; - /** @since 3.13 */ - int ProblemNotAnalysed = 1102; - /** @since 3.18 */ - int PreviewFeatureDisabled = Compliance + 1103; - /** @since 3.18 */ - int PreviewFeatureUsed = Compliance + 1104; - /** @since 3.18 */ - int PreviewFeatureNotSupported = Compliance + 1105; - /** @since 3.20*/ - int PreviewFeaturesNotAllowed = PreviewRelated + 1106; - /** @since 3.24*/ - int FeatureNotSupported = Compliance + 1107; - /** @since 3.26*/ - int PreviewAPIUsed = Compliance + 1108; - - /** @since 3.13 */ - int UnlikelyCollectionMethodArgumentType = 1200; - /** @since 3.13 */ - int UnlikelyEqualsArgumentType = 1201; - - /* Local-Variable Type Inference */ - /** @since 3.14 */ - int VarLocalMultipleDeclarators = Syntax + 1500; // ''var'' is not allowed in a compound declaration - /** @since 3.14 */ - int VarLocalCannotBeArray = Syntax + 1501; // ''var'' is not allowed as an element type of an array - /** @since 3.14 */ - int VarLocalReferencesItself = Syntax + 1502; // Declaration using ''var'' may not contin references to itself - /** @since 3.14 */ - int VarLocalWithoutInitizalier = Syntax + 1503; // Cannot use ''var'' on variable without initializer - /** @since 3.14 */ - int VarLocalInitializedToNull = TypeRelated + 1504; // Variable initialized to ''null'' needs an explicit target-type - /** @since 3.14 */ - int VarLocalInitializedToVoid = TypeRelated + 1505; // Variable initializer is ''void'' -- cannot infer variable type - /** @since 3.14 */ - int VarLocalCannotBeArrayInitalizers = TypeRelated + 1506; // Array initializer needs an explicit target-type - /** @since 3.14 */ - int VarLocalCannotBeLambda = TypeRelated + 1507; // Lambda expression needs an explicit target-type - /** @since 3.14 */ - int VarLocalCannotBeMethodReference = TypeRelated + 1508; // Method reference needs an explicit target-type - /** @since 3.14 */ - int VarIsReserved = Syntax + 1509; // ''var'' is not a valid type name - /** @since 3.14 */ - int VarIsReservedInFuture = Syntax + 1510; // ''var'' should not be used as an type name, since it is a reserved word from source level 10 on - /** @since 3.14 */ - int VarIsNotAllowedHere = Syntax + 1511; // ''var'' is not allowed here - /** @since 3.16 */ - int VarCannotBeMixedWithNonVarParams = Syntax + 1512; // ''var'' cannot be mixed with explicit or implicit parameters - /** @since 3.35 */ - int VarCannotBeUsedWithTypeArguments = Syntax + 1513; // ''var'' cannot be used with type arguments (e.g. as in ''var x = List.of(42)'') - - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionsIncompatibleResultExpressionTypes = TypeRelated + 1600; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionsEmptySwitchBlock = Internal + 1601; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionsNoResultExpression = TypeRelated + 1602; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionSwitchLabeledBlockCompletesNormally = Internal + 1603; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionLastStatementCompletesNormally = Internal + 1604; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionTrailingSwitchLabels = Internal + 1605; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int switchMixedCase = Syntax + 1606; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionMissingDefaultCase = Internal + 1607; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionBreakMissingValue = Internal + 1610; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionMissingEnumConstantCase = Internal + 1611; - /** @since 3.18 - * @deprecated preview related error - will be removed - * @noreference preview related error */ - int SwitchExpressionIllegalLastStatement = Internal + 1612; - - /* Java14 errors - begin */ - /** @since 3.21 */ - int SwitchExpressionsYieldIncompatibleResultExpressionTypes = TypeRelated + 1700; - /** @since 3.21 */ - int SwitchExpressionsYieldEmptySwitchBlock = Syntax + 1701; - /** @since 3.21 */ - int SwitchExpressionsYieldNoResultExpression = Internal + 1702; - /** @since 3.21 */ - int SwitchExpressionaYieldSwitchLabeledBlockCompletesNormally = Internal + 1703; - /** @since 3.21 */ - int SwitchExpressionsYieldLastStatementCompletesNormally = Internal + 1704; - /** @since 3.21 */ - int SwitchExpressionsYieldTrailingSwitchLabels = Internal + 1705; - /** @since 3.21 */ - int SwitchPreviewMixedCase = Syntax + 1706; - /** @since 3.21 */ - int SwitchExpressionsYieldMissingDefaultCase = Syntax + 1707; - /** @since 3.21 */ - int SwitchExpressionsYieldMissingValue = Syntax + 1708; - /** @since 3.21 */ - int SwitchExpressionsYieldMissingEnumConstantCase = Syntax + 1709; - /** @since 3.21 */ - int SwitchExpressionsYieldIllegalLastStatement = Internal + 1710; - /** @since 3.21 */ - int SwitchExpressionsYieldBreakNotAllowed = Syntax + 1711; - /** @since 3.21 */ - int SwitchExpressionsYieldUnqualifiedMethodWarning = Syntax + 1712; - /** @since 3.21 */ - int SwitchExpressionsYieldUnqualifiedMethodError = Syntax + 1713; - /** @since 3.21 */ - int SwitchExpressionsYieldOutsideSwitchExpression = Syntax + 1714; - /** @since 3.21 */ - int SwitchExpressionsYieldRestrictedGeneralWarning = Internal + 1715; - /** @since 3.21 */ - int SwitchExpressionsYieldIllegalStatement = Internal + 1716; - /** @since 3.21 */ - int SwitchExpressionsYieldTypeDeclarationWarning = Internal + 1717; - /** @since 3.21 */ - int SwitchExpressionsYieldTypeDeclarationError = Internal + 1718; - /** @since 3.22 */ - int MultiConstantCaseLabelsNotSupported = Syntax + 1719; - /** @since 3.22*/ - int ArrowInCaseStatementsNotSupported = Syntax + 1720; - /** @since 3.22 */ - int SwitchExpressionsNotSupported = Syntax + 1721; - /** @since 3.22 */ - int SwitchExpressionsBreakOutOfSwitchExpression = Syntax + 1722; - /** @since 3.22 */ - int SwitchExpressionsContinueOutOfSwitchExpression = Syntax + 1723; - /** @since 3.22 */ - int SwitchExpressionsReturnWithinSwitchExpression = Syntax + 1724; - - /* Java 14 errors end */ - /* Java 15 errors begin */ - /* records - begin */ - - /** @since 3.26 */ - int RecordIllegalModifierForInnerRecord = TypeRelated + 1730; - /** @since 3.26 */ - int RecordIllegalModifierForRecord = TypeRelated + 1731; - /** @since 3.26 - * JLS 14 Sec 8.10.1 - * it is always a compile-time error for a record header to declare a record component with the name - * finalize, getClass, hashCode, notify, notifyAll, or toString. */ - int RecordIllegalComponentNameInRecord = TypeRelated + 1732; - /** @since 3.26 - */ - int RecordNonStaticFieldDeclarationInRecord = TypeRelated + 1733; - /** @since 3.26 - */ - int RecordAccessorMethodHasThrowsClause = TypeRelated + 1734; - /** @since 3.26 - */ - int RecordCanonicalConstructorHasThrowsClause = TypeRelated + 1735; - /** @since 3.26 - */ - int RecordCanonicalConstructorVisibilityReduced = TypeRelated + 1736; - /** @since 3.26 - */ - int RecordMultipleCanonicalConstructors = TypeRelated + 1737; - /** @since 3.26 - */ - int RecordCompactConstructorHasReturnStatement = TypeRelated + 1738; - /** @since 3.26 - */ - int RecordDuplicateComponent = TypeRelated + 1739; - /** @since 3.26 - */ - int RecordIllegalNativeModifierInRecord = TypeRelated + 1740; - /** @since 3.26 - */ - int RecordInstanceInitializerBlockInRecord = TypeRelated + 1741; - /** @since 3.26 - */ - int RestrictedTypeName = TypeRelated + 1742; - /** @since 3.26 - */ - int RecordIllegalAccessorReturnType = TypeRelated + 1743; - /** @since 3.26 - */ - int RecordAccessorMethodShouldNotBeGeneric = TypeRelated + 1744; - /** @since 3.26 - */ - int RecordAccessorMethodShouldBePublic = TypeRelated + 1745; - /** @since 3.26 - */ - int RecordCanonicalConstructorShouldNotBeGeneric = TypeRelated + 1746; - /** @since 3.26 - */ - int RecordCanonicalConstructorHasReturnStatement = TypeRelated + 1747; - /** @since 3.26 - */ - int RecordCanonicalConstructorHasExplicitConstructorCall = TypeRelated + 1748; - /** @since 3.26 - */ - int RecordCompactConstructorHasExplicitConstructorCall = TypeRelated + 1749; - /** @since 3.26 - */ - int RecordNestedRecordInherentlyStatic = TypeRelated + 1750; - /** @since 3.26 - */ - int RecordAccessorMethodShouldNotBeStatic= TypeRelated + 1751; - /** @since 3.26 - */ - int RecordCannotExtendRecord= TypeRelated + 1752; - /** @since 3.26 - */ - int RecordComponentCannotBeVoid= TypeRelated + 1753; - /** @since 3.26 - */ - int RecordIllegalVararg= TypeRelated + 1754; - /** @since 3.26 - */ - int RecordStaticReferenceToOuterLocalVariable= TypeRelated + 1755; - /** @since 3.26 - */ - int RecordCannotDefineRecordInLocalType= TypeRelated + 1756; - /** @since 3.26 - */ - int RecordComponentsCannotHaveModifiers= TypeRelated + 1757; - /** @since 3.26 - */ - int RecordIllegalParameterNameInCanonicalConstructor = TypeRelated + 1758; - /** @since 3.26 - */ - int RecordIllegalExplicitFinalFieldAssignInCompactConstructor = TypeRelated + 1759; - /** @since 3.26 - */ - int RecordMissingExplicitConstructorCallInNonCanonicalConstructor= TypeRelated + 1760; - /** @since 3.26 - */ - int RecordIllegalStaticModifierForLocalClassOrInterface = TypeRelated + 1761; - /** @since 3.26 - */ - int RecordIllegalModifierForLocalRecord = TypeRelated + 1762; - /** @since 3.26 - */ - int RecordIllegalExtendedDimensionsForRecordComponent = Syntax + Internal + 1763; - /** @since 3.26 - */ - int SafeVarargsOnSyntheticRecordAccessor = TypeRelated + 1764; - - - /* records - end */ - /* Local and Nested Static Declarations - Begin */ - /** @since 3.28 */ - int LocalStaticsIllegalVisibilityModifierForInterfaceLocalType = TypeRelated + 1765; - /** @since 3.28 */ - int IllegalModifierForLocalEnumDeclaration = TypeRelated + 1766; - /** @since 3.28 */ - int ClassExtendFinalRecord = TypeRelated + 1767; - /** @since 3.29 */ - int RecordErasureIncompatibilityInCanonicalConstructor = TypeRelated + 1768; - /* records - end */ - - - /* instanceof pattern: */ - /** @since 3.22 - * @deprecated problem no longer generated */ - int PatternVariableNotInScope = PreviewRelated + 1780; - /** @since 3.26 - */ - int PatternVariableRedefined = Internal + 1781; - /** @since 3.26 - * @deprecated - */ - int PatternSubtypeOfExpression = Internal + 1782; - /** @since 3.26 - */ - int IllegalModifierForPatternVariable = Internal + 1783; - /** @since 3.26 - */ - int PatternVariableRedeclared = Internal + 1784; - - /** @since 3.28 - */ - int DiscouragedValueBasedTypeSynchronization = Internal + 1820; - - /** @since 3.28 */ - int SealedMissingClassModifier = TypeRelated + 1850; - /** @since 3.28 */ - int SealedDisAllowedNonSealedModifierInClass = TypeRelated + 1851; - /** @since 3.28 */ - int SealedSuperClassDoesNotPermit = TypeRelated + 1852; - /** @since 3.28 */ - int SealedSuperInterfaceDoesNotPermit = TypeRelated + 1853; - /** @since 3.28 */ - int SealedMissingSealedModifier = TypeRelated + 1854; - /** @since 3.28 */ - int SealedMissingInterfaceModifier = TypeRelated + 1855; - /** @since 3.28 */ - int SealedDuplicateTypeInPermits = TypeRelated + 1856; - /** @since 3.28 */ - int SealedNotDirectSuperClass = TypeRelated + 1857; - /** @since 3.28 */ - int SealedPermittedTypeOutsideOfModule = TypeRelated + 1858; - /** @since 3.28 */ - int SealedPermittedTypeOutsideOfPackage = TypeRelated + 1859; - /** @since 3.28 */ - int SealedSealedTypeMissingPermits = TypeRelated + 1860; - /** @since 3.28 */ - int SealedInterfaceIsSealedAndNonSealed = TypeRelated + 1861; - /** @since 3.28 */ - int SealedDisAllowedNonSealedModifierInInterface = TypeRelated + 1862; - /** @since 3.28 */ - int SealedNotDirectSuperInterface = TypeRelated + 1863; - /** @since 3.28 */ - int SealedLocalDirectSuperTypeSealed = TypeRelated + 1864; - /** @since 3.28 */ - int SealedAnonymousClassCannotExtendSealedType = TypeRelated + 1865; - /** @since 3.28 */ - int SealedSuperTypeInDifferentPackage = TypeRelated + 1866; - /** @since 3.28 */ - int SealedSuperTypeDisallowed = TypeRelated + 1867; - /* Java15 errors - end */ - - /** - * @since 3.28 - * @noreference preview feature error - */ - int LocalReferencedInGuardMustBeEffectivelyFinal = PreviewRelated + 1900; - /** @since 3.28 - * @noreference preview feature error */ - int ConstantWithPatternIncompatible = PreviewRelated + 1901; - /** - * @since 3.28 - * @noreference preview feature error - */ - int IllegalFallthroughToPattern = PreviewRelated + 1902; - - /** @since 3.28 - * @noreference preview feature error */ - int PatternDominated = PreviewRelated + 1906; - /** @since 3.28 - * @noreference preview feature error */ - int IllegalTotalPatternWithDefault = PreviewRelated + 1907; - /** @since 3.28 - * @noreference preview feature error */ - int EnhancedSwitchMissingDefault = PreviewRelated + 1908; - /** @since 3.28 - * @noreference preview feature error */ - int DuplicateTotalPattern = PreviewRelated + 1909; - - /** @since 3.34 - * @noreference preview feature error */ - int PatternSwitchNullOnlyOrFirstWithDefault = PreviewRelated + 1920; - - /** @since 3.34 - * @noreference preview feature error */ - int PatternSwitchCaseDefaultOnlyAsSecond = PreviewRelated + 1921; - - /** - * @since 3.34 - * @noreference preview feature error - */ - int IllegalFallthroughFromAPattern = PreviewRelated + 1922; - - /** @since 3.28 - * @noreference preview feature error */ - int UnnecessaryNullCaseInSwitchOverNonNull = PreviewRelated + 1910; - /** @since 3.28 - * @noreference preview feature error */ - int UnexpectedTypeinSwitchPattern = PreviewRelated + 1911; - /** - * @since 3.32 - * @noreference preview feature - */ - int UnexpectedTypeinRecordPattern = PreviewRelated + 1912; - /** - * @since 3.32 - * @noreference preview feature - */ - int RecordPatternMismatch = PreviewRelated + 1913; - /** - * @since 3.32 - * @noreference preview feature - */ - int PatternTypeMismatch = PreviewRelated + 1914; - /** - * @since 3.32 - * @noreference preview feature - * @deprecated - */ - int RawTypeInRecordPattern = PreviewRelated + 1915; - /** - * @since 3.36 - * @noreference preview feature - */ - int FalseConstantInGuard = PreviewRelated + 1916; - /** - * @since 3.34 - * @noreference preview feature - */ - int CannotInferRecordPatternTypes = PreviewRelated + 1940; - - /** - * @since 3.36 - */ - int IllegalRecordPattern = TypeRelated + 1941; - - - /** - * @since 3.35 - */ - int SyntheticAccessorNotEnclosingMethod = MethodRelated + 1990; - - /** - * @since 3.37 - * @noreference preview feature - */ - int UnderscoreCannotBeUsedHere = PreviewRelated + 2000; - /** - * @since 3.37 - * @noreference preview feature - */ - int UnnamedVariableMustHaveInitializer = PreviewRelated + 2001; -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/InvalidInputException.java b/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/InvalidInputException.java deleted file mode 100644 index 5887161..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/InvalidInputException.java +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2008 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.core.compiler; - -/** - * Exception thrown by a scanner when encountering lexical errors. - * - * @noinstantiate This class is not intended to be instantiated by clients. - * @noextend This class is not intended to be subclassed by clients. - */ -public class InvalidInputException extends Exception { - - private static final long serialVersionUID = 2909732853499731592L; // backward compatible - -/** - * Creates a new exception with no detail message. - */ -public InvalidInputException() { - super(); -} - -/** - * Creates a new exception with the given detail message. - * @param message the detail message - */ -public InvalidInputException(String message) { - super(message); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/SubwordMatcher.java b/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/SubwordMatcher.java deleted file mode 100644 index 9886aef..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/SubwordMatcher.java +++ /dev/null @@ -1,160 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 Julian Honnen. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Julian Honnen - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.core.compiler; - -import java.util.Arrays; -import java.util.BitSet; - -import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; - -class SubwordMatcher { - - private static final int[] EMPTY_REGIONS = new int[0]; - - private final char[] name; - private final BitSet wordBoundaries; - - public SubwordMatcher(String name) { - this.name = name.toCharArray(); - this.wordBoundaries = new BitSet(name.length()); - - for (int i = 0; i < this.name.length; i++) { - if (isWordBoundary(caseAt(i - 1), caseAt(i), caseAt(i + 1))) { - this.wordBoundaries.set(i); - } - } - } - - private Case caseAt(int index) { - if (index < 0 || index >= this.name.length) - return Case.SEPARATOR; - - char c = this.name[index]; - if (c == '_') - return Case.SEPARATOR; - if (ScannerHelper.isUpperCase(c)) - return Case.UPPER; - return Case.LOWER; - } - - private static boolean isWordBoundary(Case p, Case c, Case n) { - if (p == c && c == n) - return false; // a boundary needs some kind of gradient - - if (p == Case.SEPARATOR) - return true; // boundary after every separator - - // the remaining cases are boundaries for capitalization changes: - // lowerUpper, UPPERLower, lowerUPPER - // ^ ^ ^ - return (c == Case.UPPER) && (p == Case.LOWER || n == Case.LOWER); - } - - private enum Case { - SEPARATOR, LOWER, UPPER - } - - public int[] getMatchingRegions(String pattern) { - int segmentStart = 0; - int[] segments = EMPTY_REGIONS; - - // Main loop is on pattern characters - int iName = -1; - int iPatternWordStart = 0; - for (int iPattern = 0; iPattern < pattern.length(); iPattern++) { - iName++; - if (iName == this.name.length) { - // We have exhausted the name (and not the pattern), so it's not a match - return null; - } - - char patternChar = pattern.charAt(iPattern); - char nameChar = this.name[iName]; - - // For as long as we're exactly matching, bring it on - if (patternChar == nameChar) { - continue; - } - if (!isWordBoundary(iName) && equalsIgnoreCase(patternChar, nameChar)) { - // we're not at a word boundary, case-insensitive match is fine - continue; - } - - // not matching, record previous segment and find next word match in name - if (iName > segmentStart) { - segments = Arrays.copyOf(segments, segments.length + 2); - segments[segments.length - 2] = segmentStart; - segments[segments.length - 1] = iName - segmentStart; - } - - int wordStart = indexOfWordStart(iName, patternChar); - if (wordStart < 0) { - // no matching word found, backtrack and try to find next occurrence of current word - int next = indexOfWordStart(iName, pattern.charAt(iPatternWordStart)); - if (next > 0) { - wordStart = next; - iPattern = iPatternWordStart; - // last recorded segment was invalid -> drop it - segments = Arrays.copyOfRange(segments, 0, segments.length - 2); - } - } - - if (wordStart < 0) { - // We have exhausted name (and not pattern), so it's not a match - return null; - } - - segmentStart = wordStart; - iName = wordStart; - iPatternWordStart = iPattern; - } - - // we have exhausted pattern, record final segment - segments = Arrays.copyOf(segments, segments.length + 2); - segments[segments.length - 2] = segmentStart; - segments[segments.length - 1] = iName - segmentStart + 1; - - return segments; - } - - /** - * Returns the index of the first word after nameStart, beginning with patternChar. Returns -1 if no matching word - * is found. - */ - private int indexOfWordStart(int nameStart, char patternChar) { - - for (int iName = nameStart; iName < this.name.length; iName++) { - char nameChar = this.name[iName]; - if (isWordBoundary(iName) && equalsIgnoreCase(nameChar, patternChar)) { - return iName; - } - - // don't match across identifiers (e.g. "index" should not match "substring(int beginIndex)") - if (!ScannerHelper.isJavaIdentifierPart(nameChar)) { - return -1; - } - } - - // We have exhausted name - return -1; - } - - private boolean equalsIgnoreCase(char a, char b) { - return ScannerHelper.toLowerCase(a) == ScannerHelper.toLowerCase(b); - } - - private boolean isWordBoundary(int iName) { - return this.wordBoundaries.get(iName); - } -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/batch/BatchCompiler.java b/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/batch/BatchCompiler.java deleted file mode 100644 index 7e4ca11..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/batch/BatchCompiler.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.core.compiler.batch; - -import java.io.PrintWriter; - -import org.eclipse.jdt.core.compiler.CompilationProgress; -import org.eclipse.jdt.internal.compiler.batch.Main; - -/** - * A public API for invoking the Eclipse Compiler for Java. E.g. - *
- * BatchCompiler.compile("C:\\mySources\\X.java -d C:\\myOutput", new PrintWriter(System.out), new PrintWriter(System.err), null);
- * 
- * - * @since 3.4 - * @noinstantiate This class is not intended to be instantiated by clients. - */ -public final class BatchCompiler { - - /** - * Invokes the Eclipse Compiler for Java with the given command line arguments, using the given writers - * to print messages, and reporting progress to the given compilation progress. Returns whether - * the compilation completed successfully. - *

- * Reasons for a compilation failing to complete successfully include:

- *
    - *
  • an error was reported
  • - *
  • a runtime exception occurred
  • - *
  • the compilation was canceled using the compilation progress
  • - *
- *

- * The specification of the command line arguments is defined by running the batch compiler's help - *

BatchCompiler.compile("-help", new PrintWriter(System.out), new PrintWriter(System.err), null);
- * - * @param commandLine the command line arguments passed to the compiler - * @param outWriter the writer used to print standard messages - * @param errWriter the writer used to print error messages - * @param progress the object to report progress to and to provide cancellation, or null if no progress is needed - * @return whether the compilation completed successfully - */ - public static boolean compile(String commandLine, PrintWriter outWriter, PrintWriter errWriter, CompilationProgress progress) { - return compile(Main.tokenize(commandLine), outWriter, errWriter, progress); - } - - /** - * Invokes the Eclipse Compiler for Java with the given command line arguments, using the given writers - * to print messages, and reporting progress to the given compilation progress. Returns whether - * the compilation completed successfully. - *

- * Reasons for a compilation failing to complete successfully include:

- *
    - *
  • an error was reported
  • - *
  • a runtime exception occurred
  • - *
  • the compilation was canceled using the compilation progress
  • - *
- *

- * The specification of the command line arguments is defined by running the batch compiler's help - *

BatchCompiler.compile("-help", new PrintWriter(System.out), new PrintWriter(System.err), null);
- *

- * Note that a true returned value indicates that no errors were reported, no runtime exceptions - * occurred and that the compilation was not canceled. - * - * @param commandLineArguments the command line arguments passed to the compiler - * @param outWriter the writer used to print standard messages - * @param errWriter the writer used to print error messages - * @param progress the object to report progress to and to provide cancellation, or null if no progress is needed - * @return whether the compilation completed successfully - */ - public static boolean compile(String[] commandLineArguments, PrintWriter outWriter, PrintWriter errWriter, CompilationProgress progress) { - return Main.compile(commandLineArguments, outWriter, errWriter, progress); - } - - private BatchCompiler() { - // prevent instantiation - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/batch/package.html b/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/batch/package.html deleted file mode 100644 index cf3bc8a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/batch/package.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - Package-level Javadoc - - -This package contains the batch compiler API. -

-Package Specification

- -


This package contains the batch compiler API. - - diff --git a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/package.html b/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/package.html deleted file mode 100644 index b039ea2..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/core/compiler/package.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - Package-level Javadoc - - -This package contains compiler associated infrastructure APIs. -

-Package Specification

- -


This package contains some compiler tooling APIs, allowing to perform operations at a lower-level -than using the JavaModel. - - diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ASTVisitor.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ASTVisitor.java deleted file mode 100644 index 65f9d36..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ASTVisitor.java +++ /dev/null @@ -1,1022 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler; - -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.ast.*; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; - -/** - * A visitor for iterating through the parse tree. - */ -public abstract class ASTVisitor { - public void acceptProblem(IProblem problem) { - // do nothing by default - } - public void endVisit( - AllocationExpression allocationExpression, - BlockScope scope) { - // do nothing by default - } - public void endVisit(AND_AND_Expression and_and_Expression, BlockScope scope) { - // do nothing by default - } - public void endVisit( - AnnotationMethodDeclaration annotationTypeDeclaration, - ClassScope classScope) { - // do nothing by default - } - public void endVisit(TypePattern anyPattern, BlockScope scope) { - // do nothing by default - } - public void endVisit(Argument argument, BlockScope scope) { - // do nothing by default - } - public void endVisit(Argument argument,ClassScope scope) { - // do nothing by default - } - public void endVisit( - ArrayAllocationExpression arrayAllocationExpression, - BlockScope scope) { - // do nothing by default - } - public void endVisit(ArrayInitializer arrayInitializer, BlockScope scope) { - // do nothing by default - } - public void endVisit(ArrayInitializer arrayInitializer, ClassScope scope) { - // do nothing by default - } - public void endVisit( - ArrayQualifiedTypeReference arrayQualifiedTypeReference, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - ArrayQualifiedTypeReference arrayQualifiedTypeReference, - ClassScope scope) { - // do nothing by default - } - public void endVisit(ArrayReference arrayReference, BlockScope scope) { - // do nothing by default - } - public void endVisit(ArrayTypeReference arrayTypeReference, BlockScope scope) { - // do nothing by default - } - public void endVisit(ArrayTypeReference arrayTypeReference, ClassScope scope) { - // do nothing by default - } - public void endVisit(AssertStatement assertStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(Assignment assignment, BlockScope scope) { - // do nothing by default - } - public void endVisit(BinaryExpression binaryExpression, BlockScope scope) { - // do nothing by default - } - public void endVisit(Block block, BlockScope scope) { - // do nothing by default - } - public void endVisit(BreakStatement breakStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(CaseStatement caseStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(CastExpression castExpression, BlockScope scope) { - // do nothing by default - } - public void endVisit(CharLiteral charLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(ClassLiteralAccess classLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(Clinit clinit, ClassScope scope) { - // do nothing by default - } - public void endVisit(CompactConstructorDeclaration ccd, ClassScope scope) { - // do nothing by default - } - public void endVisit( - CompilationUnitDeclaration compilationUnitDeclaration, - CompilationUnitScope scope) { - // do nothing by default - } - public void endVisit(CompoundAssignment compoundAssignment, BlockScope scope) { - // do nothing by default - } - public void endVisit( - ConditionalExpression conditionalExpression, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - ConstructorDeclaration constructorDeclaration, - ClassScope scope) { - // do nothing by default - } - public void endVisit(ContinueStatement continueStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(DoStatement doStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(DoubleLiteral doubleLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(EmptyStatement emptyStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(EqualExpression equalExpression, BlockScope scope) { - // do nothing by default - } - public void endVisit( - ExplicitConstructorCall explicitConstructor, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - ExtendedStringLiteral extendedStringLiteral, - BlockScope scope) { - // do nothing by default - } - public void endVisit(FakeDefaultLiteral fakeDefaultLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(FalseLiteral falseLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(FieldDeclaration fieldDeclaration, MethodScope scope) { - // do nothing by default - } - public void endVisit(FieldReference fieldReference, BlockScope scope) { - // do nothing by default - } - public void endVisit(FieldReference fieldReference, ClassScope scope) { - // do nothing by default - } - public void endVisit(FloatLiteral floatLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(ForeachStatement forStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(ForStatement forStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(GuardedPattern guardedPattern, BlockScope scope) { - // do nothing by default, keep traversing - } - public void endVisit(IfStatement ifStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(ImportReference importRef, CompilationUnitScope scope) { - // do nothing by default - } - public void endVisit(Initializer initializer, MethodScope scope) { - // do nothing by default - } - public void endVisit( - InstanceOfExpression instanceOfExpression, - BlockScope scope) { - // do nothing by default - } - public void endVisit(IntLiteral intLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(Javadoc javadoc, BlockScope scope) { - // do nothing by default - } - public void endVisit(Javadoc javadoc, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocAllocationExpression expression, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocAllocationExpression expression, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocArgumentExpression expression, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocArgumentExpression expression, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocArrayQualifiedTypeReference typeRef, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocArrayQualifiedTypeReference typeRef, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocArraySingleTypeReference typeRef, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocArraySingleTypeReference typeRef, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocFieldReference fieldRef, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocFieldReference fieldRef, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocImplicitTypeReference implicitTypeReference, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocImplicitTypeReference implicitTypeReference, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocMessageSend messageSend, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocMessageSend messageSend, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocQualifiedTypeReference typeRef, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocQualifiedTypeReference typeRef, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocModuleReference moduleRef, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocModuleReference moduleRef, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocReturnStatement statement, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocReturnStatement statement, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocSingleNameReference argument, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocSingleNameReference argument, ClassScope scope) { - // do nothing by default - } - public void endVisit(JavadocSingleTypeReference typeRef, BlockScope scope) { - // do nothing by default - } - public void endVisit(JavadocSingleTypeReference typeRef, ClassScope scope) { - // do nothing by default - } - public void endVisit(LabeledStatement labeledStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(LocalDeclaration localDeclaration, BlockScope scope) { - // do nothing by default - } - public void endVisit(LongLiteral longLiteral, BlockScope scope) { - // do nothing by default - } - /** - * @since 3.1 - */ - public void endVisit(MarkerAnnotation annotation, BlockScope scope) { - // do nothing by default - } - public void endVisit(MarkerAnnotation annotation, ClassScope scope) { - // do nothing by default - } - public void endVisit(MemberValuePair pair, BlockScope scope) { - // do nothing by default - } - public void endVisit(MemberValuePair pair, ClassScope scope) { - // do nothing by default - } - public void endVisit(MessageSend messageSend, BlockScope scope) { - // do nothing by default - } - public void endVisit(MethodDeclaration methodDeclaration, ClassScope scope) { - // do nothing by default - } - public void endVisit(StringLiteralConcatenation literal, BlockScope scope) { - // do nothing by default - } - /** - * @since 3.1 - */ - public void endVisit(NormalAnnotation annotation, BlockScope scope) { - // do nothing by default - } - public void endVisit(NormalAnnotation annotation, ClassScope scope) { - // do nothing by default - } - public void endVisit(NullLiteral nullLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(OR_OR_Expression or_or_Expression, BlockScope scope) { - // do nothing by default - } - public void endVisit(Pattern patternExpression, BlockScope scope) { - // do nothing by default - } - public void endVisit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, BlockScope scope) { - // do nothing by default - } - public void endVisit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, ClassScope scope) { - // do nothing by default - } - public void endVisit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, BlockScope scope) { - // do nothing by default - } - public void endVisit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, ClassScope scope) { - // do nothing by default - } - public void endVisit(PostfixExpression postfixExpression, BlockScope scope) { - // do nothing by default - } - public void endVisit(PrefixExpression prefixExpression, BlockScope scope) { - // do nothing by default - } - public void endVisit( - QualifiedAllocationExpression qualifiedAllocationExpression, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - QualifiedNameReference qualifiedNameReference, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - QualifiedNameReference qualifiedNameReference, - ClassScope scope) { - // do nothing by default - } - public void endVisit( - QualifiedSuperReference qualifiedSuperReference, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - QualifiedSuperReference qualifiedSuperReference, - ClassScope scope) { - // do nothing by default - } - public void endVisit( - QualifiedThisReference qualifiedThisReference, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - QualifiedThisReference qualifiedThisReference, - ClassScope scope) { - // do nothing by default - } - public void endVisit( - QualifiedTypeReference qualifiedTypeReference, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - QualifiedTypeReference qualifiedTypeReference, - ClassScope scope) { - // do nothing by default - } - public void endVisit(RecordPattern recordPattern, BlockScope scope) { - // do nothing by default - } - public void endVisit(ReturnStatement returnStatement, BlockScope scope) { - // do nothing by default - } - /** - * @since 3.1 - */ - public void endVisit(SingleMemberAnnotation annotation, BlockScope scope) { - // do nothing by default - } - public void endVisit(SingleMemberAnnotation annotation, ClassScope scope) { - // do nothing by default - } - public void endVisit( - SingleNameReference singleNameReference, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - SingleNameReference singleNameReference, - ClassScope scope) { - // do nothing by default - } - public void endVisit( - SingleTypeReference singleTypeReference, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - SingleTypeReference singleTypeReference, - ClassScope scope) { - // do nothing by default - } - public void endVisit(StringLiteral stringLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(SuperReference superReference, BlockScope scope) { - // do nothing by default - } - public void endVisit(SwitchStatement switchStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit( - SynchronizedStatement synchronizedStatement, - BlockScope scope) { - // do nothing by default - } - public void endVisit(ThisReference thisReference, BlockScope scope) { - // do nothing by default - } - public void endVisit(ThisReference thisReference, ClassScope scope) { - // do nothing by default - } - public void endVisit(ThrowStatement throwStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(TrueLiteral trueLiteral, BlockScope scope) { - // do nothing by default - } - public void endVisit(TryStatement tryStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit( - TypeDeclaration localTypeDeclaration, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - TypeDeclaration memberTypeDeclaration, - ClassScope scope) { - // do nothing by default - } - public void endVisit( - TypeDeclaration typeDeclaration, - CompilationUnitScope scope) { - // do nothing by default - } - public void endVisit(TypeParameter typeParameter, BlockScope scope) { - // do nothing by default - } - public void endVisit(TypeParameter typeParameter, ClassScope scope) { - // do nothing by default - } - public void endVisit(UnaryExpression unaryExpression, BlockScope scope) { - // do nothing by default - } - public void endVisit( - UnionTypeReference unionTypeReference, - BlockScope scope) { - // do nothing by default - } - public void endVisit( - UnionTypeReference unionTypeReference, - ClassScope scope) { - // do nothing by default - } - public void endVisit(YieldStatement yieldStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(WhileStatement whileStatement, BlockScope scope) { - // do nothing by default - } - public void endVisit(Wildcard wildcard, BlockScope scope) { - // do nothing by default - } - public void endVisit(Wildcard wildcard, ClassScope scope) { - // do nothing by default - } - public void endVisit(LambdaExpression lambdaExpression, BlockScope blockScope) { - // do nothing by default - } - public void endVisit(ReferenceExpression referenceExpression, BlockScope blockScope) { - // do nothing by default - } - public void endVisit(IntersectionCastTypeReference intersectionCastTypeReference, ClassScope scope) { - // do nothing by default - } - public void endVisit(IntersectionCastTypeReference intersectionCastTypeReference, BlockScope scope) { - // do nothing by default - } - public void endVisit(SwitchExpression switchExpression, BlockScope scope) { - // do nothing by default - } - public void endVisit(RecordComponent recordComponent, BlockScope scope) { - // do nothing by default, keep traversing - } - public boolean visit(RecordPattern recordPattern, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - AllocationExpression allocationExpression, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(AND_AND_Expression and_and_Expression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - AnnotationMethodDeclaration annotationTypeDeclaration, - ClassScope classScope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(TypePattern anyPattern, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Argument argument, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Argument argument, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - ArrayAllocationExpression arrayAllocationExpression, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ArrayInitializer arrayInitializer, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ArrayInitializer arrayInitializer, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - ArrayQualifiedTypeReference arrayQualifiedTypeReference, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - ArrayQualifiedTypeReference arrayQualifiedTypeReference, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ArrayReference arrayReference, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ArrayTypeReference arrayTypeReference, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ArrayTypeReference arrayTypeReference, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(AssertStatement assertStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Assignment assignment, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(BinaryExpression binaryExpression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Block block, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(BreakStatement breakStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(CaseStatement caseStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(CastExpression castExpression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(CharLiteral charLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ClassLiteralAccess classLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Clinit clinit, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ModuleDeclaration module, CompilationUnitScope scope) { - return true; - } - public boolean visit(CompactConstructorDeclaration ccd, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - CompilationUnitDeclaration compilationUnitDeclaration, - CompilationUnitScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(CompoundAssignment compoundAssignment, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - ConditionalExpression conditionalExpression, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - ConstructorDeclaration constructorDeclaration, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ContinueStatement continueStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(DoStatement doStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(DoubleLiteral doubleLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(EmptyStatement emptyStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(EqualExpression equalExpression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - ExplicitConstructorCall explicitConstructor, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - ExtendedStringLiteral extendedStringLiteral, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(FakeDefaultLiteral fakeDefaultLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(FalseLiteral falseLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(FieldReference fieldReference, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(FieldReference fieldReference, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(FloatLiteral floatLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ForeachStatement forStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ForStatement forStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(GuardedPattern guardedPattern, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(IfStatement ifStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ImportReference importRef, CompilationUnitScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Initializer initializer, MethodScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - InstanceOfExpression instanceOfExpression, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(IntLiteral intLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Javadoc javadoc, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Javadoc javadoc, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocAllocationExpression expression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocAllocationExpression expression, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocArgumentExpression expression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocArgumentExpression expression, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocArrayQualifiedTypeReference typeRef, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocArrayQualifiedTypeReference typeRef, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocArraySingleTypeReference typeRef, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocArraySingleTypeReference typeRef, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocFieldReference fieldRef, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocFieldReference fieldRef, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocImplicitTypeReference implicitTypeReference, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocImplicitTypeReference implicitTypeReference, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocMessageSend messageSend, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocMessageSend messageSend, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocQualifiedTypeReference typeRef, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocQualifiedTypeReference typeRef, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocModuleReference moduleRef, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocModuleReference moduleRef, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocReturnStatement statement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocReturnStatement statement, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocSingleNameReference argument, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocSingleNameReference argument, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocSingleTypeReference typeRef, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(JavadocSingleTypeReference typeRef, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(LabeledStatement labeledStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(LongLiteral longLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - /** - * @since 3.1 - */ - public boolean visit(MarkerAnnotation annotation, BlockScope scope) { - return true; - } - public boolean visit(MarkerAnnotation annotation, ClassScope scope) { - return true; - } - /** - * @since 3.1 - */ - public boolean visit(MemberValuePair pair, BlockScope scope) { - return true; - } - public boolean visit(MemberValuePair pair, ClassScope scope) { - return true; - } - public boolean visit(MessageSend messageSend, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - StringLiteralConcatenation literal, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - /** - * @since 3.1 - */ - public boolean visit(NormalAnnotation annotation, BlockScope scope) { - return true; - } - public boolean visit(NormalAnnotation annotation, ClassScope scope) { - return true; - } - public boolean visit(NullLiteral nullLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(OR_OR_Expression or_or_Expression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Pattern patternExpression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(PostfixExpression postfixExpression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(PrefixExpression prefixExpression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - QualifiedAllocationExpression qualifiedAllocationExpression, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - QualifiedNameReference qualifiedNameReference, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - QualifiedNameReference qualifiedNameReference, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - QualifiedSuperReference qualifiedSuperReference, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - QualifiedSuperReference qualifiedSuperReference, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - QualifiedThisReference qualifiedThisReference, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - QualifiedThisReference qualifiedThisReference, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - QualifiedTypeReference qualifiedTypeReference, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - QualifiedTypeReference qualifiedTypeReference, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ReturnStatement returnStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - /** - * @since 3.1 - */ - public boolean visit(SingleMemberAnnotation annotation, BlockScope scope) { - return true; - } - public boolean visit(SingleMemberAnnotation annotation, ClassScope scope) { - return true; - } - public boolean visit( - SingleNameReference singleNameReference, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - SingleNameReference singleNameReference, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - SingleTypeReference singleTypeReference, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - SingleTypeReference singleTypeReference, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(StringLiteral stringLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(SuperReference superReference, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(SwitchStatement switchStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - SynchronizedStatement synchronizedStatement, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ThisReference thisReference, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ThisReference thisReference, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ThrowStatement throwStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(TrueLiteral trueLiteral, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(TryStatement tryStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - TypeDeclaration localTypeDeclaration, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - TypeDeclaration memberTypeDeclaration, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - TypeDeclaration typeDeclaration, - CompilationUnitScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(TypeParameter typeParameter, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(TypeParameter typeParameter, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(UnaryExpression unaryExpression, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - UnionTypeReference unionTypeReference, - BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit( - UnionTypeReference unionTypeReference, - ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(YieldStatement yieldStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(WhileStatement whileStatement, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Wildcard wildcard, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(Wildcard wildcard, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(LambdaExpression lambdaExpression, BlockScope blockScope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(ReferenceExpression referenceExpression, BlockScope blockScope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(IntersectionCastTypeReference intersectionCastTypeReference, ClassScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(IntersectionCastTypeReference intersectionCastTypeReference, BlockScope scope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(SwitchExpression switchExpression, BlockScope blockScope) { - return true; // do nothing by default, keep traversing - } - public boolean visit(RecordComponent recordComponent, BlockScope scope) { - return true; // do nothing by default, keep traversing - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/AbstractAnnotationProcessorManager.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/AbstractAnnotationProcessorManager.java deleted file mode 100644 index 5eecab8..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/AbstractAnnotationProcessorManager.java +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * BEA - Patch for bug 172743 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler; - -import java.io.PrintWriter; - -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; - -public abstract class AbstractAnnotationProcessorManager { - /** - * Configure the receiver using the given batch compiler and the given options. - * The parameter batchCompiler is expected to be an instance of the batch compiler. This method is - * only used for the batch mode. For the IDE mode, please see {@link #configureFromPlatform(Compiler, Object, Object, boolean)}. - * - * @param batchCompiler the given batch compiler object - * @param options the given options - */ - public abstract void configure(Object batchCompiler, String[] options); - - /** - * Configure the receiver using the given compiler, the given compilationUnitLocator and - * the given java project. - * - * @param compiler the given compiler - * @param compilationUnitLocator the given compilation unit locator - * @param javaProject the given java project - */ - public abstract void configureFromPlatform(Compiler compiler, Object compilationUnitLocator, Object javaProject, boolean isTestCode); - - /** - * Set the print writer for the standard output. - * - * @param out the given print writer for output - */ - public abstract void setOut(PrintWriter out); - - /** - * Set the print writer for the standard error. - * - * @param err the given print writer for error - */ - public abstract void setErr(PrintWriter err); - - /** - * Return the new units created in the last round. - * - * @return the new units created in the last round - */ - public abstract ICompilationUnit[] getNewUnits(); - - /** - * Return the new binary bindings created in the last round. - * - * @return the new binary bindings created in the last round - */ - public abstract ReferenceBinding[] getNewClassFiles(); - - /** - * Returns the deleted units. - * @return the deleted units - */ - public abstract ICompilationUnit[] getDeletedUnits(); - - /** - * Reinitialize the receiver - */ - public abstract void reset(); - - /** - * Final cleanup after all rounds have completed. - */ - protected void cleanUp() { - // default: do nothing, because reset() already did the common work - } - - /** - * Run a new annotation processing round on the given values. - * - * @param units the given source type - * @param referenceBindings the given binary types - * @param isLastRound flag to notify the last round - */ - public abstract void processAnnotations(CompilationUnitDeclaration[] units, ReferenceBinding[] referenceBindings, boolean isLastRound); - - /** - * Set the processors for annotation processing. - * - * @param processors the given processors - */ - public abstract void setProcessors(Object[] processors); -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ClassFile.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ClassFile.java deleted file mode 100644 index 5d7b9d3..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ClassFile.java +++ /dev/null @@ -1,7962 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Jesper S Moller - Contributions for - * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 - * Bug 406982 - [1.8][compiler] Generation of MethodParameters Attribute in classfile - * Bug 416885 - [1.8][compiler]IncompatibleClassChange error (edit) - * Bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - * Bug 409236 - [1.8][compiler] Type annotations on intersection cast types dropped by code generator - * Bug 409246 - [1.8][compiler] Type annotations on catch parameters not handled properly - * Bug 415541 - [1.8][compiler] Type annotations in the body of static initializer get dropped - * Bug 415399 - [1.8][compiler] Type annotations on constructor results dropped by the code generator - * Bug 415470 - [1.8][compiler] Type annotations on class declaration go vanishing - * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas - * Bug 434556 - Broken class file generated for incorrect annotation usage - * Bug 442416 - $deserializeLambda$ missing cases for nested lambdas - * Stephan Herrmann - Contribution for - * Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables - * Olivier Tardieu tardieu@us.ibm.com - Contributions for - * Bug 442416 - $deserializeLambda$ missing cases for nested lambdas - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -import org.eclipse.jdt.core.compiler.CategorizedProblem; -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.core.compiler.IProblem; -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.AnnotationMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Argument; -import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; -import org.eclipse.jdt.internal.compiler.ast.CaseStatement; -import org.eclipse.jdt.internal.compiler.ast.CaseStatement.ResolvedCase; -import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.ast.ExportsStatement; -import org.eclipse.jdt.internal.compiler.ast.Expression; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; -import org.eclipse.jdt.internal.compiler.ast.FunctionalExpression; -import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; -import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; -import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; -import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration; -import org.eclipse.jdt.internal.compiler.ast.NormalAnnotation; -import org.eclipse.jdt.internal.compiler.ast.NullLiteral; -import org.eclipse.jdt.internal.compiler.ast.OpensStatement; -import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference; -import org.eclipse.jdt.internal.compiler.ast.Receiver; -import org.eclipse.jdt.internal.compiler.ast.RecordComponent; -import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression; -import org.eclipse.jdt.internal.compiler.ast.RequiresStatement; -import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation; -import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; -import org.eclipse.jdt.internal.compiler.ast.StringLiteral; -import org.eclipse.jdt.internal.compiler.ast.StringTemplate; -import org.eclipse.jdt.internal.compiler.ast.SwitchStatement; -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.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.AnnotationContext; -import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants; -import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; -import org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel; -import org.eclipse.jdt.internal.compiler.codegen.Opcodes; -import org.eclipse.jdt.internal.compiler.codegen.StackMapFrame; -import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream; -import org.eclipse.jdt.internal.compiler.codegen.StackMapFrameCodeStream.ExceptionMarker; -import org.eclipse.jdt.internal.compiler.codegen.TypeAnnotationCodeStream; -import org.eclipse.jdt.internal.compiler.codegen.VerificationTypeInfo; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.StringConstant; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolymorphicMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -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.SyntheticArgumentBinding; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; -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.AbortMethod; -import org.eclipse.jdt.internal.compiler.problem.AbortType; -import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; -import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement; -import org.eclipse.jdt.internal.compiler.util.Messages; -import org.eclipse.jdt.internal.compiler.util.Util; - -/** - * Represents a class file wrapper on bytes, it is aware of its actual - * type name. - * - * Public APIs are listed below: - * - * byte[] getBytes(); - * Answer the actual bytes of the class file - * - * char[][] getCompoundName(); - * Answer the compound name of the class file. - * For example, {{java}, {util}, {Hashtable}}. - * - * byte[] getReducedBytes(); - * Answer a smaller byte format, which is only contains some structural - * information. Those bytes are decodable with a regular class file reader, - * such as DietClassFileReader - */ -public class ClassFile implements TypeConstants, TypeIds { - - private byte[] bytes; - public CodeStream codeStream; - public ConstantPool constantPool; - - public int constantPoolOffset; - - // the header contains all the bytes till the end of the constant pool - public byte[] contents; - - public int contentsOffset; - - protected boolean creatingProblemType; - - public ClassFile enclosingClassFile; - public byte[] header; - // that collection contains all the remaining bytes of the .class file - public int headerOffset; - public Map innerClassesBindings; - public Set nestMembers; - public List bootstrapMethods = null; - public int methodCount; - public int methodCountOffset; - // pool managment - boolean isShared = false; - // used to generate private access methods - // debug and stack map attributes - public int produceAttributes; - public SourceTypeBinding referenceBinding; - public boolean isNestedType; - public long targetJDK; - - public List missingTypes = null; - - public Set visitedTypes; - - public static final int INITIAL_CONTENTS_SIZE = 400; - public static final int INITIAL_HEADER_SIZE = 1500; - public static final int INNER_CLASSES_SIZE = 5; - public static final int NESTED_MEMBER_SIZE = 5; - - // TODO: Move these to an enum? - public static final String ALTMETAFACTORY_STRING = new String(ConstantPool.ALTMETAFACTORY); - public static final String METAFACTORY_STRING = new String(ConstantPool.METAFACTORY); - public static final String BOOTSTRAP_STRING = new String(ConstantPool.BOOTSTRAP); - public static final String TYPESWITCH_STRING = new String(ConstantPool.TYPESWITCH); - public static final String ENUMSWITCH_STRING = new String(ConstantPool.ENUMSWITCH); - public static final String CONCAT_CONSTANTS = new String(ConstantPool.ConcatWithConstants); - public static final String INVOKE_STRING = new String(ConstantPool.INVOKE_METHOD_METHOD_NAME); - public static final String ENUMDESC_OF = "EnumDesc.of"; //$NON-NLS-1$ - public static final String CLASSDESC = "ClassDesc"; //$NON-NLS-1$ - public static final String CLASSDESC_OF = "ClassDesc.of"; //$NON-NLS-1$ - public static final String PROCESS_STRING = "process"; //$NON-NLS-1$ - public static final String NEW_STRING_TEMPLATE = "newStringTemplate"; //$NON-NLS-1$ - public static final String[] BOOTSTRAP_METHODS = { ALTMETAFACTORY_STRING, METAFACTORY_STRING, BOOTSTRAP_STRING, - TYPESWITCH_STRING, ENUMSWITCH_STRING, CONCAT_CONSTANTS, INVOKE_STRING, ENUMDESC_OF, CLASSDESC, CLASSDESC_OF, PROCESS_STRING, NEW_STRING_TEMPLATE}; - /** - * INTERNAL USE-ONLY - * Request the creation of a ClassFile compatible representation of a problematic type - * - * @param typeDeclaration org.eclipse.jdt.internal.compiler.ast.TypeDeclaration - * @param unitResult org.eclipse.jdt.internal.compiler.CompilationUnitResult - */ - public static void createProblemType(TypeDeclaration typeDeclaration, CompilationResult unitResult) { - createProblemType(typeDeclaration, null, unitResult); - } - - private static void createProblemType(TypeDeclaration typeDeclaration, ClassFile parentClassFile, CompilationResult unitResult) { - SourceTypeBinding typeBinding = typeDeclaration.binding; - ClassFile classFile = ClassFile.getNewInstance(typeBinding); - classFile.initialize(typeBinding, parentClassFile, true); - - if (typeBinding.hasMemberTypes()) { - // see bug 180109 - ReferenceBinding[] members = typeBinding.memberTypes; - for (int i = 0, l = members.length; i < l; i++) - classFile.recordInnerClasses(members[i]); - } - // TODO (olivier) handle cases where a field cannot be generated (name too long) - // TODO (olivier) handle too many methods - // inner attributes - if (typeBinding.isNestedType()) { - classFile.recordInnerClasses(typeBinding); - } - TypeVariableBinding[] typeVariables = typeBinding.typeVariables(); - for (int i = 0, max = typeVariables.length; i < max; i++) { - TypeVariableBinding typeVariableBinding = typeVariables[i]; - if ((typeVariableBinding.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { - Util.recordNestedType(classFile, typeVariableBinding); - } - } - // add its fields - FieldBinding[] fields = typeBinding.fields(); - if ((fields != null) && (fields != Binding.NO_FIELDS)) { - classFile.addFieldInfos(); - } else { - // we have to set the number of fields to be equals to 0 - if (classFile.contentsOffset + 2 >= classFile.contents.length) { - classFile.resizeContents(2); - } - classFile.contents[classFile.contentsOffset++] = 0; - classFile.contents[classFile.contentsOffset++] = 0; - } - // leave some space for the methodCount - classFile.setForMethodInfos(); - // add its user defined methods - int problemsLength; - CategorizedProblem[] problems = unitResult.getErrors(); - if (problems == null) { - problems = new CategorizedProblem[0]; - } - CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; - System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); - - AbstractMethodDeclaration[] methodDecls = typeDeclaration.methods; - boolean abstractMethodsOnly = false; - if (methodDecls != null) { - if (typeBinding.isInterface()) { - if (typeBinding.scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) - abstractMethodsOnly = true; - // We generate a clinit which contains all the problems, since we may not be able to generate problem methods (< 1.8) and problem constructors (all levels). - classFile.addProblemClinit(problemsCopy); - } - for (int i = 0, length = methodDecls.length; i < length; i++) { - AbstractMethodDeclaration methodDecl = methodDecls[i]; - MethodBinding method = methodDecl.binding; - if (method == null) continue; - if (abstractMethodsOnly) { - method.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccAbstract; - } - if (method.isConstructor()) { - if (typeBinding.isInterface()) continue; - classFile.addProblemConstructor(methodDecl, method, problemsCopy); - } else if (method.isAbstract()) { - classFile.addAbstractMethod(methodDecl, method); - } else { - classFile.addProblemMethod(methodDecl, method, problemsCopy); - } - } - // add abstract methods - classFile.addDefaultAbstractMethods(); - } - - // propagate generation of (problem) member types - if (typeDeclaration.memberTypes != null) { - for (int i = 0, max = typeDeclaration.memberTypes.length; i < max; i++) { - TypeDeclaration memberType = typeDeclaration.memberTypes[i]; - if (memberType.binding != null) { - ClassFile.createProblemType(memberType, classFile, unitResult); - } - } - } - classFile.addAttributes(); - unitResult.record(typeBinding.constantPoolName(), classFile); - } - public static ClassFile getNewInstance(SourceTypeBinding typeBinding) { - LookupEnvironment env = typeBinding.scope.environment(); - return env.classFilePool.acquire(typeBinding); - } - /** - * INTERNAL USE-ONLY - * This methods creates a new instance of the receiver. - */ - protected ClassFile() { - // default constructor for subclasses - } - - public ClassFile(SourceTypeBinding typeBinding) { - // default constructor for subclasses - this.constantPool = new ConstantPool(this); - final CompilerOptions options = typeBinding.scope.compilerOptions(); - this.targetJDK = options.targetJDK; - this.produceAttributes = options.produceDebugAttributes; - this.referenceBinding = typeBinding; - this.isNestedType = typeBinding.isNestedType(); - if (this.targetJDK >= ClassFileConstants.JDK1_6) { - this.produceAttributes |= ClassFileConstants.ATTR_STACK_MAP_TABLE; - if (this.targetJDK >= ClassFileConstants.JDK1_8) { - this.produceAttributes |= ClassFileConstants.ATTR_TYPE_ANNOTATION; - this.codeStream = new TypeAnnotationCodeStream(this); - if (options.produceMethodParameters) { - this.produceAttributes |= ClassFileConstants.ATTR_METHOD_PARAMETERS; - } - } else { - this.codeStream = new StackMapFrameCodeStream(this); - } - } else if (this.targetJDK == ClassFileConstants.CLDC_1_1) { - this.targetJDK = ClassFileConstants.JDK1_1; // put back 45.3 - this.produceAttributes |= ClassFileConstants.ATTR_STACK_MAP; - this.codeStream = new StackMapFrameCodeStream(this); - } else { - this.codeStream = new CodeStream(this); - } - initByteArrays(this.referenceBinding.methods().length + this.referenceBinding.fields().length); - } - - public ClassFile(ModuleBinding moduleBinding, CompilerOptions options) { - this.constantPool = new ConstantPool(this); - this.targetJDK = options.targetJDK; - this.produceAttributes = ClassFileConstants.ATTR_SOURCE; - this.isNestedType = false; - this.codeStream = new StackMapFrameCodeStream(this); - initByteArrays(0); - } - - /** - * INTERNAL USE-ONLY - * Generate the byte for a problem method info that correspond to a bogus method. - * - * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding - */ - public void addAbstractMethod( - AbstractMethodDeclaration method, - MethodBinding methodBinding) { - - this.generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - int attributeNumber = this.generateMethodInfoAttributes(methodBinding); - completeMethodInfo(methodBinding, methodAttributeOffset, attributeNumber); - } - - /** - * INTERNAL USE-ONLY - * This methods generate all the attributes for the receiver. - * For a class they could be: - * - source file attribute - * - inner classes attribute - * - deprecated attribute - */ - public void addAttributes() { - // update the method count - this.contents[this.methodCountOffset++] = (byte) (this.methodCount >> 8); - this.contents[this.methodCountOffset] = (byte) this.methodCount; - - int attributesNumber = 0; - // leave two bytes for the number of attributes and store the current offset - int attributeOffset = this.contentsOffset; - this.contentsOffset += 2; - - // source attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_SOURCE) != 0) { - String fullFileName = - new String(this.referenceBinding.scope.referenceCompilationUnit().getFileName()); - fullFileName = fullFileName.replace('\\', '/'); - int lastIndex = fullFileName.lastIndexOf('/'); - if (lastIndex != -1) { - fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length()); - } - attributesNumber += generateSourceAttribute(fullFileName); - } - // Deprecated attribute - if (this.referenceBinding.isDeprecated()) { - // check that there is enough space to write all the bytes for the field info corresponding - // to the @fieldBinding - attributesNumber += generateDeprecatedAttribute(); - } - // add signature attribute - char[] genericSignature = this.referenceBinding.genericSignature(); - if (genericSignature != null) { - attributesNumber += generateSignatureAttribute(genericSignature); - } - if (this.targetJDK >= ClassFileConstants.JDK1_5 - && this.referenceBinding.isNestedType() - && !this.referenceBinding.isMemberType()) { - // add enclosing method attribute (1.5 mode only) - attributesNumber += generateEnclosingMethodAttribute(); - } - if (this.targetJDK >= ClassFileConstants.JDK1_4) { - TypeDeclaration typeDeclaration = this.referenceBinding.scope.referenceContext; - if (typeDeclaration != null) { - final Annotation[] annotations = typeDeclaration.annotations; - if (annotations != null) { - long targetMask; - if (typeDeclaration.isPackageInfo()) - targetMask = TagBits.AnnotationForPackage; - else if (this.referenceBinding.isAnnotationType()) - targetMask = TagBits.AnnotationForType | TagBits.AnnotationForAnnotationType; - else - targetMask = TagBits.AnnotationForType | TagBits.AnnotationForTypeUse; // 9.7.4 ... applicable to type declarations or in type contexts - attributesNumber += generateRuntimeAnnotations(annotations, targetMask); - } - } - } - - if (this.referenceBinding.isHierarchyInconsistent()) { - ReferenceBinding superclass = this.referenceBinding.superclass; - if (superclass != null) { - this.missingTypes = superclass.collectMissingTypes(this.missingTypes); - } - ReferenceBinding[] superInterfaces = this.referenceBinding.superInterfaces(); - for (int i = 0, max = superInterfaces.length; i < max; i++) { - this.missingTypes = superInterfaces[i].collectMissingTypes(this.missingTypes); - } - attributesNumber += generateHierarchyInconsistentAttribute(); - } - // Functional expression, lambda bootstrap methods and record bootstrap methods - if (this.bootstrapMethods != null && !this.bootstrapMethods.isEmpty()) { - attributesNumber += generateBootstrapMethods(this.bootstrapMethods); - } - if (this.targetJDK >= ClassFileConstants.JDK17) { - // add record attributes - attributesNumber += generatePermittedTypeAttributes(); - } - // Inner class attribute - int numberOfInnerClasses = this.innerClassesBindings == null ? 0 : this.innerClassesBindings.size(); - if (numberOfInnerClasses != 0) { - ReferenceBinding[] innerClasses = new ReferenceBinding[numberOfInnerClasses]; - this.innerClassesBindings.keySet().toArray(innerClasses); - Arrays.sort(innerClasses, new Comparator() { - @Override - public int compare(ReferenceBinding o1, ReferenceBinding o2) { - Boolean onBottom1 = ClassFile.this.innerClassesBindings.get(o1); - Boolean onBottom2 = ClassFile.this.innerClassesBindings.get(o2); - if (onBottom1) { - if (!onBottom2) { - return 1; - } - } else { - if (onBottom2) { - return -1; - } - } - return CharOperation.compareTo(o1.constantPoolName(), o2.constantPoolName()); - } - }); - attributesNumber += generateInnerClassAttribute(numberOfInnerClasses, innerClasses); - } - if (this.missingTypes != null) { - generateMissingTypesAttribute(); - attributesNumber++; - } - - attributesNumber += generateTypeAnnotationAttributeForTypeDeclaration(); - - if (this.targetJDK >= ClassFileConstants.JDK11) { - // add nestMember and nestHost attributes - attributesNumber += generateNestAttributes(); - } - if (this.targetJDK >= ClassFileConstants.JDK14) { - // add record attributes - attributesNumber += generateRecordAttributes(); - } - // update the number of attributes - if (attributeOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[attributeOffset++] = (byte) (attributesNumber >> 8); - this.contents[attributeOffset] = (byte) attributesNumber; - - // resynchronize all offsets of the classfile - this.header = this.constantPool.poolContent; - this.headerOffset = this.constantPool.currentOffset; - int constantPoolCount = this.constantPool.currentIndex; - this.header[this.constantPoolOffset++] = (byte) (constantPoolCount >> 8); - this.header[this.constantPoolOffset] = (byte) constantPoolCount; - } - - /** - * INTERNAL USE-ONLY - * This methods generate all the module attributes for the receiver. - */ - public void addModuleAttributes(ModuleBinding module, Annotation[] annotations, CompilationUnitDeclaration cud) { - int attributesNumber = 0; - // leave two bytes for the number of attributes and store the current offset - int attributeOffset = this.contentsOffset; - this.contentsOffset += 2; - - // source attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_SOURCE) != 0) { - String fullFileName = - new String(cud.getFileName()); - fullFileName = fullFileName.replace('\\', '/'); - int lastIndex = fullFileName.lastIndexOf('/'); - if (lastIndex != -1) { - fullFileName = fullFileName.substring(lastIndex + 1, fullFileName.length()); - } - attributesNumber += generateSourceAttribute(fullFileName); - } - attributesNumber += generateModuleAttribute(cud.moduleDeclaration); - if (annotations != null) { - long targetMask = TagBits.AnnotationForModule; - attributesNumber += generateRuntimeAnnotations(annotations, targetMask); - } - char[] mainClass = cud.moduleDeclaration.binding.mainClassName; - if (mainClass != null) { - attributesNumber += generateModuleMainClassAttribute(CharOperation.replaceOnCopy(mainClass, '.', '/')); - } - char[][] packageNames = cud.moduleDeclaration.binding.getPackageNamesForClassFile(); - if (packageNames != null) { - attributesNumber += generateModulePackagesAttribute(packageNames); - } - - // update the number of attributes - if (attributeOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[attributeOffset++] = (byte) (attributesNumber >> 8); - this.contents[attributeOffset] = (byte) attributesNumber; - - // resynchronize all offsets of the classfile - this.header = this.constantPool.poolContent; - this.headerOffset = this.constantPool.currentOffset; - int constantPoolCount = this.constantPool.currentIndex; - this.header[this.constantPoolOffset++] = (byte) (constantPoolCount >> 8); - this.header[this.constantPoolOffset] = (byte) constantPoolCount; - } - - /** - * INTERNAL USE-ONLY - * This methods generate all the default abstract method infos that correpond to - * the abstract methods inherited from superinterfaces. - */ - public void addDefaultAbstractMethods() { // default abstract methods - MethodBinding[] defaultAbstractMethods = - this.referenceBinding.getDefaultAbstractMethods(); - for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) { - MethodBinding methodBinding = defaultAbstractMethods[i]; - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - int attributeNumber = generateMethodInfoAttributes(methodBinding); - completeMethodInfo(methodBinding, methodAttributeOffset, attributeNumber); - } - } - - private int addFieldAttributes(FieldBinding fieldBinding, int fieldAttributeOffset) { - int attributesNumber = 0; - // 4.7.2 only static constant fields get a ConstantAttribute - // Generate the constantValueAttribute - Constant fieldConstant = fieldBinding.constant(); - if (fieldConstant != Constant.NotAConstant){ - attributesNumber += generateConstantValueAttribute(fieldConstant, fieldBinding, fieldAttributeOffset); - } - if (this.targetJDK < ClassFileConstants.JDK1_5 && fieldBinding.isSynthetic()) { - attributesNumber += generateSyntheticAttribute(); - } - if (fieldBinding.isDeprecated()) { - attributesNumber += generateDeprecatedAttribute(); - } - // add signature attribute - char[] genericSignature = fieldBinding.genericSignature(); - if (genericSignature != null) { - attributesNumber += generateSignatureAttribute(genericSignature); - } - if (this.targetJDK >= ClassFileConstants.JDK1_4) { - FieldDeclaration fieldDeclaration = fieldBinding.sourceField(); - if (fieldDeclaration != null) { - try { - if (fieldDeclaration.isARecordComponent) { - long rcMask = TagBits.AnnotationForField | TagBits.AnnotationForTypeUse; - RecordComponent comp = getRecordComponent(fieldBinding.declaringClass, fieldBinding.name); - if (comp != null) - fieldDeclaration.annotations = ASTNode.getRelevantAnnotations(comp.annotations, rcMask, null); - } - Annotation[] annotations = fieldDeclaration.annotations; - if (annotations != null) { - attributesNumber += generateRuntimeAnnotations(annotations, TagBits.AnnotationForField); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { - List allTypeAnnotationContexts = new ArrayList<>(); - if (annotations != null && (fieldDeclaration.bits & ASTNode.HasTypeAnnotations) != 0) { - fieldDeclaration.getAllAnnotationContexts(AnnotationTargetTypeConstants.FIELD, allTypeAnnotationContexts); - } - TypeReference fieldType = fieldDeclaration.type; - if (fieldType != null && ((fieldType.bits & ASTNode.HasTypeAnnotations) != 0)) { - fieldType.getAllAnnotationContexts(AnnotationTargetTypeConstants.FIELD, allTypeAnnotationContexts); - } - int size = allTypeAnnotationContexts.size(); - attributesNumber = completeRuntimeTypeAnnotations(attributesNumber, - null, - node -> size > 0, - () -> allTypeAnnotationContexts); - } - } finally { - if (fieldDeclaration.isARecordComponent) { - fieldDeclaration.annotations = null; - } - } - } - } - if ((fieldBinding.tagBits & TagBits.HasMissingType) != 0) { - this.missingTypes = fieldBinding.type.collectMissingTypes(this.missingTypes); - } - return attributesNumber; - } - private RecordComponent getRecordComponent(ReferenceBinding declaringClass, char[] name) { - if (declaringClass instanceof SourceTypeBinding) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) declaringClass; - RecordComponentBinding rcb = sourceTypeBinding.getRecordComponent(name); - if (rcb != null) { - RecordComponent recordComponent = rcb.sourceRecordComponent(); - return recordComponent; - } - } - return null; - } - private int addComponentAttributes(RecordComponentBinding recordComponentBinding, int componetAttributeOffset) { - // See JVMS 14 Table 4.7-C - Record Preview for allowed attributes - int attributesNumber = 0; - // add signature attribute - char[] genericSignature = recordComponentBinding.genericSignature(); - if (genericSignature != null) { - attributesNumber += generateSignatureAttribute(genericSignature); - } - RecordComponent recordComponent = recordComponentBinding.sourceRecordComponent(); - if (recordComponent != null) { - Annotation[] annotations = recordComponent.annotations; - if (annotations != null) { - attributesNumber += generateRuntimeAnnotations(annotations, TagBits.AnnotationForRecordComponent); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { - List allTypeAnnotationContexts = new ArrayList<>(); - if (annotations != null && (recordComponent.bits & ASTNode.HasTypeAnnotations) != 0) { - recordComponent.getAllAnnotationContexts(AnnotationTargetTypeConstants.RECORD_COMPONENT, allTypeAnnotationContexts); - } - TypeReference recordComponentType = recordComponent.type; - if (recordComponentType != null && ((recordComponentType.bits & ASTNode.HasTypeAnnotations) != 0)) { - recordComponentType.getAllAnnotationContexts(AnnotationTargetTypeConstants.RECORD_COMPONENT, allTypeAnnotationContexts); - } - int size = allTypeAnnotationContexts.size(); - attributesNumber = completeRuntimeTypeAnnotations(attributesNumber, - null, - node -> size > 0, - () -> allTypeAnnotationContexts); - - } - } - if ((recordComponentBinding.tagBits & TagBits.HasMissingType) != 0) { - this.missingTypes = recordComponentBinding.type.collectMissingTypes(this.missingTypes); - } - return attributesNumber; - } - - private void addComponentInfo(RecordComponentBinding recordComponentBinding) { - // check that there is enough space to write all the bytes for the field info corresponding - // to the @fieldBinding sans accessflags for component - /* record_component_info { - * u2 name_index; - * u2 descriptor_index; - * u2 attributes_count; - * attribute_info attributes[attributes_count]; - } */ - if (this.contentsOffset + 6 >= this.contents.length) { - resizeContents(6); - } - // Now we can generate all entries into the byte array - int nameIndex = this.constantPool.literalIndex(recordComponentBinding.name); - this.contents[this.contentsOffset++] = (byte) (nameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) nameIndex; - // Then the descriptorIndex - int descriptorIndex = this.constantPool.literalIndex(recordComponentBinding.type); - this.contents[this.contentsOffset++] = (byte) (descriptorIndex >> 8); - this.contents[this.contentsOffset++] = (byte) descriptorIndex; - int componentAttributeOffset = this.contentsOffset; - int attributeNumber = 0; - // leave some space for the number of attributes - this.contentsOffset += 2; - attributeNumber += addComponentAttributes(recordComponentBinding, componentAttributeOffset); - if (this.contentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[componentAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[componentAttributeOffset] = (byte) attributeNumber; - } - - /** - * INTERNAL USE-ONLY - * This methods generates the bytes for the given field binding - * @param fieldBinding the given field binding - */ - private void addFieldInfo(FieldBinding fieldBinding) { - // check that there is enough space to write all the bytes for the field info corresponding - // to the @fieldBinding - if (this.contentsOffset + 8 >= this.contents.length) { - resizeContents(8); - } - // Now we can generate all entries into the byte array - // First the accessFlags - int accessFlags = fieldBinding.getAccessFlags(); - if (this.targetJDK < ClassFileConstants.JDK1_5) { - // pre 1.5, synthetic was an attribute, not a modifier - accessFlags &= ~ClassFileConstants.AccSynthetic; - } - this.contents[this.contentsOffset++] = (byte) (accessFlags >> 8); - this.contents[this.contentsOffset++] = (byte) accessFlags; - // Then the nameIndex - int nameIndex = this.constantPool.literalIndex(fieldBinding.name); - this.contents[this.contentsOffset++] = (byte) (nameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) nameIndex; - // Then the descriptorIndex - int descriptorIndex = this.constantPool.literalIndex(fieldBinding.type); - this.contents[this.contentsOffset++] = (byte) (descriptorIndex >> 8); - this.contents[this.contentsOffset++] = (byte) descriptorIndex; - int fieldAttributeOffset = this.contentsOffset; - int attributeNumber = 0; - // leave some space for the number of attributes - this.contentsOffset += 2; - attributeNumber += addFieldAttributes(fieldBinding, fieldAttributeOffset); - if (this.contentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[fieldAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[fieldAttributeOffset] = (byte) attributeNumber; - } - - /** - * INTERNAL USE-ONLY - * This methods generate all the fields infos for the receiver. - * This includes: - * - a field info for each defined field of that class - * - a field info for each synthetic field (e.g. this$0) - */ - /** - * INTERNAL USE-ONLY - * This methods generate all the fields infos for the receiver. - * This includes: - * - a field info for each defined field of that class - * - a field info for each synthetic field (e.g. this$0) - */ - public void addFieldInfos() { - SourceTypeBinding currentBinding = this.referenceBinding; - FieldBinding[] syntheticFields = currentBinding.syntheticFields(); - int fieldCount = currentBinding.fieldCount() + (syntheticFields == null ? 0 : syntheticFields.length); - - // write the number of fields - if (fieldCount > 0xFFFF) { - this.referenceBinding.scope.problemReporter().tooManyFields(this.referenceBinding.scope.referenceType()); - } - if (this.contentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[this.contentsOffset++] = (byte) (fieldCount >> 8); - this.contents[this.contentsOffset++] = (byte) fieldCount; - - FieldDeclaration[] fieldDecls = currentBinding.scope.referenceContext.fields; - for (int i = 0, max = fieldDecls == null ? 0 : fieldDecls.length; i < max; i++) { - FieldDeclaration fieldDecl = fieldDecls[i]; - if (fieldDecl.binding != null) { - addFieldInfo(fieldDecl.binding); - } - } - - if (syntheticFields != null) { - for (int i = 0, max = syntheticFields.length; i < max; i++) { - addFieldInfo(syntheticFields[i]); - } - } - } - - private void addMissingAbstractProblemMethod(MethodDeclaration methodDeclaration, MethodBinding methodBinding, CategorizedProblem problem, CompilationResult compilationResult) { - // always clear the strictfp/native/abstract bit for a problem method - generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(ClassFileConstants.AccStrictfp | ClassFileConstants.AccNative | ClassFileConstants.AccAbstract)); - int methodAttributeOffset = this.contentsOffset; - int attributeNumber = generateMethodInfoAttributes(methodBinding); - - // Code attribute - attributeNumber++; - - int codeAttributeOffset = this.contentsOffset; - generateCodeAttributeHeader(); - StringBuilder buffer = new StringBuilder(25); - buffer.append("\t" + problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ - buffer.insert(0, Messages.compilation_unresolvedProblem); - String problemString = buffer.toString(); - - this.codeStream.init(this); - this.codeStream.preserveUnusedLocals = true; - this.codeStream.initializeMaxLocals(methodBinding); - - // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") - this.codeStream.generateCodeAttributeForProblemMethod(problemString); - - completeCodeAttributeForMissingAbstractProblemMethod( - methodBinding, - codeAttributeOffset, - compilationResult.getLineSeparatorPositions(), - problem.getSourceLineNumber()); - - completeMethodInfo(methodBinding, methodAttributeOffset, attributeNumber); - } - - /** - * INTERNAL USE-ONLY - * Generate the byte for a problem clinit method info that correspond to a boggus method. - * - * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] - */ - public void addProblemClinit(CategorizedProblem[] problems) { - generateMethodInfoHeaderForClinit(); - // leave two spaces for the number of attributes - this.contentsOffset -= 2; - int attributeOffset = this.contentsOffset; - this.contentsOffset += 2; - int attributeNumber = 0; - - int codeAttributeOffset = this.contentsOffset; - generateCodeAttributeHeader(); - this.codeStream.resetForProblemClinit(this); - String problemString = "" ; //$NON-NLS-1$ - int problemLine = 0; - if (problems != null) { - int max = problems.length; - StringBuilder buffer = new StringBuilder(25); - int count = 0; - for (int i = 0; i < max; i++) { - CategorizedProblem problem = problems[i]; - if ((problem != null) && (problem.isError())) { - buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ - count++; - if (problemLine == 0) { - problemLine = problem.getSourceLineNumber(); - } - problems[i] = null; - } - } // insert the top line afterwards, once knowing how many problems we have to consider - if (count > 1) { - buffer.insert(0, Messages.compilation_unresolvedProblems); - } else { - buffer.insert(0, Messages.compilation_unresolvedProblem); - } - problemString = buffer.toString(); - } - - // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") - this.codeStream.generateCodeAttributeForProblemMethod(problemString); - attributeNumber++; // code attribute - completeCodeAttributeForClinit( - codeAttributeOffset, - problemLine, - null); - if (this.contentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[attributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[attributeOffset] = (byte) attributeNumber; - } - - /** - * INTERNAL USE-ONLY - * Generate the byte for a problem method info that correspond to a boggus constructor. - * - * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding - * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] - */ - public void addProblemConstructor( - AbstractMethodDeclaration method, - MethodBinding methodBinding, - CategorizedProblem[] problems) { - - if (methodBinding.declaringClass.isInterface()) { - method.abort(ProblemSeverities.AbortType, null); - } - - // always clear the strictfp/native/abstract bit for a problem method - generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(ClassFileConstants.AccStrictfp | ClassFileConstants.AccNative | ClassFileConstants.AccAbstract)); - int methodAttributeOffset = this.contentsOffset; - int attributesNumber = generateMethodInfoAttributes(methodBinding); - - // Code attribute - attributesNumber++; - int codeAttributeOffset = this.contentsOffset; - generateCodeAttributeHeader(); - this.codeStream.reset(method, this); - String problemString = "" ; //$NON-NLS-1$ - int problemLine = 0; - if (problems != null) { - int max = problems.length; - StringBuilder buffer = new StringBuilder(25); - int count = 0; - for (int i = 0; i < max; i++) { - CategorizedProblem problem = problems[i]; - if ((problem != null) && (problem.isError())) { - buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ - count++; - if (problemLine == 0) { - problemLine = problem.getSourceLineNumber(); - } - } - } // insert the top line afterwards, once knowing how many problems we have to consider - if (count > 1) { - buffer.insert(0, Messages.compilation_unresolvedProblems); - } else { - buffer.insert(0, Messages.compilation_unresolvedProblem); - } - problemString = buffer.toString(); - } - - // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") - this.codeStream.generateCodeAttributeForProblemMethod(problemString); - completeCodeAttributeForProblemMethod( - method, - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions(), - problemLine); - completeMethodInfo(methodBinding, methodAttributeOffset, attributesNumber); - } - /** - * INTERNAL USE-ONLY - * Generate the byte for a problem method info that correspond to a boggus constructor. - * Reset the position inside the contents byte array to the savedOffset. - * - * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding - * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] - * @param savedOffset int - */ - public void addProblemConstructor( - AbstractMethodDeclaration method, - MethodBinding methodBinding, - CategorizedProblem[] problems, - int savedOffset) { - // we need to move back the contentsOffset to the value at the beginning of the method - this.contentsOffset = savedOffset; - this.methodCount--; // we need to remove the method that causes the problem - addProblemConstructor(method, methodBinding, problems); - } - /** - * INTERNAL USE-ONLY - * Generate the byte for a problem method info that correspond to a boggus method. - * - * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding - * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] - */ - public void addProblemMethod( - AbstractMethodDeclaration method, - MethodBinding methodBinding, - CategorizedProblem[] problems) { - if (methodBinding.isAbstract() && methodBinding.declaringClass.isInterface()) { - method.abort(ProblemSeverities.AbortType, null); - } - // always clear the strictfp/native/abstract bit for a problem method - generateMethodInfoHeader(methodBinding, methodBinding.modifiers & ~(ClassFileConstants.AccStrictfp | ClassFileConstants.AccNative | ClassFileConstants.AccAbstract)); - int methodAttributeOffset = this.contentsOffset; - int attributesNumber = generateMethodInfoAttributes(methodBinding); - - // Code attribute - attributesNumber++; - - int codeAttributeOffset = this.contentsOffset; - generateCodeAttributeHeader(); - this.codeStream.reset(method, this); - String problemString = "" ; //$NON-NLS-1$ - int problemLine = 0; - if (problems != null) { - int max = problems.length; - StringBuilder buffer = new StringBuilder(25); - int count = 0; - for (int i = 0; i < max; i++) { - CategorizedProblem problem = problems[i]; - if ((problem != null) - && (problem.isError()) - && (problem.getSourceStart() >= method.declarationSourceStart) - && (problem.getSourceEnd() <= method.declarationSourceEnd)) { - buffer.append("\t" +problem.getMessage() + "\n" ); //$NON-NLS-1$ //$NON-NLS-2$ - count++; - if (problemLine == 0) { - problemLine = problem.getSourceLineNumber(); - } - problems[i] = null; - } - } // insert the top line afterwards, once knowing how many problems we have to consider - if (count > 1) { - buffer.insert(0, Messages.compilation_unresolvedProblems); - } else { - buffer.insert(0, Messages.compilation_unresolvedProblem); - } - problemString = buffer.toString(); - } - - // return codeStream.generateCodeAttributeForProblemMethod(comp.options.runtimeExceptionNameForCompileError, "") - this.codeStream.generateCodeAttributeForProblemMethod(problemString); - completeCodeAttributeForProblemMethod( - method, - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions(), - problemLine); - completeMethodInfo(methodBinding, methodAttributeOffset, attributesNumber); - } - - /** - * INTERNAL USE-ONLY - * Generate the byte for a problem method info that correspond to a boggus method. - * Reset the position inside the contents byte array to the savedOffset. - * - * @param method org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.MethodBinding - * @param problems org.eclipse.jdt.internal.compiler.problem.Problem[] - * @param savedOffset int - */ - public void addProblemMethod( - AbstractMethodDeclaration method, - MethodBinding methodBinding, - CategorizedProblem[] problems, - int savedOffset) { - // we need to move back the contentsOffset to the value at the beginning of the method - this.contentsOffset = savedOffset; - this.methodCount--; // we need to remove the method that causes the problem - addProblemMethod(method, methodBinding, problems); - } - - /** - * INTERNAL USE-ONLY - * Generate the byte for all the special method infos. - * They are: - * - synthetic access methods - * - default abstract methods - * - lambda methods. - */ - public void addSpecialMethods(TypeDeclaration typeDecl) { - - // add all methods (default abstract methods and synthetic) - - // default abstract methods - generateMissingAbstractMethods(this.referenceBinding.scope.referenceType().missingAbstractMethods, this.referenceBinding.scope.referenceCompilationUnit().compilationResult); - - MethodBinding[] defaultAbstractMethods = this.referenceBinding.getDefaultAbstractMethods(); - for (int i = 0, max = defaultAbstractMethods.length; i < max; i++) { - MethodBinding methodBinding = defaultAbstractMethods[i]; - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - int attributeNumber = generateMethodInfoAttributes(methodBinding); - completeMethodInfo(methodBinding, methodAttributeOffset, attributeNumber); - } - - // add synthetic methods infos - int emittedSyntheticsCount = 0; - SyntheticMethodBinding deserializeLambdaMethod = null; - boolean continueScanningSynthetics = true; - while (continueScanningSynthetics) { - continueScanningSynthetics = false; - SyntheticMethodBinding[] syntheticMethods = this.referenceBinding.syntheticMethods(); - int currentSyntheticsCount = syntheticMethods == null ? 0: syntheticMethods.length; - if (emittedSyntheticsCount != currentSyntheticsCount) { - for (int i = emittedSyntheticsCount, max = currentSyntheticsCount; i < max; i++) { - SyntheticMethodBinding syntheticMethod = syntheticMethods[i]; - switch (syntheticMethod.purpose) { - case SyntheticMethodBinding.FieldReadAccess : - case SyntheticMethodBinding.SuperFieldReadAccess : - // generate a method info to emulate an reading access to - // a non-accessible field - addSyntheticFieldReadAccessMethod(syntheticMethod); - break; - case SyntheticMethodBinding.FieldWriteAccess : - case SyntheticMethodBinding.SuperFieldWriteAccess : - // generate a method info to emulate an writing access to - // a non-accessible field - addSyntheticFieldWriteAccessMethod(syntheticMethod); - break; - case SyntheticMethodBinding.MethodAccess : - case SyntheticMethodBinding.SuperMethodAccess : - case SyntheticMethodBinding.BridgeMethod : - // generate a method info to emulate an access to a non-accessible method / super-method or bridge method - addSyntheticMethodAccessMethod(syntheticMethod); - break; - case SyntheticMethodBinding.ConstructorAccess : - // generate a method info to emulate an access to a non-accessible constructor - addSyntheticConstructorAccessMethod(syntheticMethod); - break; - case SyntheticMethodBinding.EnumValues : - // generate a method info to define #values() - addSyntheticEnumValuesMethod(syntheticMethod); - break; - case SyntheticMethodBinding.EnumValueOf : - // generate a method info to define #valueOf(String) - addSyntheticEnumValueOfMethod(syntheticMethod); - break; - case SyntheticMethodBinding.SwitchTable : - // generate a method info to define the switch table synthetic method - addSyntheticSwitchTable(syntheticMethod); - break; - case SyntheticMethodBinding.TooManyEnumsConstants : - addSyntheticEnumInitializationMethod(syntheticMethod); - break; - case SyntheticMethodBinding.LambdaMethod: - syntheticMethod.lambda.generateCode(this.referenceBinding.scope, this); - continueScanningSynthetics = true; // lambda code generation could schedule additional nested lambdas for code generation. - break; - case SyntheticMethodBinding.ArrayConstructor: - addSyntheticArrayConstructor(syntheticMethod); - break; - case SyntheticMethodBinding.ArrayClone: - addSyntheticArrayClone(syntheticMethod); - break; - case SyntheticMethodBinding.FactoryMethod: - addSyntheticFactoryMethod(syntheticMethod); - break; - case SyntheticMethodBinding.DeserializeLambda: - deserializeLambdaMethod = syntheticMethod; // delay processing - break; - case SyntheticMethodBinding.SerializableMethodReference: - // Nothing to be done - break; - case SyntheticMethodBinding.RecordCanonicalConstructor: - addSyntheticRecordCanonicalConstructor(typeDecl, syntheticMethod); - break; - case SyntheticMethodBinding.RecordOverrideEquals: - case SyntheticMethodBinding.RecordOverrideHashCode: - case SyntheticMethodBinding.RecordOverrideToString: - addSyntheticRecordOverrideMethods(typeDecl, syntheticMethod, syntheticMethod.purpose); - break; - } - } - emittedSyntheticsCount = currentSyntheticsCount; - } - } - if (deserializeLambdaMethod != null) { - int problemResetPC = 0; - this.codeStream.wideMode = false; - boolean restart = false; - do { - try { - problemResetPC = this.contentsOffset; - addSyntheticDeserializeLambda(deserializeLambdaMethod,this.referenceBinding.syntheticMethods()); - restart = false; - } catch (AbortMethod e) { - // Restart code generation if possible ... - if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { - // a branch target required a goto_w, restart code generation in wide mode. - this.contentsOffset = problemResetPC; - this.methodCount--; - this.codeStream.resetInWideMode(); // request wide mode - restart = true; - } else { - throw new AbortType(this.referenceBinding.scope.referenceContext.compilationResult, e.problem); - } - } - } while (restart); - } - } - - private void addSyntheticRecordCanonicalConstructor(TypeDeclaration typeDecl, SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForRecordCanonicalConstructor(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - private void addSyntheticRecordOverrideMethods(TypeDeclaration typeDecl, SyntheticMethodBinding methodBinding, int purpose) { - if (this.bootstrapMethods == null) - this.bootstrapMethods = new ArrayList<>(3); - if (!this.bootstrapMethods.contains(typeDecl)) - this.bootstrapMethods.add(typeDecl); - int index = this.bootstrapMethods.indexOf(typeDecl); - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - switch (purpose) { - case SyntheticMethodBinding.RecordCanonicalConstructor: - this.codeStream.generateSyntheticBodyForRecordCanonicalConstructor(methodBinding); - break; - case SyntheticMethodBinding.RecordOverrideEquals: - this.codeStream.generateSyntheticBodyForRecordEquals(methodBinding, index); - break; - case SyntheticMethodBinding.RecordOverrideHashCode: - this.codeStream.generateSyntheticBodyForRecordHashCode(methodBinding, index); - break; - case SyntheticMethodBinding.RecordOverrideToString: - this.codeStream.generateSyntheticBodyForRecordToString(methodBinding, index); - break; - default: - break; - } - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - public void addSyntheticArrayConstructor(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForArrayConstructor(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - public void addSyntheticArrayClone(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForArrayClone(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - public void addSyntheticFactoryMethod(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForFactoryMethod(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - /** - * INTERNAL USE-ONLY - * Generate the bytes for a synthetic method that provides an access to a private constructor. - * - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding - */ - public void addSyntheticConstructorAccessMethod(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForConstructorAccess(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - /** - * INTERNAL USE-ONLY - * Generate the bytes for a synthetic method that implements Enum#valueOf(String) for a given enum type - * - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding - */ - public void addSyntheticEnumValueOfMethod(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForEnumValueOf(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - if ((this.produceAttributes & ClassFileConstants.ATTR_METHOD_PARAMETERS) != 0) { - attributeNumber += generateMethodParameters(methodBinding); - } - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - /** - * INTERNAL USE-ONLY - * Generate the bytes for a synthetic method that implements Enum#values() for a given enum type - * - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding - */ - public void addSyntheticEnumValuesMethod(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForEnumValues(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - public void addSyntheticEnumInitializationMethod(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForEnumInitializationMethod(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - /** - * INTERNAL USE-ONLY - * Generate the byte for a problem method info that correspond to a synthetic method that - * generate an read access to a private field. - * - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding - */ - public void addSyntheticFieldReadAccessMethod(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForFieldReadAccess(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - /** - * INTERNAL USE-ONLY - * Generate the byte for a problem method info that correspond to a synthetic method that - * generate an write access to a private field. - * - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding - */ - public void addSyntheticFieldWriteAccessMethod(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForFieldWriteAccess(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - /** - * INTERNAL USE-ONLY - * Generate the bytes for a synthetic method that provides access to a private method. - * - * @param methodBinding org.eclipse.jdt.internal.compiler.nameloopkup.SyntheticAccessMethodBinding - */ - public void addSyntheticMethodAccessMethod(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForMethodAccess(methodBinding); - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - public void addSyntheticSwitchTable(SyntheticMethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForSwitchTable(methodBinding); - int code_length = this.codeStream.position; - if (code_length > 65535) { - SwitchStatement switchStatement = methodBinding.switchStatement; - if (switchStatement != null) { - switchStatement.scope.problemReporter().bytecodeExceeds64KLimit(switchStatement); - } - } - completeCodeAttributeForSyntheticMethod( - true, - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions(), - ((SourceTypeBinding) methodBinding.declaringClass) - .scope); - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - /** - * INTERNAL USE-ONLY - * That method completes the creation of the code attribute by setting - * - the attribute_length - * - max_stack - * - max_locals - * - code_length - * - exception table - * - and debug attributes if necessary. - * - * @param codeAttributeOffset int - */ - public void completeCodeAttribute(int codeAttributeOffset, MethodScope scope) { - // reinitialize the localContents with the byte modified by the code stream - this.contents = this.codeStream.bCodeStream; - int localContentsOffset = this.codeStream.classFileOffset; - // codeAttributeOffset is the position inside localContents byte array before we started to write - // any information about the codeAttribute - // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset - // to get the right position, 6 for the max_stack etc... - int code_length = this.codeStream.position; - if (code_length > 65535) { - if (this.codeStream.methodDeclaration != null) { - this.codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit(this.codeStream.methodDeclaration); - } else { - this.codeStream.lambdaExpression.scope.problemReporter().bytecodeExceeds64KLimit(this.codeStream.lambdaExpression); - } - } - if (localContentsOffset + 20 >= this.contents.length) { - resizeContents(20); - } - int max_stack = this.codeStream.stackMax; - this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); - this.contents[codeAttributeOffset + 7] = (byte) max_stack; - int max_locals = this.codeStream.maxLocals; - this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); - this.contents[codeAttributeOffset + 9] = (byte) max_locals; - this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); - this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); - this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); - this.contents[codeAttributeOffset + 13] = (byte) code_length; - - boolean addStackMaps = (this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0; - // write the exception table - ExceptionLabel[] exceptionLabels = this.codeStream.exceptionLabels; - int exceptionHandlersCount = 0; // each label holds one handler per range (start/end contiguous) - for (int i = 0, length = this.codeStream.exceptionLabelsCounter; i < length; i++) { - exceptionHandlersCount += this.codeStream.exceptionLabels[i].getCount() / 2; - } - int exSize = exceptionHandlersCount * 8 + 2; - if (exSize + localContentsOffset >= this.contents.length) { - resizeContents(exSize); - } - // there is no exception table, so we need to offset by 2 the current offset and move - // on the attribute generation - this.contents[localContentsOffset++] = (byte) (exceptionHandlersCount >> 8); - this.contents[localContentsOffset++] = (byte) exceptionHandlersCount; - for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { - ExceptionLabel exceptionLabel = exceptionLabels[i]; - if (exceptionLabel != null) { - int iRange = 0, maxRange = exceptionLabel.getCount(); - if ((maxRange & 1) != 0) { - if (this.codeStream.methodDeclaration != null) { - this.codeStream.methodDeclaration.scope.problemReporter().abortDueToInternalError( - Messages.bind(Messages.abort_invalidExceptionAttribute, new String(this.codeStream.methodDeclaration.selector)), - this.codeStream.methodDeclaration); - } else { - this.codeStream.lambdaExpression.scope.problemReporter().abortDueToInternalError( - Messages.bind(Messages.abort_invalidExceptionAttribute, new String(this.codeStream.lambdaExpression.binding.selector)), - this.codeStream.lambdaExpression); - } - } - while (iRange < maxRange) { - int start = exceptionLabel.ranges[iRange++]; // even ranges are start positions - this.contents[localContentsOffset++] = (byte) (start >> 8); - this.contents[localContentsOffset++] = (byte) start; - int end = exceptionLabel.ranges[iRange++]; // odd ranges are end positions - this.contents[localContentsOffset++] = (byte) (end >> 8); - this.contents[localContentsOffset++] = (byte) end; - int handlerPC = exceptionLabel.position; - if (addStackMaps) { - StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; - stackMapFrameCodeStream.addFramePosition(handlerPC); -// stackMapFrameCodeStream.addExceptionMarker(handlerPC, exceptionLabel.exceptionType); - } - this.contents[localContentsOffset++] = (byte) (handlerPC >> 8); - this.contents[localContentsOffset++] = (byte) handlerPC; - if (exceptionLabel.exceptionType == null) { - // any exception handler - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - } else { - int nameIndex; - if (exceptionLabel.exceptionType == TypeBinding.NULL) { - /* represents ClassNotFoundException, see class literal access*/ - nameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName); - } else { - nameIndex = this.constantPool.literalIndexForType(exceptionLabel.exceptionType); - } - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) nameIndex; - } - } - } - } - // debug attributes - int codeAttributeAttributeOffset = localContentsOffset; - int attributesNumber = 0; - // leave two bytes for the attribute_length - localContentsOffset += 2; - if (localContentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - - this.contentsOffset = localContentsOffset; - - // first we handle the linenumber attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { - attributesNumber += generateLineNumberAttribute(); - } - // then we do the local variable attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { - final boolean methodDeclarationIsStatic = this.codeStream.methodDeclaration != null ? this.codeStream.methodDeclaration.isStatic() : this.codeStream.lambdaExpression.binding.isStatic(); - attributesNumber += generateLocalVariableTableAttribute(code_length, methodDeclarationIsStatic, false); - } - - if (addStackMaps) { - attributesNumber += generateStackMapTableAttribute( - this.codeStream.methodDeclaration != null ? this.codeStream.methodDeclaration.binding : this.codeStream.lambdaExpression.binding, - code_length, - codeAttributeOffset, - max_locals, - false, - scope); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { - attributesNumber += generateStackMapAttribute( - this.codeStream.methodDeclaration != null ? this.codeStream.methodDeclaration.binding : this.codeStream.lambdaExpression.binding, - code_length, - codeAttributeOffset, - max_locals, - false, - scope); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { - attributesNumber += generateTypeAnnotationsOnCodeAttribute(); - } - - this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); - this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; - - // update the attribute length - int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); - this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); - this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); - this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); - this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; - } - - public int generateTypeAnnotationsOnCodeAttribute() { - int attributesNumber = 0; - - List allTypeAnnotationContexts = ((TypeAnnotationCodeStream) this.codeStream).allTypeAnnotationContexts; - - for (int i = 0, max = this.codeStream.allLocalsCounter; i < max; i++) { - LocalVariableBinding localVariable = this.codeStream.locals[i]; - if (localVariable.isCatchParameter()) continue; - LocalDeclaration declaration = localVariable.declaration; - if (declaration == null - || (declaration.isArgument() && ((declaration.bits & ASTNode.IsUnionType) == 0)) - || (localVariable.initializationCount == 0) - || ((declaration.bits & ASTNode.HasTypeAnnotations) == 0)) { - continue; - } - int targetType = ((localVariable.tagBits & TagBits.IsResource) == 0) ? AnnotationTargetTypeConstants.LOCAL_VARIABLE : AnnotationTargetTypeConstants.RESOURCE_VARIABLE; - declaration.getAllAnnotationContexts(targetType, localVariable, allTypeAnnotationContexts); - } - - ExceptionLabel[] exceptionLabels = this.codeStream.exceptionLabels; - for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { - ExceptionLabel exceptionLabel = exceptionLabels[i]; - if (exceptionLabel.exceptionTypeReference != null && (exceptionLabel.exceptionTypeReference.bits & ASTNode.HasTypeAnnotations) != 0) { - exceptionLabel.exceptionTypeReference.getAllAnnotationContexts(AnnotationTargetTypeConstants.EXCEPTION_PARAMETER, i, allTypeAnnotationContexts, exceptionLabel.se7Annotations); - } - } - int size = allTypeAnnotationContexts.size(); - attributesNumber = completeRuntimeTypeAnnotations(attributesNumber, - null, - node -> size > 0, - () -> allTypeAnnotationContexts); - return attributesNumber; - } - - /** - * INTERNAL USE-ONLY - * That method completes the creation of the code attribute by setting - * - the attribute_length - * - max_stack - * - max_locals - * - code_length - * - exception table - * - and debug attributes if necessary. - * - * @param codeAttributeOffset int - */ - public void completeCodeAttributeForClinit(int codeAttributeOffset, Scope scope) { - // reinitialize the contents with the byte modified by the code stream - this.contents = this.codeStream.bCodeStream; - int localContentsOffset = this.codeStream.classFileOffset; - // codeAttributeOffset is the position inside contents byte array before we started to write - // any information about the codeAttribute - // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset - // to get the right position, 6 for the max_stack etc... - int code_length = this.codeStream.position; - if (code_length > 65535) { - this.codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( - this.codeStream.methodDeclaration.scope.referenceType()); - } - if (localContentsOffset + 20 >= this.contents.length) { - resizeContents(20); - } - int max_stack = this.codeStream.stackMax; - this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); - this.contents[codeAttributeOffset + 7] = (byte) max_stack; - int max_locals = this.codeStream.maxLocals; - this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); - this.contents[codeAttributeOffset + 9] = (byte) max_locals; - this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); - this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); - this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); - this.contents[codeAttributeOffset + 13] = (byte) code_length; - - boolean addStackMaps = (this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0; - // write the exception table - ExceptionLabel[] exceptionLabels = this.codeStream.exceptionLabels; - int exceptionHandlersCount = 0; // each label holds one handler per range (start/end contiguous) - for (int i = 0, length = this.codeStream.exceptionLabelsCounter; i < length; i++) { - exceptionHandlersCount += this.codeStream.exceptionLabels[i].getCount() / 2; - } - int exSize = exceptionHandlersCount * 8 + 2; - if (exSize + localContentsOffset >= this.contents.length) { - resizeContents(exSize); - } - // there is no exception table, so we need to offset by 2 the current offset and move - // on the attribute generation - this.contents[localContentsOffset++] = (byte) (exceptionHandlersCount >> 8); - this.contents[localContentsOffset++] = (byte) exceptionHandlersCount; - for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { - ExceptionLabel exceptionLabel = exceptionLabels[i]; - if (exceptionLabel != null) { - int iRange = 0, maxRange = exceptionLabel.getCount(); - if ((maxRange & 1) != 0) { - this.codeStream.methodDeclaration.scope.problemReporter().abortDueToInternalError( - Messages.bind(Messages.abort_invalidExceptionAttribute, new String(this.codeStream.methodDeclaration.selector)), - this.codeStream.methodDeclaration); - } - while (iRange < maxRange) { - int start = exceptionLabel.ranges[iRange++]; // even ranges are start positions - this.contents[localContentsOffset++] = (byte) (start >> 8); - this.contents[localContentsOffset++] = (byte) start; - int end = exceptionLabel.ranges[iRange++]; // odd ranges are end positions - this.contents[localContentsOffset++] = (byte) (end >> 8); - this.contents[localContentsOffset++] = (byte) end; - int handlerPC = exceptionLabel.position; - this.contents[localContentsOffset++] = (byte) (handlerPC >> 8); - this.contents[localContentsOffset++] = (byte) handlerPC; - if (addStackMaps) { - StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; - stackMapFrameCodeStream.addFramePosition(handlerPC); -// stackMapFrameCodeStream.addExceptionMarker(handlerPC, exceptionLabel.exceptionType); - } - if (exceptionLabel.exceptionType == null) { - // any exception handler - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - } else { - int nameIndex; - if (exceptionLabel.exceptionType == TypeBinding.NULL) { - /* represents denote ClassNotFoundException, see class literal access*/ - nameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName); - } else { - nameIndex = this.constantPool.literalIndexForType(exceptionLabel.exceptionType); - } - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) nameIndex; - } - } - } - } - // debug attributes - int codeAttributeAttributeOffset = localContentsOffset; - int attributesNumber = 0; - // leave two bytes for the attribute_length - localContentsOffset += 2; - if (localContentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - - this.contentsOffset = localContentsOffset; - - // first we handle the linenumber attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { - attributesNumber += generateLineNumberAttribute(); - } - // then we do the local variable attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { - attributesNumber += generateLocalVariableTableAttribute(code_length, true, false); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) { - attributesNumber += generateStackMapTableAttribute( - null, - code_length, - codeAttributeOffset, - max_locals, - true, - scope); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { - attributesNumber += generateStackMapAttribute( - null, - code_length, - codeAttributeOffset, - max_locals, - true, - scope); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { - attributesNumber += generateTypeAnnotationsOnCodeAttribute(); - } - - // update the number of attributes - // ensure first that there is enough space available inside the contents array - if (codeAttributeAttributeOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); - this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; - // update the attribute length - int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); - this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); - this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); - this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); - this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; - } - - /** - * INTERNAL USE-ONLY - * That method completes the creation of the code attribute by setting - * - the attribute_length - * - max_stack - * - max_locals - * - code_length - * - exception table - * - and debug attributes if necessary. - */ - public void completeCodeAttributeForClinit( - int codeAttributeOffset, - int problemLine, - MethodScope scope) { - // reinitialize the contents with the byte modified by the code stream - this.contents = this.codeStream.bCodeStream; - int localContentsOffset = this.codeStream.classFileOffset; - // codeAttributeOffset is the position inside contents byte array before we started to write - // any information about the codeAttribute - // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset - // to get the right position, 6 for the max_stack etc... - int code_length = this.codeStream.position; - if (code_length > 65535) { - this.codeStream.methodDeclaration.scope.problemReporter().bytecodeExceeds64KLimit( - this.codeStream.methodDeclaration.scope.referenceType()); - } - if (localContentsOffset + 20 >= this.contents.length) { - resizeContents(20); - } - int max_stack = this.codeStream.stackMax; - this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); - this.contents[codeAttributeOffset + 7] = (byte) max_stack; - int max_locals = this.codeStream.maxLocals; - this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); - this.contents[codeAttributeOffset + 9] = (byte) max_locals; - this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); - this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); - this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); - this.contents[codeAttributeOffset + 13] = (byte) code_length; - - // write the exception table - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - - // debug attributes - int codeAttributeAttributeOffset = localContentsOffset; - int attributesNumber = 0; // leave two bytes for the attribute_length - localContentsOffset += 2; // first we handle the linenumber attribute - if (localContentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - - this.contentsOffset = localContentsOffset; - // first we handle the linenumber attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { - attributesNumber += generateLineNumberAttribute(problemLine); - } - localContentsOffset = this.contentsOffset; - // then we do the local variable attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { - int localVariableNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); - if (localContentsOffset + 8 >= this.contents.length) { - resizeContents(8); - } - this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) localVariableNameIndex; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 2; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - attributesNumber++; - } - - this.contentsOffset = localContentsOffset; - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) { - attributesNumber += generateStackMapTableAttribute( - null, - code_length, - codeAttributeOffset, - max_locals, - true, - scope); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { - attributesNumber += generateStackMapAttribute( - null, - code_length, - codeAttributeOffset, - max_locals, - true, - scope); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { - attributesNumber += generateTypeAnnotationsOnCodeAttribute(); - } - - // update the number of attributes - // ensure first that there is enough space available inside the contents array - if (codeAttributeAttributeOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); - this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; - // update the attribute length - int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); - this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); - this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); - this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); - this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; - } - - - public void completeCodeAttributeForMissingAbstractProblemMethod( - MethodBinding binding, - int codeAttributeOffset, - int[] startLineIndexes, - int problemLine) { - // reinitialize the localContents with the byte modified by the code stream - this.contents = this.codeStream.bCodeStream; - int localContentsOffset = this.codeStream.classFileOffset; - // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc... - int max_stack = this.codeStream.stackMax; - this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); - this.contents[codeAttributeOffset + 7] = (byte) max_stack; - int max_locals = this.codeStream.maxLocals; - this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); - this.contents[codeAttributeOffset + 9] = (byte) max_locals; - int code_length = this.codeStream.position; - this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); - this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); - this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); - this.contents[codeAttributeOffset + 13] = (byte) code_length; - // write the exception table - if (localContentsOffset + 50 >= this.contents.length) { - resizeContents(50); - } - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - // debug attributes - int codeAttributeAttributeOffset = localContentsOffset; - int attributesNumber = 0; // leave two bytes for the attribute_length - localContentsOffset += 2; // first we handle the linenumber attribute - if (localContentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - - this.contentsOffset = localContentsOffset; - if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { - if (problemLine == 0) { - problemLine = Util.getLineNumber(binding.sourceStart(), startLineIndexes, 0, startLineIndexes.length-1); - } - attributesNumber += generateLineNumberAttribute(problemLine); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) { - attributesNumber += generateStackMapTableAttribute( - binding, - code_length, - codeAttributeOffset, - max_locals, - false, - null); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { - attributesNumber += generateStackMapAttribute( - binding, - code_length, - codeAttributeOffset, - max_locals, - false, - null); - } - - // then we do the local variable attribute - // update the number of attributes// ensure first that there is enough space available inside the localContents array - if (codeAttributeAttributeOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); - this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; - // update the attribute length - int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); - this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); - this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); - this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); - this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; - } - - /** - * INTERNAL USE-ONLY - * That method completes the creation of the code attribute by setting - * - the attribute_length - * - max_stack - * - max_locals - * - code_length - * - exception table - * - and debug attributes if necessary. - * - * @param codeAttributeOffset int - */ - public void completeCodeAttributeForProblemMethod( - AbstractMethodDeclaration method, - MethodBinding binding, - int codeAttributeOffset, - int[] startLineIndexes, - int problemLine) { - // reinitialize the localContents with the byte modified by the code stream - this.contents = this.codeStream.bCodeStream; - int localContentsOffset = this.codeStream.classFileOffset; - // codeAttributeOffset is the position inside localContents byte array before we started to write// any information about the codeAttribute// That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset// to get the right position, 6 for the max_stack etc... - int max_stack = this.codeStream.stackMax; - this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); - this.contents[codeAttributeOffset + 7] = (byte) max_stack; - int max_locals = this.codeStream.maxLocals; - this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); - this.contents[codeAttributeOffset + 9] = (byte) max_locals; - int code_length = this.codeStream.position; - this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); - this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); - this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); - this.contents[codeAttributeOffset + 13] = (byte) code_length; - // write the exception table - if (localContentsOffset + 50 >= this.contents.length) { - resizeContents(50); - } - - // write the exception table - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - // debug attributes - int codeAttributeAttributeOffset = localContentsOffset; - int attributesNumber = 0; // leave two bytes for the attribute_length - localContentsOffset += 2; // first we handle the linenumber attribute - if (localContentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - - this.contentsOffset = localContentsOffset; - if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { - if (problemLine == 0) { - problemLine = Util.getLineNumber(binding.sourceStart(), startLineIndexes, 0, startLineIndexes.length-1); - } - attributesNumber += generateLineNumberAttribute(problemLine); - } - - // then we do the local variable attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { - final boolean methodDeclarationIsStatic = this.codeStream.methodDeclaration.isStatic(); - attributesNumber += generateLocalVariableTableAttribute(code_length, methodDeclarationIsStatic, false); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0) { - attributesNumber += generateStackMapTableAttribute( - binding, - code_length, - codeAttributeOffset, - max_locals, - false, - null); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { - attributesNumber += generateStackMapAttribute( - binding, - code_length, - codeAttributeOffset, - max_locals, - false, - null); - } - - // update the number of attributes// ensure first that there is enough space available inside the localContents array - if (codeAttributeAttributeOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); - this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; - // update the attribute length - int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); - this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); - this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); - this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); - this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; - } - - /** - * INTERNAL USE-ONLY - * That method completes the creation of the code attribute by setting - * - the attribute_length - * - max_stack - * - max_locals - * - code_length - * - exception table - * - and debug attributes if necessary. - * - * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding - * @param codeAttributeOffset int - */ - public void completeCodeAttributeForSyntheticMethod( - boolean hasExceptionHandlers, - SyntheticMethodBinding binding, - int codeAttributeOffset, - int[] startLineIndexes, - Scope scope) { - // reinitialize the contents with the byte modified by the code stream - this.contents = this.codeStream.bCodeStream; - int localContentsOffset = this.codeStream.classFileOffset; - // codeAttributeOffset is the position inside contents byte array before we started to write - // any information about the codeAttribute - // That means that to write the attribute_length you need to offset by 2 the value of codeAttributeOffset - // to get the right position, 6 for the max_stack etc... - int max_stack = this.codeStream.stackMax; - this.contents[codeAttributeOffset + 6] = (byte) (max_stack >> 8); - this.contents[codeAttributeOffset + 7] = (byte) max_stack; - int max_locals = this.codeStream.maxLocals; - this.contents[codeAttributeOffset + 8] = (byte) (max_locals >> 8); - this.contents[codeAttributeOffset + 9] = (byte) max_locals; - int code_length = this.codeStream.position; - this.contents[codeAttributeOffset + 10] = (byte) (code_length >> 24); - this.contents[codeAttributeOffset + 11] = (byte) (code_length >> 16); - this.contents[codeAttributeOffset + 12] = (byte) (code_length >> 8); - this.contents[codeAttributeOffset + 13] = (byte) code_length; - if ((localContentsOffset + 40) >= this.contents.length) { - resizeContents(40); - } - - boolean addStackMaps = (this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP_TABLE) != 0; - if (hasExceptionHandlers) { - // write the exception table - ExceptionLabel[] exceptionLabels = this.codeStream.exceptionLabels; - int exceptionHandlersCount = 0; // each label holds one handler per range (start/end contiguous) - for (int i = 0, length = this.codeStream.exceptionLabelsCounter; i < length; i++) { - exceptionHandlersCount += this.codeStream.exceptionLabels[i].getCount() / 2; - } - int exSize = exceptionHandlersCount * 8 + 2; - if (exSize + localContentsOffset >= this.contents.length) { - resizeContents(exSize); - } - // there is no exception table, so we need to offset by 2 the current offset and move - // on the attribute generation - this.contents[localContentsOffset++] = (byte) (exceptionHandlersCount >> 8); - this.contents[localContentsOffset++] = (byte) exceptionHandlersCount; - for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { - ExceptionLabel exceptionLabel = exceptionLabels[i]; - if (exceptionLabel != null) { - int iRange = 0, maxRange = exceptionLabel.getCount(); - if ((maxRange & 1) != 0) { - ProblemReporter problemReporter = this.referenceBinding.scope.problemReporter(); - problemReporter.abortDueToInternalError( - Messages.bind(Messages.abort_invalidExceptionAttribute, new String(binding.selector), - problemReporter.referenceContext)); - } - while (iRange < maxRange) { - int start = exceptionLabel.ranges[iRange++]; // even ranges are start positions - this.contents[localContentsOffset++] = (byte) (start >> 8); - this.contents[localContentsOffset++] = (byte) start; - int end = exceptionLabel.ranges[iRange++]; // odd ranges are end positions - this.contents[localContentsOffset++] = (byte) (end >> 8); - this.contents[localContentsOffset++] = (byte) end; - int handlerPC = exceptionLabel.position; - if (addStackMaps) { - StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; - stackMapFrameCodeStream.addFramePosition(handlerPC); - } - this.contents[localContentsOffset++] = (byte) (handlerPC >> 8); - this.contents[localContentsOffset++] = (byte) handlerPC; - if (exceptionLabel.exceptionType == null) { - // any exception handler - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - } else { - int nameIndex; - switch(exceptionLabel.exceptionType.id) { - case T_null : - /* represents ClassNotFoundException, see class literal access*/ - nameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangClassNotFoundExceptionConstantPoolName); - break; - case T_long : - /* represents NoSuchFieldError, see switch table generation*/ - nameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangNoSuchFieldErrorConstantPoolName); - break; - default: - nameIndex = this.constantPool.literalIndexForType(exceptionLabel.exceptionType); - } - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) nameIndex; - } - } - } - } - } else { - // there is no exception table, so we need to offset by 2 the current offset and move - // on the attribute generation - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - } - // debug attributes - int codeAttributeAttributeOffset = localContentsOffset; - int attributesNumber = 0; - // leave two bytes for the attribute_length - localContentsOffset += 2; - if (localContentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - - this.contentsOffset = localContentsOffset; - // first we handle the linenumber attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_LINES) != 0) { - int lineNumber = Util.getLineNumber(binding.sourceStart, startLineIndexes, 0, startLineIndexes.length-1); - attributesNumber += generateLineNumberAttribute(lineNumber); - } - // then we do the local variable attribute - if ((this.produceAttributes & ClassFileConstants.ATTR_VARS) != 0) { - final boolean methodDeclarationIsStatic = binding.isStatic(); - attributesNumber += generateLocalVariableTableAttribute(code_length, methodDeclarationIsStatic, true); - } - if (addStackMaps) { - attributesNumber += generateStackMapTableAttribute(binding, code_length, codeAttributeOffset, max_locals, false, scope); - } - - if ((this.produceAttributes & ClassFileConstants.ATTR_STACK_MAP) != 0) { - attributesNumber += generateStackMapAttribute( - binding, - code_length, - codeAttributeOffset, - max_locals, - false, - scope); - } - - // update the number of attributes - // ensure first that there is enough space available inside the contents array - if (codeAttributeAttributeOffset + 2 >= this.contents.length) { - resizeContents(2); - } - this.contents[codeAttributeAttributeOffset++] = (byte) (attributesNumber >> 8); - this.contents[codeAttributeAttributeOffset] = (byte) attributesNumber; - - // update the attribute length - int codeAttributeLength = this.contentsOffset - (codeAttributeOffset + 6); - this.contents[codeAttributeOffset + 2] = (byte) (codeAttributeLength >> 24); - this.contents[codeAttributeOffset + 3] = (byte) (codeAttributeLength >> 16); - this.contents[codeAttributeOffset + 4] = (byte) (codeAttributeLength >> 8); - this.contents[codeAttributeOffset + 5] = (byte) codeAttributeLength; - } - - /** - * INTERNAL USE-ONLY - * That method completes the creation of the code attribute by setting - * - the attribute_length - * - max_stack - * - max_locals - * - code_length - * - exception table - * - and debug attributes if necessary. - * - * @param binding org.eclipse.jdt.internal.compiler.lookup.SyntheticAccessMethodBinding - * @param codeAttributeOffset int - */ - public void completeCodeAttributeForSyntheticMethod( - SyntheticMethodBinding binding, - int codeAttributeOffset, - int[] startLineIndexes) { - - this.completeCodeAttributeForSyntheticMethod( - false, - binding, - codeAttributeOffset, - startLineIndexes, - ((SourceTypeBinding) binding.declaringClass).scope); - } - - private void completeArgumentAnnotationInfo(Argument[] arguments, List allAnnotationContexts) { - for (int i = 0, max = arguments.length; i < max; i++) { - Argument argument = arguments[i]; - if ((argument.bits & ASTNode.HasTypeAnnotations) != 0) { - argument.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER, i, allAnnotationContexts); - } - } - } - - /** - * INTERNAL USE-ONLY - * Complete the creation of a method info by setting up the number of attributes at the right offset. - * - * @param methodAttributeOffset int - * @param attributesNumber int - */ - public void completeMethodInfo( - MethodBinding binding, - int methodAttributeOffset, - int attributesNumber) { - - if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { - List allTypeAnnotationContexts = new ArrayList<>(); - AbstractMethodDeclaration methodDeclaration = binding.sourceMethod(); - if (methodDeclaration != null) { - if ((methodDeclaration.bits & ASTNode.HasTypeAnnotations) != 0) { - Argument[] arguments = methodDeclaration.arguments; - if (arguments != null) { - completeArgumentAnnotationInfo(arguments, allTypeAnnotationContexts); - } - Receiver receiver = methodDeclaration.receiver; - if (receiver != null && (receiver.type.bits & ASTNode.HasTypeAnnotations) != 0) { - receiver.type.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_RECEIVER, allTypeAnnotationContexts); - } - } - Annotation[] annotations = methodDeclaration.annotations; - if (annotations != null && !methodDeclaration.isClinit() && (methodDeclaration.isConstructor() || binding.returnType.id != T_void)) { - // at source level type annotations have not been moved from declaration to type use position, collect them now: - methodDeclaration.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_RETURN, allTypeAnnotationContexts); - } - if (!methodDeclaration.isConstructor() && !methodDeclaration.isClinit() && binding.returnType.id != T_void) { - MethodDeclaration declaration = (MethodDeclaration) methodDeclaration; - TypeReference typeReference = declaration.returnType; - if ((typeReference.bits & ASTNode.HasTypeAnnotations) != 0) { - typeReference.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_RETURN, allTypeAnnotationContexts); - } - } - TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions; - if (thrownExceptions != null) { - for (int i = 0, max = thrownExceptions.length; i < max; i++) { - TypeReference thrownException = thrownExceptions[i]; - thrownException.getAllAnnotationContexts(AnnotationTargetTypeConstants.THROWS, i, allTypeAnnotationContexts); - } - } - TypeParameter[] typeParameters = methodDeclaration.typeParameters(); - if (typeParameters != null) { - for (int i = 0, max = typeParameters.length; i < max; i++) { - TypeParameter typeParameter = typeParameters[i]; - if ((typeParameter.bits & ASTNode.HasTypeAnnotations) != 0) { - typeParameter.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER, i, allTypeAnnotationContexts); - } - } - } - } else if (binding.sourceLambda() != null) { // SyntheticMethodBinding, purpose : LambdaMethod. - LambdaExpression lambda = binding.sourceLambda(); - if ((lambda.bits & ASTNode.HasTypeAnnotations) != 0) { - if (lambda.arguments != null) - completeArgumentAnnotationInfo(lambda.arguments, allTypeAnnotationContexts); - } - } - int size = allTypeAnnotationContexts.size(); - attributesNumber = completeRuntimeTypeAnnotations(attributesNumber, - null, - node -> size > 0, - () -> allTypeAnnotationContexts); - } - if ((this.produceAttributes & ClassFileConstants.ATTR_METHOD_PARAMETERS) != 0 || - binding.isConstructor() && binding.declaringClass.isRecord()) { - attributesNumber += generateMethodParameters(binding); - } - // update the number of attributes - this.contents[methodAttributeOffset++] = (byte) (attributesNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributesNumber; - } - - private void dumpLocations(int[] locations) { - if (locations == null) { - // no type path - if (this.contentsOffset + 1 >= this.contents.length) { - resizeContents(1); - } - this.contents[this.contentsOffset++] = (byte) 0; - } else { - int length = locations.length; - if (this.contentsOffset + length >= this.contents.length) { - resizeContents(length + 1); - } - this.contents[this.contentsOffset++] = (byte) (locations.length / 2); - for (int i = 0; i < length; i++) { - this.contents[this.contentsOffset++] = (byte) locations[i]; - } - } - } - private void dumpTargetTypeContents(int targetType, AnnotationContext annotationContext) { - switch(targetType) { - case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER : - case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER : - // parameter index - this.contents[this.contentsOffset++] = (byte) annotationContext.info; - break; - - case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER_BOUND : - // type_parameter_index - this.contents[this.contentsOffset++] = (byte) annotationContext.info; - // bound_index - this.contents[this.contentsOffset++] = (byte) annotationContext.info2; - break; - case AnnotationTargetTypeConstants.FIELD : - case AnnotationTargetTypeConstants.METHOD_RECEIVER : - case AnnotationTargetTypeConstants.METHOD_RETURN : - // target_info is empty_target - break; - case AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER : - // target_info is parameter index - this.contents[this.contentsOffset++] = (byte) annotationContext.info; - break; - - case AnnotationTargetTypeConstants.INSTANCEOF : - case AnnotationTargetTypeConstants.NEW : - case AnnotationTargetTypeConstants.EXCEPTION_PARAMETER : - case AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE : - case AnnotationTargetTypeConstants.METHOD_REFERENCE : - // bytecode offset for new/instanceof/method_reference - // exception table entry index for exception_parameter - this.contents[this.contentsOffset++] = (byte) (annotationContext.info >> 8); - this.contents[this.contentsOffset++] = (byte) annotationContext.info; - break; - case AnnotationTargetTypeConstants.CAST : - // bytecode offset - this.contents[this.contentsOffset++] = (byte) (annotationContext.info >> 8); - this.contents[this.contentsOffset++] = (byte) annotationContext.info; - this.contents[this.contentsOffset++] = (byte) annotationContext.info2; - break; - - case AnnotationTargetTypeConstants.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT : - case AnnotationTargetTypeConstants.METHOD_INVOCATION_TYPE_ARGUMENT : - case AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT : - case AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT : - // bytecode offset - this.contents[this.contentsOffset++] = (byte) (annotationContext.info >> 8); - this.contents[this.contentsOffset++] = (byte) annotationContext.info; - // type_argument_index - this.contents[this.contentsOffset++] = (byte) annotationContext.info2; - break; - - case AnnotationTargetTypeConstants.CLASS_EXTENDS : - case AnnotationTargetTypeConstants.THROWS : - // For CLASS_EXTENDS - info is supertype index (-1 = superclass) - // For THROWS - info is exception table index - this.contents[this.contentsOffset++] = (byte) (annotationContext.info >> 8); - this.contents[this.contentsOffset++] = (byte) annotationContext.info; - break; - - case AnnotationTargetTypeConstants.LOCAL_VARIABLE : - case AnnotationTargetTypeConstants.RESOURCE_VARIABLE : - int localVariableTableOffset = this.contentsOffset; - LocalVariableBinding localVariable = annotationContext.variableBinding; - int actualSize = 0; - int initializationCount = localVariable.initializationCount; - actualSize += 2 /* for number of entries */ + (6 * initializationCount); - // reserve enough space - if (this.contentsOffset + actualSize >= this.contents.length) { - resizeContents(actualSize); - } - this.contentsOffset += 2; - int numberOfEntries = 0; - for (int j = 0; j < initializationCount; j++) { - int startPC = localVariable.initializationPCs[j << 1]; - int endPC = localVariable.initializationPCs[(j << 1) + 1]; - if (startPC != endPC) { // only entries for non zero length - // now we can safely add the local entry - numberOfEntries++; - this.contents[this.contentsOffset++] = (byte) (startPC >> 8); - this.contents[this.contentsOffset++] = (byte) startPC; - int length = endPC - startPC; - this.contents[this.contentsOffset++] = (byte) (length >> 8); - this.contents[this.contentsOffset++] = (byte) length; - int resolvedPosition = localVariable.resolvedPosition; - this.contents[this.contentsOffset++] = (byte) (resolvedPosition >> 8); - this.contents[this.contentsOffset++] = (byte) resolvedPosition; - } - } - this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); - this.contents[localVariableTableOffset] = (byte) numberOfEntries; - break; - case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER_BOUND : - this.contents[this.contentsOffset++] = (byte) annotationContext.info; - this.contents[this.contentsOffset++] = (byte) annotationContext.info2; - break; - } - } - - - - /** - * INTERNAL USE-ONLY - * This methods returns a char[] representing the file name of the receiver - * - * @return char[] - */ - public char[] fileName() { - return this.constantPool.UTF8Cache.returnKeyFor(2); - } - - private void generateAnnotation(Annotation annotation, int currentOffset) { - int startingContentsOffset = currentOffset; - if (this.contentsOffset + 4 >= this.contents.length) { - resizeContents(4); - } - TypeBinding annotationTypeBinding = annotation.resolvedType; - if (annotationTypeBinding == null) { - this.contentsOffset = startingContentsOffset; - return; - } - if (annotationTypeBinding.isMemberType()) { - this.recordInnerClasses(annotationTypeBinding); - } - final int typeIndex = this.constantPool.literalIndex(annotationTypeBinding.signature()); - this.contents[this.contentsOffset++] = (byte) (typeIndex >> 8); - this.contents[this.contentsOffset++] = (byte) typeIndex; - if (annotation instanceof NormalAnnotation) { - NormalAnnotation normalAnnotation = (NormalAnnotation) annotation; - MemberValuePair[] memberValuePairs = normalAnnotation.memberValuePairs; - int memberValuePairOffset = this.contentsOffset; - if (memberValuePairs != null) { - int memberValuePairsCount = 0; - int memberValuePairsLengthPosition = this.contentsOffset; - this.contentsOffset += 2; // leave space to fill in the pair count later - int resetPosition = this.contentsOffset; - final int memberValuePairsLength = memberValuePairs.length; - loop: for (int i = 0; i < memberValuePairsLength; i++) { - MemberValuePair memberValuePair = memberValuePairs[i]; - if (this.contentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - final int elementNameIndex = this.constantPool.literalIndex(memberValuePair.name); - this.contents[this.contentsOffset++] = (byte) (elementNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) elementNameIndex; - MethodBinding methodBinding = memberValuePair.binding; - if (methodBinding == null) { - this.contentsOffset = resetPosition; - } else { - try { - generateElementValue(memberValuePair.value, methodBinding.returnType, memberValuePairOffset); - if (this.contentsOffset == memberValuePairOffset) { - // ignore all annotation values - this.contents[this.contentsOffset++] = 0; - this.contents[this.contentsOffset++] = 0; - break loop; - } - memberValuePairsCount++; - resetPosition = this.contentsOffset; - } catch(ClassCastException | ShouldNotImplement e) { - this.contentsOffset = resetPosition; - } - } - } - this.contents[memberValuePairsLengthPosition++] = (byte) (memberValuePairsCount >> 8); - this.contents[memberValuePairsLengthPosition++] = (byte) memberValuePairsCount; - } else { - this.contents[this.contentsOffset++] = 0; - this.contents[this.contentsOffset++] = 0; - } - } else if (annotation instanceof SingleMemberAnnotation) { - SingleMemberAnnotation singleMemberAnnotation = (SingleMemberAnnotation) annotation; - // this is a single member annotation (one member value) - this.contents[this.contentsOffset++] = 0; - this.contents[this.contentsOffset++] = 1; - if (this.contentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - final int elementNameIndex = this.constantPool.literalIndex(VALUE); - this.contents[this.contentsOffset++] = (byte) (elementNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) elementNameIndex; - MethodBinding methodBinding = singleMemberAnnotation.memberValuePairs()[0].binding; - if (methodBinding == null) { - this.contentsOffset = startingContentsOffset; - } else { - int memberValuePairOffset = this.contentsOffset; - try { - generateElementValue(singleMemberAnnotation.memberValue, methodBinding.returnType, memberValuePairOffset); - if (this.contentsOffset == memberValuePairOffset) { - // completely remove the annotation as its value is invalid - this.contentsOffset = startingContentsOffset; - } - } catch(ClassCastException | ShouldNotImplement e) { - this.contentsOffset = startingContentsOffset; - } - } - } else { - // this is a marker annotation (no member value pairs) - this.contents[this.contentsOffset++] = 0; - this.contents[this.contentsOffset++] = 0; - } - } - - private int generateAnnotationDefaultAttribute(AnnotationMethodDeclaration declaration, int attributeOffset) { - int attributesNumber = 0; - // add an annotation default attribute - int annotationDefaultNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.AnnotationDefaultName); - if (this.contentsOffset + 6 >= this.contents.length) { - resizeContents(6); - } - this.contents[this.contentsOffset++] = (byte) (annotationDefaultNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) annotationDefaultNameIndex; - int attributeLengthOffset = this.contentsOffset; - this.contentsOffset += 4; - generateElementValue(declaration.defaultValue, declaration.binding.returnType, attributeOffset); - if (this.contentsOffset != attributeOffset) { - int attributeLength = this.contentsOffset - attributeLengthOffset - 4; - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); - this.contents[attributeLengthOffset++] = (byte) attributeLength; - attributesNumber++; - } - return attributesNumber; - } - /** - * INTERNAL USE-ONLY - * That method generates the header of a code attribute. - * - the index inside the constant pool for the attribute name ("Code") - * - leave some space for attribute_length(4), max_stack(2), max_locals(2), code_length(4). - */ - public void generateCodeAttributeHeader() { - if (this.contentsOffset + 20 >= this.contents.length) { - resizeContents(20); - } - int constantValueNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.CodeName); - this.contents[this.contentsOffset++] = (byte) (constantValueNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) constantValueNameIndex; - // leave space for attribute_length(4), max_stack(2), max_locals(2), code_length(4) - this.contentsOffset += 12; - } - - private int generateConstantValueAttribute(Constant fieldConstant, FieldBinding fieldBinding, int fieldAttributeOffset) { - int localContentsOffset = this.contentsOffset; - int attributesNumber = 1; - if (localContentsOffset + 8 >= this.contents.length) { - resizeContents(8); - } - // Now we generate the constant attribute corresponding to the fieldBinding - int constantValueNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.ConstantValueName); - this.contents[localContentsOffset++] = (byte) (constantValueNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) constantValueNameIndex; - // The attribute length = 2 in case of a constantValue attribute - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 2; - // Need to add the constant_value_index - switch (fieldConstant.typeID()) { - case T_boolean : - int booleanValueIndex = - this.constantPool.literalIndex(fieldConstant.booleanValue() ? 1 : 0); - this.contents[localContentsOffset++] = (byte) (booleanValueIndex >> 8); - this.contents[localContentsOffset++] = (byte) booleanValueIndex; - break; - case T_byte : - case T_char : - case T_int : - case T_short : - int integerValueIndex = - this.constantPool.literalIndex(fieldConstant.intValue()); - this.contents[localContentsOffset++] = (byte) (integerValueIndex >> 8); - this.contents[localContentsOffset++] = (byte) integerValueIndex; - break; - case T_float : - int floatValueIndex = - this.constantPool.literalIndex(fieldConstant.floatValue()); - this.contents[localContentsOffset++] = (byte) (floatValueIndex >> 8); - this.contents[localContentsOffset++] = (byte) floatValueIndex; - break; - case T_double : - int doubleValueIndex = - this.constantPool.literalIndex(fieldConstant.doubleValue()); - this.contents[localContentsOffset++] = (byte) (doubleValueIndex >> 8); - this.contents[localContentsOffset++] = (byte) doubleValueIndex; - break; - case T_long : - int longValueIndex = - this.constantPool.literalIndex(fieldConstant.longValue()); - this.contents[localContentsOffset++] = (byte) (longValueIndex >> 8); - this.contents[localContentsOffset++] = (byte) longValueIndex; - break; - case T_JavaLangString : - int stringValueIndex = - this.constantPool.literalIndex( - ((StringConstant) fieldConstant).stringValue()); - if (stringValueIndex == -1) { - if (!this.creatingProblemType) { - // report an error and abort: will lead to a problem type classfile creation - TypeDeclaration typeDeclaration = this.referenceBinding.scope.referenceContext; - FieldDeclaration[] fieldDecls = typeDeclaration.fields; - int max = fieldDecls == null ? 0 : fieldDecls.length; - for (int i = 0; i < max; i++) { - if (fieldDecls[i].binding == fieldBinding) { - // problem should abort - typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit( - fieldDecls[i]); - } - } - } else { - // already inside a problem type creation : no constant for this field - this.contentsOffset = fieldAttributeOffset; - attributesNumber = 0; - } - } else { - this.contents[localContentsOffset++] = (byte) (stringValueIndex >> 8); - this.contents[localContentsOffset++] = (byte) stringValueIndex; - } - } - this.contentsOffset = localContentsOffset; - return attributesNumber; - } - private int generateDeprecatedAttribute() { - int localContentsOffset = this.contentsOffset; - if (localContentsOffset + 6 >= this.contents.length) { - resizeContents(6); - } - int deprecatedAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.DeprecatedName); - this.contents[localContentsOffset++] = (byte) (deprecatedAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) deprecatedAttributeNameIndex; - // the length of a deprecated attribute is equals to 0 - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contentsOffset = localContentsOffset; - return 1; - } - private int generateNestHostAttribute() { - SourceTypeBinding nestHost = this.referenceBinding.getNestHost(); - if (nestHost == null) - return 0; - int localContentsOffset = this.contentsOffset; - if (localContentsOffset + 10 >= this.contents.length) { - resizeContents(10); - } - int nestHostAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.NestHost); - this.contents[localContentsOffset++] = (byte) (nestHostAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) nestHostAttributeNameIndex; - - // The value of the attribute_length item must be two. - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 2; - - int nestHostIndex = this.constantPool.literalIndexForType(nestHost.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (nestHostIndex >> 8); - this.contents[localContentsOffset++] = (byte) nestHostIndex; - this.contentsOffset = localContentsOffset; - return 1; - } - private int generateNestMembersAttribute() { - - int localContentsOffset = this.contentsOffset; - List nestedMembers = getNestMembers(); - int numberOfNestedMembers = nestedMembers != null ? nestedMembers.size() : 0; - if (numberOfNestedMembers == 0) // JVMS 11 4.7.29 says "at most one" NestMembers attribute - return if none. - return 0; - - int exSize = 8 + 2 * numberOfNestedMembers; - if (exSize + localContentsOffset >= this.contents.length) { - resizeContents(exSize); - } - int attributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.NestMembers); - this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) attributeNameIndex; - int value = (numberOfNestedMembers << 1) + 2; - this.contents[localContentsOffset++] = (byte) (value >> 24); - this.contents[localContentsOffset++] = (byte) (value >> 16); - this.contents[localContentsOffset++] = (byte) (value >> 8); - this.contents[localContentsOffset++] = (byte) value; - this.contents[localContentsOffset++] = (byte) (numberOfNestedMembers >> 8); - this.contents[localContentsOffset++] = (byte) numberOfNestedMembers; - - for (int i = 0; i < numberOfNestedMembers; i++) { - char[] nestMemberName = nestedMembers.get(i).toCharArray(); - int nestedMemberIndex = this.constantPool.literalIndexForType(nestMemberName); - this.contents[localContentsOffset++] = (byte) (nestedMemberIndex >> 8); - this.contents[localContentsOffset++] = (byte) nestedMemberIndex; - } - this.contentsOffset = localContentsOffset; - return 1; - } - private int generateNestAttributes() { - int nAttrs = generateNestMembersAttribute(); //either member or host will exist 4.7.29 - nAttrs += generateNestHostAttribute(); - return nAttrs; - } - private int generatePermittedTypeAttributes() { - SourceTypeBinding type = this.referenceBinding; - int localContentsOffset = this.contentsOffset; - ReferenceBinding[] permittedTypes = type.permittedTypes(); - int l = permittedTypes != null ? permittedTypes.length : 0; - if (l == 0) - return 0; - - int exSize = 8 + 2 * l; - if (exSize + localContentsOffset >= this.contents.length) { - resizeContents(exSize); - } - int attributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.PermittedSubclasses); - this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) attributeNameIndex; - int value = (l << 1) + 2; - this.contents[localContentsOffset++] = (byte) (value >> 24); - this.contents[localContentsOffset++] = (byte) (value >> 16); - this.contents[localContentsOffset++] = (byte) (value >> 8); - this.contents[localContentsOffset++] = (byte) value; - this.contents[localContentsOffset++] = (byte) (l >> 8); - this.contents[localContentsOffset++] = (byte) l; - - for (int i = 0; i < l; i++) { - int permittedTypeIndex = this.constantPool.literalIndexForType(permittedTypes[i]); - this.contents[localContentsOffset++] = (byte) (permittedTypeIndex >> 8); - this.contents[localContentsOffset++] = (byte) permittedTypeIndex; - } - this.contentsOffset = localContentsOffset; - return 1; - } - private int generateRecordAttributes() { - SourceTypeBinding record = this.referenceBinding; - if (record == null || !record.isRecord()) - return 0; - int localContentsOffset = this.contentsOffset; - RecordComponentBinding[] recordComponents = this.referenceBinding.components(); - if (recordComponents == null) - return 0; - // could be an empty record also, account for zero components as well. - - int numberOfRecordComponents = recordComponents.length; - - int exSize = 8 + 2 * numberOfRecordComponents; - if (exSize + localContentsOffset >= this.contents.length) { - resizeContents(exSize); - } - /* - * Record_attribute { - * u2 attribute_name_index; - * u4 attribute_length; - * u2 components_count; - * component_info components[components_count]; - * }*/ - int attributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.RecordClass); - this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) attributeNameIndex; - int attrLengthOffset = localContentsOffset; - localContentsOffset += 4; - int base = localContentsOffset; - this.contents[localContentsOffset++] = (byte) (numberOfRecordComponents >> 8); - this.contents[localContentsOffset++] = (byte) numberOfRecordComponents; - this.contentsOffset = localContentsOffset; - for (int i = 0; i < numberOfRecordComponents; i++) { - addComponentInfo(recordComponents[i]); - } - int attrLength = this.contentsOffset - base; - this.contents[attrLengthOffset++] = (byte) (attrLength >> 24); - this.contents[attrLengthOffset++] = (byte) (attrLength >> 16); - this.contents[attrLengthOffset++] = (byte) (attrLength >> 8); - this.contents[attrLengthOffset++] = (byte) attrLength; - return 1; - } - - private int generateModuleAttribute(ModuleDeclaration module) { - ModuleBinding binding = module.binding; - int localContentsOffset = this.contentsOffset; - if (localContentsOffset + 10 >= this.contents.length) { - resizeContents(10); - } - int moduleAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.ModuleName); - this.contents[localContentsOffset++] = (byte) (moduleAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) moduleAttributeNameIndex; - int attrLengthOffset = localContentsOffset; - localContentsOffset += 4; - int moduleNameIndex = - this.constantPool.literalIndexForModule(binding.moduleName); - this.contents[localContentsOffset++] = (byte) (moduleNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) moduleNameIndex; - int flags = module.modifiers & ~(ClassFileConstants.AccModule); - this.contents[localContentsOffset++] = (byte) (flags >> 8); - this.contents[localContentsOffset++] = (byte) flags; - String moduleVersion = module.getModuleVersion(); - int module_version_idx = moduleVersion == null ? 0 : this.constantPool.literalIndex(moduleVersion.toCharArray()); - this.contents[localContentsOffset++] = (byte) (module_version_idx >> 8); - this.contents[localContentsOffset++] = (byte) module_version_idx; - int attrLength = 6; - - // ================= requires section ================= - /** u2 requires_count; - { u2 requires_index; - u2 requires_flags; - } requires[requires_count]; - **/ - int requiresCountOffset = localContentsOffset; - int requiresCount = module.requiresCount; - int requiresSize = 2 + requiresCount * 6; - if (localContentsOffset + requiresSize >= this.contents.length) { - resizeContents(requiresSize); - } - - localContentsOffset += 2; - ModuleBinding javaBaseBinding = null; - for(int i = 0; i < module.requiresCount; i++) { - RequiresStatement req = module.requires[i]; - ModuleBinding reqBinding = req.resolvedBinding; - if (CharOperation.equals(reqBinding.moduleName, TypeConstants.JAVA_BASE)) { - javaBaseBinding = reqBinding; - } - int nameIndex = this.constantPool.literalIndexForModule(reqBinding.moduleName); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) (nameIndex); - flags = req.modifiers; - this.contents[localContentsOffset++] = (byte) (flags >> 8); - this.contents[localContentsOffset++] = (byte) (flags); - int required_version = 0; - this.contents[localContentsOffset++] = (byte) (required_version >> 8); - this.contents[localContentsOffset++] = (byte) (required_version); - } - if (!CharOperation.equals(binding.moduleName, TypeConstants.JAVA_BASE) && javaBaseBinding == null) { - if (localContentsOffset + 6 >= this.contents.length) { - resizeContents(6); - } - javaBaseBinding = binding.environment.javaBaseModule(); - int javabase_index = this.constantPool.literalIndexForModule(javaBaseBinding.moduleName); - this.contents[localContentsOffset++] = (byte) (javabase_index >> 8); - this.contents[localContentsOffset++] = (byte) (javabase_index); - flags = ClassFileConstants.AccMandated; - this.contents[localContentsOffset++] = (byte) (flags >> 8); - this.contents[localContentsOffset++] = (byte) flags; - int required_version = 0; - this.contents[localContentsOffset++] = (byte) (required_version >> 8); - this.contents[localContentsOffset++] = (byte) (required_version); - requiresCount++; - } - this.contents[requiresCountOffset++] = (byte) (requiresCount >> 8); - this.contents[requiresCountOffset++] = (byte) requiresCount; - attrLength += 2 + 6 * requiresCount; - // ================= end requires section ================= - - // ================= exports section ================= - /** - * u2 exports_count; - * { u2 exports_index; - * u2 exports_flags; - * u2 exports_to_count; - * u2 exports_to_index[exports_to_count]; - * } exports[exports_count]; - */ - int exportsSize = 2 + module.exportsCount * 6; - if (localContentsOffset + exportsSize >= this.contents.length) { - resizeContents(exportsSize); - } - this.contents[localContentsOffset++] = (byte) (module.exportsCount >> 8); - this.contents[localContentsOffset++] = (byte) module.exportsCount; - for (int i = 0; i < module.exportsCount; i++) { - ExportsStatement ref = module.exports[i]; - if (localContentsOffset + 6 >= this.contents.length) { - resizeContents((module.exportsCount - i) * 6); - } - int nameIndex = this.constantPool.literalIndexForPackage(CharOperation.replaceOnCopy(ref.pkgName, '.', '/')); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) (nameIndex); - // TODO exports_flags - check when they are set - this.contents[localContentsOffset++] = (byte) 0; - this.contents[localContentsOffset++] = (byte) 0; - - int exportsToCount = ref.isQualified() ? ref.targets.length : 0; - this.contents[localContentsOffset++] = (byte) (exportsToCount >> 8); - this.contents[localContentsOffset++] = (byte) (exportsToCount); - if (exportsToCount > 0) { - int targetSize = 2 * exportsToCount; - if (localContentsOffset + targetSize >= this.contents.length) { - resizeContents(targetSize); - } - for(int j = 0; j < exportsToCount; j++) { - nameIndex = this.constantPool.literalIndexForModule(ref.targets[j].moduleName); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) (nameIndex); - } - attrLength += targetSize; - } - } - attrLength += exportsSize; - // ================= end exports section ================= - - // ================= opens section ================= - /** - * u2 opens_count; - * { u2 opens_index; - * u2 opens_flags; - * u2 opens_to_count; - * u2 opens_to_index[opens_to_count]; - * } exports[exports_count]; - */ - int opensSize = 2 + module.opensCount * 6; - if (localContentsOffset + opensSize >= this.contents.length) { - resizeContents(opensSize); - } - this.contents[localContentsOffset++] = (byte) (module.opensCount >> 8); - this.contents[localContentsOffset++] = (byte) module.opensCount; - for (int i = 0; i < module.opensCount; i++) { - OpensStatement ref = module.opens[i]; - if (localContentsOffset + 6 >= this.contents.length) { - resizeContents((module.opensCount - i) * 6); - } - int nameIndex = this.constantPool.literalIndexForPackage(CharOperation.replaceOnCopy(ref.pkgName, '.', '/')); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) (nameIndex); - // TODO opens_flags - check when they are set - this.contents[localContentsOffset++] = (byte) 0; - this.contents[localContentsOffset++] = (byte) 0; - - int opensToCount = ref.isQualified() ? ref.targets.length : 0; - this.contents[localContentsOffset++] = (byte) (opensToCount >> 8); - this.contents[localContentsOffset++] = (byte) (opensToCount); - if (opensToCount > 0) { - int targetSize = 2 * opensToCount; - if (localContentsOffset + targetSize >= this.contents.length) { - resizeContents(targetSize); - } - for(int j = 0; j < opensToCount; j++) { - nameIndex = this.constantPool.literalIndexForModule(ref.targets[j].moduleName); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) (nameIndex); - } - attrLength += targetSize; - } - } - attrLength += opensSize; - // ================= end opens section ================= - - // ================= uses section ================= - /** - * u2 uses_count; - * u2 uses_index[uses_count]; - */ - int usesSize = 2 + 2 * module.usesCount; - if (localContentsOffset + usesSize >= this.contents.length) { - resizeContents(usesSize); - } - this.contents[localContentsOffset++] = (byte) (module.usesCount >> 8); - this.contents[localContentsOffset++] = (byte) module.usesCount; - for(int i = 0; i < module.usesCount; i++) { - int nameIndex = this.constantPool.literalIndexForType(module.uses[i].serviceInterface.resolvedType.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) (nameIndex); - } - attrLength += usesSize; - // ================= end uses section ================= - - // ================= provides section ================= - /** - * u2 provides_count; - * { - * u2 provides_index; - * u2 provides_with_count; - * u2 provides_with_index[provides_with_count]; - * } provides[provides_count]; - */ - int servicesSize = 2 + 4 * module.servicesCount; - if (localContentsOffset + servicesSize >= this.contents.length) { - resizeContents(servicesSize); - } - this.contents[localContentsOffset++] = (byte) (module.servicesCount >> 8); - this.contents[localContentsOffset++] = (byte) module.servicesCount; - for(int i = 0; i < module.servicesCount; i++) { - if (localContentsOffset + 4 >= this.contents.length) { - resizeContents((module.servicesCount - i) * 4); - } - int nameIndex = this.constantPool.literalIndexForType(module.services[i].serviceInterface.resolvedType.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) (nameIndex); - TypeReference[] impls = module.services[i].implementations; - int implLength = impls.length; - this.contents[localContentsOffset++] = (byte) (implLength >> 8); - this.contents[localContentsOffset++] = (byte) implLength; - int targetSize = implLength * 2; - if (localContentsOffset + targetSize >= this.contents.length) { - resizeContents(targetSize); - } - for (int j = 0; j < implLength; j++) { - nameIndex = this.constantPool.literalIndexForType(impls[j].resolvedType.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) (nameIndex); - } - attrLength += targetSize; - } - attrLength += servicesSize; - // ================= end provides section ================= - - this.contents[attrLengthOffset++] = (byte)(attrLength >> 24); - this.contents[attrLengthOffset++] = (byte)(attrLength >> 16); - this.contents[attrLengthOffset++] = (byte)(attrLength >> 8); - this.contents[attrLengthOffset++] = (byte)attrLength; - this.contentsOffset = localContentsOffset; - return 1; - } - - private int generateModuleMainClassAttribute(char[] moduleMainClass) { - int localContentsOffset = this.contentsOffset; - if (localContentsOffset + 8 >= this.contents.length) { - resizeContents(8); - } - int moduleAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.ModuleMainClass); - this.contents[localContentsOffset++] = (byte) (moduleAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) moduleAttributeNameIndex; - int attrLength = 2; - this.contents[localContentsOffset++] = (byte)(attrLength >> 24); - this.contents[localContentsOffset++] = (byte)(attrLength >> 16); - this.contents[localContentsOffset++] = (byte)(attrLength >> 8); - this.contents[localContentsOffset++] = (byte)attrLength; - int moduleNameIndex = this.constantPool.literalIndexForType(moduleMainClass); - this.contents[localContentsOffset++] = (byte) (moduleNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) moduleNameIndex; - this.contentsOffset = localContentsOffset; - return 1; - } - - private int generateModulePackagesAttribute(char[][] packageNames) { - int localContentsOffset = this.contentsOffset; - int maxSize = 6 + 2*packageNames.length; - if (localContentsOffset + maxSize >= this.contents.length) { - resizeContents(maxSize); - } - int moduleAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.ModulePackages); - this.contents[localContentsOffset++] = (byte) (moduleAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) moduleAttributeNameIndex; - - int attrLengthOffset = localContentsOffset; - localContentsOffset+= 4; - int packageCountOffset = localContentsOffset; - localContentsOffset+= 2; - - int packagesCount = 0; - for (char[] packageName : packageNames) { - if (packageName == null || packageName.length == 0) continue; - int packageNameIndex = this.constantPool.literalIndexForPackage(packageName); - this.contents[localContentsOffset++] = (byte) (packageNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) packageNameIndex; - packagesCount++; - } - - this.contents[packageCountOffset++] = (byte)(packagesCount >> 8); - this.contents[packageCountOffset++] = (byte)packagesCount; - int attrLength = 2 + 2 * packagesCount; - this.contents[attrLengthOffset++] = (byte)(attrLength >> 24); - this.contents[attrLengthOffset++] = (byte)(attrLength >> 16); - this.contents[attrLengthOffset++] = (byte)(attrLength >> 8); - this.contents[attrLengthOffset++] = (byte)attrLength; - this.contentsOffset = localContentsOffset; - return 1; - } - - private void generateElementValue( - Expression defaultValue, - TypeBinding memberValuePairReturnType, - int attributeOffset) { - Constant constant = defaultValue.constant; - TypeBinding defaultValueBinding = defaultValue.resolvedType; - if (defaultValueBinding == null) { - this.contentsOffset = attributeOffset; - } else { - if (defaultValueBinding.isMemberType()) { - this.recordInnerClasses(defaultValueBinding); - } - if (memberValuePairReturnType.isMemberType()) { - this.recordInnerClasses(memberValuePairReturnType); - } - if (memberValuePairReturnType.isArrayType() && !defaultValueBinding.isArrayType()) { - // automatic wrapping - if (this.contentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - this.contents[this.contentsOffset++] = (byte) '['; - this.contents[this.contentsOffset++] = (byte) 0; - this.contents[this.contentsOffset++] = (byte) 1; - } - if (constant != null && constant != Constant.NotAConstant) { - generateElementValue(attributeOffset, defaultValue, constant, memberValuePairReturnType.leafComponentType()); - } else { - generateElementValueForNonConstantExpression(defaultValue, attributeOffset, defaultValueBinding); - } - } - } - private void generateElementValue(int attributeOffset, Expression defaultValue, Constant constant, TypeBinding binding) { - if (this.contentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - switch (binding.id) { - case T_boolean : - this.contents[this.contentsOffset++] = (byte) 'Z'; - int booleanValueIndex = - this.constantPool.literalIndex(constant.booleanValue() ? 1 : 0); - this.contents[this.contentsOffset++] = (byte) (booleanValueIndex >> 8); - this.contents[this.contentsOffset++] = (byte) booleanValueIndex; - break; - case T_byte : - this.contents[this.contentsOffset++] = (byte) 'B'; - int integerValueIndex = - this.constantPool.literalIndex(constant.intValue()); - this.contents[this.contentsOffset++] = (byte) (integerValueIndex >> 8); - this.contents[this.contentsOffset++] = (byte) integerValueIndex; - break; - case T_char : - this.contents[this.contentsOffset++] = (byte) 'C'; - integerValueIndex = - this.constantPool.literalIndex(constant.intValue()); - this.contents[this.contentsOffset++] = (byte) (integerValueIndex >> 8); - this.contents[this.contentsOffset++] = (byte) integerValueIndex; - break; - case T_int : - this.contents[this.contentsOffset++] = (byte) 'I'; - integerValueIndex = - this.constantPool.literalIndex(constant.intValue()); - this.contents[this.contentsOffset++] = (byte) (integerValueIndex >> 8); - this.contents[this.contentsOffset++] = (byte) integerValueIndex; - break; - case T_short : - this.contents[this.contentsOffset++] = (byte) 'S'; - integerValueIndex = - this.constantPool.literalIndex(constant.intValue()); - this.contents[this.contentsOffset++] = (byte) (integerValueIndex >> 8); - this.contents[this.contentsOffset++] = (byte) integerValueIndex; - break; - case T_float : - this.contents[this.contentsOffset++] = (byte) 'F'; - int floatValueIndex = - this.constantPool.literalIndex(constant.floatValue()); - this.contents[this.contentsOffset++] = (byte) (floatValueIndex >> 8); - this.contents[this.contentsOffset++] = (byte) floatValueIndex; - break; - case T_double : - this.contents[this.contentsOffset++] = (byte) 'D'; - int doubleValueIndex = - this.constantPool.literalIndex(constant.doubleValue()); - this.contents[this.contentsOffset++] = (byte) (doubleValueIndex >> 8); - this.contents[this.contentsOffset++] = (byte) doubleValueIndex; - break; - case T_long : - this.contents[this.contentsOffset++] = (byte) 'J'; - int longValueIndex = - this.constantPool.literalIndex(constant.longValue()); - this.contents[this.contentsOffset++] = (byte) (longValueIndex >> 8); - this.contents[this.contentsOffset++] = (byte) longValueIndex; - break; - case T_JavaLangString : - this.contents[this.contentsOffset++] = (byte) 's'; - int stringValueIndex = - this.constantPool.literalIndex(((StringConstant) constant).stringValue().toCharArray()); - if (stringValueIndex == -1) { - if (!this.creatingProblemType) { - // report an error and abort: will lead to a problem type classfile creation - TypeDeclaration typeDeclaration = this.referenceBinding.scope.referenceContext; - typeDeclaration.scope.problemReporter().stringConstantIsExceedingUtf8Limit(defaultValue); - } else { - // already inside a problem type creation : no attribute - this.contentsOffset = attributeOffset; - } - } else { - this.contents[this.contentsOffset++] = (byte) (stringValueIndex >> 8); - this.contents[this.contentsOffset++] = (byte) stringValueIndex; - } - } - } - - private void generateElementValueForNonConstantExpression(Expression defaultValue, int attributeOffset, TypeBinding defaultValueBinding) { - if (defaultValueBinding != null) { - if (defaultValueBinding.isEnum()) { - if (this.contentsOffset + 5 >= this.contents.length) { - resizeContents(5); - } - this.contents[this.contentsOffset++] = (byte) 'e'; - FieldBinding fieldBinding = null; - if (defaultValue instanceof QualifiedNameReference) { - QualifiedNameReference nameReference = (QualifiedNameReference) defaultValue; - fieldBinding = (FieldBinding) nameReference.binding; - } else if (defaultValue instanceof SingleNameReference) { - SingleNameReference nameReference = (SingleNameReference) defaultValue; - fieldBinding = (FieldBinding) nameReference.binding; - } else { - this.contentsOffset = attributeOffset; - } - if (fieldBinding != null) { - final int enumConstantTypeNameIndex = this.constantPool.literalIndex(fieldBinding.type.signature()); - final int enumConstantNameIndex = this.constantPool.literalIndex(fieldBinding.name); - this.contents[this.contentsOffset++] = (byte) (enumConstantTypeNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) enumConstantTypeNameIndex; - this.contents[this.contentsOffset++] = (byte) (enumConstantNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) enumConstantNameIndex; - } - } else if (defaultValueBinding.isAnnotationType()) { - if (this.contentsOffset + 1 >= this.contents.length) { - resizeContents(1); - } - this.contents[this.contentsOffset++] = (byte) '@'; - generateAnnotation((Annotation) defaultValue, attributeOffset); - } else if (defaultValueBinding.isArrayType()) { - // array type - if (this.contentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - this.contents[this.contentsOffset++] = (byte) '['; - if (defaultValue instanceof ArrayInitializer) { - ArrayInitializer arrayInitializer = (ArrayInitializer) defaultValue; - int arrayLength = arrayInitializer.expressions != null ? arrayInitializer.expressions.length : 0; - this.contents[this.contentsOffset++] = (byte) (arrayLength >> 8); - this.contents[this.contentsOffset++] = (byte) arrayLength; - for (int i = 0; i < arrayLength; i++) { - generateElementValue(arrayInitializer.expressions[i], defaultValueBinding.leafComponentType(), attributeOffset); - } - } else { - this.contentsOffset = attributeOffset; - } - } else { - // class type - if (this.contentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - this.contents[this.contentsOffset++] = (byte) 'c'; - if (defaultValue instanceof ClassLiteralAccess) { - ClassLiteralAccess classLiteralAccess = (ClassLiteralAccess) defaultValue; - final int classInfoIndex = this.constantPool.literalIndex(classLiteralAccess.targetType.signature()); - this.contents[this.contentsOffset++] = (byte) (classInfoIndex >> 8); - this.contents[this.contentsOffset++] = (byte) classInfoIndex; - } else { - this.contentsOffset = attributeOffset; - } - } - } else { - this.contentsOffset = attributeOffset; - } - } - - private int generateEnclosingMethodAttribute() { - int localContentsOffset = this.contentsOffset; - // add enclosing method attribute (1.5 mode only) - if (localContentsOffset + 10 >= this.contents.length) { - resizeContents(10); - } - int enclosingMethodAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.EnclosingMethodName); - this.contents[localContentsOffset++] = (byte) (enclosingMethodAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) enclosingMethodAttributeNameIndex; - // the length of a signature attribute is equals to 2 - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 4; - - int enclosingTypeIndex = this.constantPool.literalIndexForType(this.referenceBinding.enclosingType().constantPoolName()); - this.contents[localContentsOffset++] = (byte) (enclosingTypeIndex >> 8); - this.contents[localContentsOffset++] = (byte) enclosingTypeIndex; - byte methodIndexByte1 = 0; - byte methodIndexByte2 = 0; - if (this.referenceBinding instanceof LocalTypeBinding) { - MethodBinding methodBinding = ((LocalTypeBinding) this.referenceBinding).enclosingMethod; - if (methodBinding != null) { - int enclosingMethodIndex = this.constantPool.literalIndexForNameAndType(methodBinding.selector, methodBinding.signature(this)); - methodIndexByte1 = (byte) (enclosingMethodIndex >> 8); - methodIndexByte2 = (byte) enclosingMethodIndex; - } - } - this.contents[localContentsOffset++] = methodIndexByte1; - this.contents[localContentsOffset++] = methodIndexByte2; - this.contentsOffset = localContentsOffset; - return 1; - } - private int generateExceptionsAttribute(ReferenceBinding[] thrownsExceptions) { - int localContentsOffset = this.contentsOffset; - int length = thrownsExceptions.length; - int exSize = 8 + length * 2; - if (exSize + this.contentsOffset >= this.contents.length) { - resizeContents(exSize); - } - int exceptionNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.ExceptionsName); - this.contents[localContentsOffset++] = (byte) (exceptionNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) exceptionNameIndex; - // The attribute length = length * 2 + 2 in case of a exception attribute - int attributeLength = length * 2 + 2; - this.contents[localContentsOffset++] = (byte) (attributeLength >> 24); - this.contents[localContentsOffset++] = (byte) (attributeLength >> 16); - this.contents[localContentsOffset++] = (byte) (attributeLength >> 8); - this.contents[localContentsOffset++] = (byte) attributeLength; - this.contents[localContentsOffset++] = (byte) (length >> 8); - this.contents[localContentsOffset++] = (byte) length; - for (int i = 0; i < length; i++) { - int exceptionIndex = this.constantPool.literalIndexForType(thrownsExceptions[i]); - this.contents[localContentsOffset++] = (byte) (exceptionIndex >> 8); - this.contents[localContentsOffset++] = (byte) exceptionIndex; - } - this.contentsOffset = localContentsOffset; - return 1; - } - private int generateHierarchyInconsistentAttribute() { - int localContentsOffset = this.contentsOffset; - // add an attribute for inconsistent hierarchy - if (localContentsOffset + 6 >= this.contents.length) { - resizeContents(6); - } - int inconsistentHierarchyNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.InconsistentHierarchy); - this.contents[localContentsOffset++] = (byte) (inconsistentHierarchyNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) inconsistentHierarchyNameIndex; - // the length of an inconsistent hierarchy attribute is equals to 0 - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contentsOffset = localContentsOffset; - return 1; - } - private int generateInnerClassAttribute(int numberOfInnerClasses, ReferenceBinding[] innerClasses) { - int localContentsOffset = this.contentsOffset; - // Generate the inner class attribute - int exSize = 8 * numberOfInnerClasses + 8; - if (exSize + localContentsOffset >= this.contents.length) { - resizeContents(exSize); - } - // Now we now the size of the attribute and the number of entries - // attribute name - int attributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.InnerClassName); - this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) attributeNameIndex; - int value = (numberOfInnerClasses << 3) + 2; - this.contents[localContentsOffset++] = (byte) (value >> 24); - this.contents[localContentsOffset++] = (byte) (value >> 16); - this.contents[localContentsOffset++] = (byte) (value >> 8); - this.contents[localContentsOffset++] = (byte) value; - this.contents[localContentsOffset++] = (byte) (numberOfInnerClasses >> 8); - this.contents[localContentsOffset++] = (byte) numberOfInnerClasses; - for (int i = 0; i < numberOfInnerClasses; i++) { - ReferenceBinding innerClass = innerClasses[i]; - int accessFlags = innerClass.getAccessFlags(); - int innerClassIndex = this.constantPool.literalIndexForType(innerClass.constantPoolName()); - // inner class index - this.contents[localContentsOffset++] = (byte) (innerClassIndex >> 8); - this.contents[localContentsOffset++] = (byte) innerClassIndex; - // outer class index: anonymous and local have no outer class index - if (innerClass.isMemberType()) { - // member or member of local - int outerClassIndex = this.constantPool.literalIndexForType(innerClass.enclosingType().constantPoolName()); - this.contents[localContentsOffset++] = (byte) (outerClassIndex >> 8); - this.contents[localContentsOffset++] = (byte) outerClassIndex; - } else { - // equals to 0 if the innerClass is not a member type - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - } - // name index - if (!innerClass.isAnonymousType()) { - int nameIndex = this.constantPool.literalIndex(innerClass.sourceName()); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) nameIndex; - } else { - // equals to 0 if the innerClass is an anonymous type - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - } - // access flag - if (innerClass.isAnonymousType()) { - ReferenceBinding superClass = innerClass.superclass(); - if (superClass == null || !(superClass.isEnum() && superClass.isSealed())) - accessFlags &= ~ClassFileConstants.AccFinal; - } else if (innerClass.isMemberType() && innerClass.isInterface()) { - accessFlags |= ClassFileConstants.AccStatic; // implicitely static - } - this.contents[localContentsOffset++] = (byte) (accessFlags >> 8); - this.contents[localContentsOffset++] = (byte) accessFlags; - } - this.contentsOffset = localContentsOffset; - return 1; - } - - private Map createInitBootStrapMethodsMap() { - Map fPtr = new HashMap<>(ClassFile.BOOTSTRAP_METHODS.length); - for (String key : ClassFile.BOOTSTRAP_METHODS) { - fPtr.put(key, 0); - } - return fPtr; - } - private int generateBootstrapMethods(List bootStrapMethodsList) { - /* See JVM spec 4.7.21 - The BootstrapMethods attribute has the following format: - BootstrapMethods_attribute { - u2 attribute_name_index; - u4 attribute_length; - u2 num_bootstrap_methods; - { u2 bootstrap_method_ref; - u2 num_bootstrap_arguments; - u2 bootstrap_arguments[num_bootstrap_arguments]; - } bootstrap_methods[num_bootstrap_methods]; - } - */ - // Record inner classes for MethodHandles$Lookup - ReferenceBinding methodHandlesLookup = this.referenceBinding.scope.getJavaLangInvokeMethodHandlesLookup(); - if (methodHandlesLookup == null) return 0; // skip bootstrap section, class path problem already reported, just avoid NPE. - recordInnerClasses(methodHandlesLookup); // Should be done, it's what javac does also - - int numberOfBootstraps = bootStrapMethodsList != null ? bootStrapMethodsList.size() : 0; - int localContentsOffset = this.contentsOffset; - // Generate the boot strap attribute - since we are only making lambdas and - // functional expressions, we know the size ahead of time - this less general - // than the full invokedynamic scope, but fine for Java 8 - - final int contentsEntries = 10; - int exSize = contentsEntries * numberOfBootstraps + 8; - if (exSize + localContentsOffset >= this.contents.length) { - resizeContents(exSize); - } - - int attributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.BootstrapMethodsName); - this.contents[localContentsOffset++] = (byte) (attributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) attributeNameIndex; - // leave space for attribute_length and remember where to insert it - int attributeLengthPosition = localContentsOffset; - localContentsOffset += 4; - - this.contents[localContentsOffset++] = (byte) (numberOfBootstraps >> 8); - this.contents[localContentsOffset++] = (byte) numberOfBootstraps; - - Map fPtr = createInitBootStrapMethodsMap(); - for (int i = 0; i < numberOfBootstraps; i++) { - Object o = this.bootstrapMethods.get(i); - if (o instanceof FunctionalExpression) { - localContentsOffset = addBootStrapLambdaEntry(localContentsOffset, (FunctionalExpression) o, fPtr); - } else if (o instanceof TypeDeclaration) { - localContentsOffset = addBootStrapRecordEntry(localContentsOffset, (TypeDeclaration) o, fPtr); - } else if (o instanceof SwitchStatement) { - SwitchStatement stmt = (SwitchStatement) o; - if (stmt.expression.resolvedType.isEnum()) { - localContentsOffset = addBootStrapEnumSwitchEntry(localContentsOffset, stmt, fPtr); - } else { - localContentsOffset = addBootStrapTypeSwitchEntry(localContentsOffset, stmt, fPtr); - } - } else if (o instanceof String) { - localContentsOffset = addBootStrapStringConcatEntry(localContentsOffset, (String) o, fPtr); - } else if (o instanceof ResolvedCase) { - localContentsOffset = addBootStrapTypeCaseConstantEntry(localContentsOffset, (ResolvedCase) o, fPtr); - } else if (o instanceof TypeBinding) { - localContentsOffset = addClassDescBootstrap(localContentsOffset, (TypeBinding) o, fPtr); - } else if (o instanceof StringTemplate template) { - localContentsOffset = addBootStrapTemplateRuntimeEntry(localContentsOffset, template, fPtr); - } - } - - int attributeLength = localContentsOffset - attributeLengthPosition - 4; - this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 24); - this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 16); - this.contents[attributeLengthPosition++] = (byte) (attributeLength >> 8); - this.contents[attributeLengthPosition++] = (byte) attributeLength; - this.contentsOffset = localContentsOffset; - return 1; - } - - private int addBootStrapLambdaEntry(int localContentsOffset, FunctionalExpression functional, Map fPtr) { - MethodBinding [] bridges = functional.getRequiredBridges(); - TypeBinding[] markerInterfaces = null; - final int contentsEntries = 10; - int indexForAltMetaFactory = fPtr.get(ClassFile.ALTMETAFACTORY_STRING); - int indexForMetaFactory = fPtr.get(ClassFile.METAFACTORY_STRING); - if ((functional instanceof LambdaExpression - && (((markerInterfaces = ((LambdaExpression) functional).getMarkerInterfaces()) != null)) - || bridges != null) || functional.isSerializable) { - // may need even more space - int extraSpace = 2; // at least 2 more than when the normal metafactory is used, for the bitflags entry - if (markerInterfaces != null) { - // 2 for the marker interface list size then 2 per marker interface index - extraSpace += (2 + 2 * markerInterfaces.length); - } - if (bridges != null) { - // 2 for bridge count then 2 per bridge method type. - extraSpace += (2 + 2 * bridges.length); - } - if (extraSpace + contentsEntries + localContentsOffset >= this.contents.length) { - resizeContents(extraSpace + contentsEntries); - } - - if (indexForAltMetaFactory == 0) { - ReferenceBinding javaLangInvokeLambdaMetafactory = this.referenceBinding.scope.getJavaLangInvokeLambdaMetafactory(); - indexForAltMetaFactory = - this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangInvokeLambdaMetafactory, - ConstantPool.ALTMETAFACTORY, ConstantPool.JAVA_LANG_INVOKE_LAMBDAMETAFACTORY_ALTMETAFACTORY_SIGNATURE, false); - fPtr.put(ClassFile.ALTMETAFACTORY_STRING, indexForAltMetaFactory); - } - this.contents[localContentsOffset++] = (byte) (indexForAltMetaFactory >> 8); - this.contents[localContentsOffset++] = (byte) indexForAltMetaFactory; - - // u2 num_bootstrap_arguments - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = (byte) (4 + (markerInterfaces==null?0:1+markerInterfaces.length) + - (bridges == null ? 0 : 1 + bridges.length)); - - int functionalDescriptorIndex = this.constantPool.literalIndexForMethodType(functional.descriptor.original().signature()); - this.contents[localContentsOffset++] = (byte) (functionalDescriptorIndex >> 8); - this.contents[localContentsOffset++] = (byte) functionalDescriptorIndex; - - int methodHandleIndex = this.constantPool.literalIndexForMethodHandle(functional.binding.original()); // Speak of " implementation" (erased) version here, adaptations described below. - this.contents[localContentsOffset++] = (byte) (methodHandleIndex >> 8); - this.contents[localContentsOffset++] = (byte) methodHandleIndex; - - char [] instantiatedSignature = functional.descriptor.signature(); - int methodTypeIndex = this.constantPool.literalIndexForMethodType(instantiatedSignature); - this.contents[localContentsOffset++] = (byte) (methodTypeIndex >> 8); - this.contents[localContentsOffset++] = (byte) methodTypeIndex; - - int bitflags = 0; - if (functional.isSerializable) { - bitflags |= ClassFileConstants.FLAG_SERIALIZABLE; - } - if (markerInterfaces!=null) { - bitflags |= ClassFileConstants.FLAG_MARKERS; - } - if (bridges != null) { - bitflags |= ClassFileConstants.FLAG_BRIDGES; - } - int indexForBitflags = this.constantPool.literalIndex(bitflags); - - this.contents[localContentsOffset++] = (byte)(indexForBitflags>>8); - this.contents[localContentsOffset++] = (byte)(indexForBitflags); - - if (markerInterfaces != null) { - int markerInterfaceCountIndex = this.constantPool.literalIndex(markerInterfaces.length); - this.contents[localContentsOffset++] = (byte)(markerInterfaceCountIndex>>8); - this.contents[localContentsOffset++] = (byte)(markerInterfaceCountIndex); - for (int m = 0, maxm = markerInterfaces.length; m < maxm; m++) { - int classTypeIndex = this.constantPool.literalIndexForType(markerInterfaces[m]); - this.contents[localContentsOffset++] = (byte)(classTypeIndex>>8); - this.contents[localContentsOffset++] = (byte)(classTypeIndex); - } - } - if (bridges != null) { - int bridgeCountIndex = this.constantPool.literalIndex(bridges.length); - this.contents[localContentsOffset++] = (byte) (bridgeCountIndex >> 8); - this.contents[localContentsOffset++] = (byte) (bridgeCountIndex); - for (int m = 0, maxm = bridges.length; m < maxm; m++) { - char [] bridgeSignature = bridges[m].signature(); - int bridgeMethodTypeIndex = this.constantPool.literalIndexForMethodType(bridgeSignature); - this.contents[localContentsOffset++] = (byte) (bridgeMethodTypeIndex >> 8); - this.contents[localContentsOffset++] = (byte) bridgeMethodTypeIndex; - } - } - } else { - if (contentsEntries + localContentsOffset >= this.contents.length) { - resizeContents(contentsEntries); - } - if (indexForMetaFactory == 0) { - ReferenceBinding javaLangInvokeLambdaMetafactory = this.referenceBinding.scope.getJavaLangInvokeLambdaMetafactory(); - indexForMetaFactory = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangInvokeLambdaMetafactory, - ConstantPool.METAFACTORY, ConstantPool.JAVA_LANG_INVOKE_LAMBDAMETAFACTORY_METAFACTORY_SIGNATURE, false); - fPtr.put(ClassFile.METAFACTORY_STRING, indexForMetaFactory); - } - this.contents[localContentsOffset++] = (byte) (indexForMetaFactory >> 8); - this.contents[localContentsOffset++] = (byte) indexForMetaFactory; - - // u2 num_bootstrap_arguments - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = (byte) 3; - - int functionalDescriptorIndex = this.constantPool.literalIndexForMethodType(functional.descriptor.original().signature()); - this.contents[localContentsOffset++] = (byte) (functionalDescriptorIndex >> 8); - this.contents[localContentsOffset++] = (byte) functionalDescriptorIndex; - - int methodHandleIndex = this.constantPool.literalIndexForMethodHandle(functional.binding instanceof PolymorphicMethodBinding ? functional.binding : functional.binding.original()); // Speak of " implementation" (erased) version here, adaptations described below. - this.contents[localContentsOffset++] = (byte) (methodHandleIndex >> 8); - this.contents[localContentsOffset++] = (byte) methodHandleIndex; - - char [] instantiatedSignature = functional.descriptor.signature(); - int methodTypeIndex = this.constantPool.literalIndexForMethodType(instantiatedSignature); - this.contents[localContentsOffset++] = (byte) (methodTypeIndex >> 8); - this.contents[localContentsOffset++] = (byte) methodTypeIndex; - } - return localContentsOffset; - } - - private int addBootStrapRecordEntry(int localContentsOffset, TypeDeclaration typeDecl, Map fPtr) { - TypeBinding type = typeDecl.binding; - assert type.isRecord(); // sanity check - final int contentsEntries = 10; - int indexForObjectMethodBootStrap = fPtr.get(ClassFile.BOOTSTRAP_STRING); - if (contentsEntries + localContentsOffset >= this.contents.length) { - resizeContents(contentsEntries); - } - if (indexForObjectMethodBootStrap == 0) { - ReferenceBinding javaLangRuntimeObjectMethods = this.referenceBinding.scope.getJavaLangRuntimeObjectMethods(); - indexForObjectMethodBootStrap = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangRuntimeObjectMethods, - ConstantPool.BOOTSTRAP, ConstantPool.JAVA_LANG_RUNTIME_OBJECTMETHOD_BOOTSTRAP_SIGNATURE, false); - fPtr.put(ClassFile.BOOTSTRAP_STRING, indexForObjectMethodBootStrap); - } - this.contents[localContentsOffset++] = (byte) (indexForObjectMethodBootStrap >> 8); - this.contents[localContentsOffset++] = (byte) indexForObjectMethodBootStrap; - - // u2 num_bootstrap_arguments - int numArgsLocation = localContentsOffset; - localContentsOffset += 2; - - char[] recordName = type.constantPoolName(); - int recordIndex = this.constantPool.literalIndexForType(recordName); - this.contents[localContentsOffset++] = (byte) (recordIndex >> 8); - this.contents[localContentsOffset++] = (byte) recordIndex; - - assert type instanceof SourceTypeBinding; - SourceTypeBinding sourceType = (SourceTypeBinding) type; - FieldBinding[] recordComponents = sourceType.getImplicitComponentFields(); - - int numArgs = 2 + recordComponents.length; - this.contents[numArgsLocation++] = (byte) (numArgs >> 8); - this.contents[numArgsLocation] = (byte) numArgs; - - String names = - Arrays.stream(recordComponents) - .map(f -> new String(f.name)) - .reduce((s1, s2) -> (s1 + ";" + s2)) //$NON-NLS-1$ - .orElse(Util.EMPTY_STRING); - int namesIndex = this.constantPool.literalIndex(names); - this.contents[localContentsOffset++] = (byte) (namesIndex >> 8); - this.contents[localContentsOffset++] = (byte) namesIndex; - - if (recordComponents.length * 2 + localContentsOffset >= this.contents.length) { - resizeContents(recordComponents.length * 2); - } - for (FieldBinding field : recordComponents) { - int methodHandleIndex = this.constantPool.literalIndexForMethodHandleFieldRef( - ClassFileConstants.MethodHandleRefKindGetField, - recordName, field.name, field.type.signature()); - - this.contents[localContentsOffset++] = (byte) (methodHandleIndex >> 8); - this.contents[localContentsOffset++] = (byte) methodHandleIndex; - } - return localContentsOffset; - } - private int addBootStrapTypeCaseConstantEntry(int localContentsOffset, ResolvedCase caseConstant, Map fPtr) { - final int contentsEntries = 10; - if (contentsEntries + localContentsOffset >= this.contents.length) { - resizeContents(contentsEntries); - } - int idx = fPtr.get(ClassFile.INVOKE_STRING); - if (idx == 0) { - ReferenceBinding constantBootstrap = this.referenceBinding.scope.getJavaLangInvokeConstantBootstraps(); - idx = this.constantPool.literalIndexForMethodHandle( - ClassFileConstants.MethodHandleRefKindInvokeStatic, - constantBootstrap, - ConstantPool.INVOKE_METHOD_METHOD_NAME, - ConstantPool.JAVA_LANG_INVOKE_CONSTANTBOOTSTRAP_SIGNATURE, - false); - fPtr.put(ClassFile.INVOKE_STRING, idx); - } - this.contents[localContentsOffset++] = (byte) (idx >> 8); - this.contents[localContentsOffset++] = (byte) idx; - - // u2 num_bootstrap_arguments - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = (byte) 3; - - idx = fPtr.get(ClassFile.ENUMDESC_OF); - if (idx == 0) { - ReferenceBinding enumDesc = this.referenceBinding.scope.getJavaLangEnumDesc(); - idx = this.constantPool.literalIndexForMethodHandle( - ClassFileConstants.MethodHandleRefKindInvokeStatic, - enumDesc, - "of".toCharArray(), //$NON-NLS-1$ - ConstantPool.JAVA_LANG_ENUMDESC_OF_SIGNATURE, - false); - fPtr.put(ClassFile.ENUMDESC_OF, idx); - } - - this.contents[localContentsOffset++] = (byte) (idx >> 8); - this.contents[localContentsOffset++] = (byte) idx; - - idx = this.constantPool.literalIndexForDynamic( - caseConstant.classDescIdx, - ConstantPool.INVOKE_METHOD_METHOD_NAME, - ConstantPool.JAVA_LANG_CONST_CLASSDESC); - this.contents[localContentsOffset++] = (byte) (idx >> 8); - this.contents[localContentsOffset++] = (byte) idx; - - idx = this.constantPool.literalIndex(caseConstant.c.stringValue()); - this.contents[localContentsOffset++] = (byte) (idx >> 8); - this.contents[localContentsOffset++] = (byte) idx; - - return localContentsOffset; - } - private int addClassDescBootstrap(int localContentsOffset, TypeBinding type, Map fPtr) { - final int contentsEntries = 10; - int idx = fPtr.get(ClassFile.INVOKE_STRING); - if (contentsEntries + localContentsOffset >= this.contents.length) { - resizeContents(contentsEntries); - } - if (idx == 0) { - ReferenceBinding constantBootstrap = this.referenceBinding.scope.getJavaLangInvokeConstantBootstraps(); - idx = this.constantPool.literalIndexForMethodHandle( - ClassFileConstants.MethodHandleRefKindInvokeStatic, - constantBootstrap, - ConstantPool.INVOKE_METHOD_METHOD_NAME, - ConstantPool.JAVA_LANG_INVOKE_CONSTANTBOOTSTRAP_SIGNATURE, - false); - fPtr.put(ClassFile.INVOKE_STRING, idx); - } - this.contents[localContentsOffset++] = (byte) (idx >> 8); - this.contents[localContentsOffset++] = (byte) idx; - - // u2 num_bootstrap_arguments - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = (byte) 2; - - idx = fPtr.get(ClassFile.CLASSDESC); - if (idx == 0) { - ReferenceBinding classDesc = this.referenceBinding.scope.getJavaLangClassDesc(); - idx = this.constantPool.literalIndexForMethodHandle( - ClassFileConstants.MethodHandleRefKindInvokeStatic, - classDesc, - "of".toCharArray(), //$NON-NLS-1$ - ConstantPool.JAVA_LANG_CLASSDESC_OF_SIGNATURE, - true); - fPtr.put(ClassFile.CLASSDESC_OF, idx); - } - - this.contents[localContentsOffset++] = (byte) (idx >> 8); - this.contents[localContentsOffset++] = (byte) idx; - - ReferenceBinding refBinding = (ReferenceBinding) type; - idx = this.constantPool.literalIndex(CharOperation.toString(refBinding.compoundName)); - this.contents[localContentsOffset++] = (byte) (idx >> 8); - this.contents[localContentsOffset++] = (byte) idx; - - return localContentsOffset; - } - private int addBootStrapTypeSwitchEntry(int localContentsOffset, SwitchStatement switchStatement, Map fPtr) { - CaseStatement.ResolvedCase[] constants = switchStatement.otherConstants; - int numArgs = constants.length; - final int contentsEntries = 10 + (numArgs * 2); - int indexFortypeSwitch = fPtr.get(ClassFile.TYPESWITCH_STRING); - if (contentsEntries + localContentsOffset >= this.contents.length) { - resizeContents(contentsEntries); - } - if (indexFortypeSwitch == 0) { - ReferenceBinding javaLangRuntimeSwitchBootstraps = this.referenceBinding.scope.getJavaLangRuntimeSwitchBootstraps(); - indexFortypeSwitch = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangRuntimeSwitchBootstraps, - ConstantPool.TYPESWITCH, ConstantPool.JAVA_LANG_RUNTIME_SWITCHBOOTSTRAPS_SWITCH_SIGNATURE, false); - fPtr.put(ClassFile.TYPESWITCH_STRING, indexFortypeSwitch); - } - this.contents[localContentsOffset++] = (byte) (indexFortypeSwitch >> 8); - this.contents[localContentsOffset++] = (byte) indexFortypeSwitch; - - // u2 num_bootstrap_arguments - int numArgsLocation = localContentsOffset; - if (switchStatement.containsNull) --numArgs; - this.contents[numArgsLocation++] = (byte) (numArgs >> 8); - this.contents[numArgsLocation] = (byte) numArgs; - localContentsOffset += 2; - for (CaseStatement.ResolvedCase c : constants) { - if (c.isPattern()) { - char[] typeName = c.t.constantPoolName(); - int typeIndex = this.constantPool.literalIndexForType(typeName); - this.contents[localContentsOffset++] = (byte) (typeIndex >> 8); - this.contents[localContentsOffset++] = (byte) typeIndex; - } else if (c.isQualifiedEnum()){ - int typeIndex = this.constantPool.literalIndexForDynamic(c.enumDescIdx, - ConstantPool.INVOKE_METHOD_METHOD_NAME, - ConstantPool.JAVA_LANG_ENUM_ENUMDESC); - this.contents[localContentsOffset++] = (byte) (typeIndex >> 8); - this.contents[localContentsOffset++] = (byte) typeIndex; - } else if ((c.e instanceof StringLiteral)||(c.c instanceof StringConstant)) { - int intValIdx = - this.constantPool.literalIndex(c.c.stringValue()); - this.contents[localContentsOffset++] = (byte) (intValIdx >> 8); - this.contents[localContentsOffset++] = (byte) intValIdx; - } else { - if (c.e instanceof NullLiteral) continue; - int intValIdx = - this.constantPool.literalIndex(c.intValue()); - this.contents[localContentsOffset++] = (byte) (intValIdx >> 8); - this.contents[localContentsOffset++] = (byte) intValIdx; - } - } - - return localContentsOffset; - } - private int addBootStrapEnumSwitchEntry(int localContentsOffset, SwitchStatement switchStatement, Map fPtr) { - final int contentsEntries = 10; - int indexForenumSwitch = fPtr.get(ClassFile.ENUMSWITCH_STRING); - if (contentsEntries + localContentsOffset >= this.contents.length) { - resizeContents(contentsEntries); - } - if (indexForenumSwitch == 0) { - ReferenceBinding javaLangRuntimeSwitchBootstraps = this.referenceBinding.scope.getJavaLangRuntimeSwitchBootstraps(); - indexForenumSwitch = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangRuntimeSwitchBootstraps, - ConstantPool.ENUMSWITCH, ConstantPool.JAVA_LANG_RUNTIME_SWITCHBOOTSTRAPS_SWITCH_SIGNATURE, false); - fPtr.put(ClassFile.ENUMSWITCH_STRING, indexForenumSwitch); - } - this.contents[localContentsOffset++] = (byte) (indexForenumSwitch >> 8); - this.contents[localContentsOffset++] = (byte) indexForenumSwitch; - - // u2 num_bootstrap_arguments - int numArgsLocation = localContentsOffset; - CaseStatement.ResolvedCase[] constants = switchStatement.otherConstants; - int numArgs = constants.length; - if (switchStatement.containsNull) --numArgs; - this.contents[numArgsLocation++] = (byte) (numArgs >> 8); - this.contents[numArgsLocation] = (byte) numArgs; - localContentsOffset += 2; - - for (CaseStatement.ResolvedCase c : constants) { - if (c.isPattern()) { - char[] typeName = switchStatement.expression.resolvedType.constantPoolName(); - int typeIndex = this.constantPool.literalIndexForType(typeName); - this.contents[localContentsOffset++] = (byte) (typeIndex >> 8); - this.contents[localContentsOffset++] = (byte) typeIndex; - } else { - if (c.e instanceof NullLiteral) continue; - String s = c.e instanceof QualifiedNameReference qnr ? // handle superfluously qualified enumerator. - new String(qnr.tokens[qnr.tokens.length-1]) : c.e.toString(); - int intValIdx = - this.constantPool.literalIndex(s); - this.contents[localContentsOffset++] = (byte) (intValIdx >> 8); - this.contents[localContentsOffset++] = (byte) intValIdx; - } - } - - return localContentsOffset; - } - private int addBootStrapStringConcatEntry(int localContentsOffset, String recipe, Map fPtr) { - final int contentsEntries = 10; - int indexForStringConcat = fPtr.get(ClassFile.CONCAT_CONSTANTS); - if (contentsEntries + localContentsOffset >= this.contents.length) { - resizeContents(contentsEntries); - } - if (indexForStringConcat == 0) { - ReferenceBinding stringConcatBootstrap = this.referenceBinding.scope.getJavaLangInvokeStringConcatFactory(); - indexForStringConcat = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, stringConcatBootstrap, - ConstantPool.ConcatWithConstants, ConstantPool.JAVA_LANG_INVOKE_STRING_CONCAT_FACTORY_SIGNATURE, false); - fPtr.put(ClassFile.CONCAT_CONSTANTS, indexForStringConcat); - } - this.contents[localContentsOffset++] = (byte) (indexForStringConcat >> 8); - this.contents[localContentsOffset++] = (byte) indexForStringConcat; - - // u2 num_bootstrap_arguments - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = (byte) 1; - - int intValIdx = - this.constantPool.literalIndex(recipe); - this.contents[localContentsOffset++] = (byte) (intValIdx >> 8); - this.contents[localContentsOffset++] = (byte) intValIdx; - - return localContentsOffset; - } - private int addBootStrapTemplateRuntimeEntry(int localContentsOffset, StringTemplate template, Map fPtr) { - final int contentsEntries = 10; - int indexForProcess = fPtr.get(NEW_STRING_TEMPLATE); - if (contentsEntries + localContentsOffset >= this.contents.length) { - resizeContents(contentsEntries); - } - if (indexForProcess == 0) { - ReferenceBinding javaLangRuntimeTemplateBootstraps = this.referenceBinding.scope.getJavaLangRuntimeTemplateRuntimeBootstraps(); - indexForProcess = this.constantPool.literalIndexForMethodHandle(ClassFileConstants.MethodHandleRefKindInvokeStatic, javaLangRuntimeTemplateBootstraps, - NEW_STRING_TEMPLATE.toCharArray(), ConstantPool.JAVA_LANG_RUNTIME_STRING_TEMPLATE_SIGNATURE, false); - fPtr.put(NEW_STRING_TEMPLATE, indexForProcess); - } - this.contents[localContentsOffset++] = (byte) (indexForProcess >> 8); - this.contents[localContentsOffset++] = (byte) indexForProcess; - - // u2 num_bootstrap_arguments - int numArgsLocation = localContentsOffset; - StringLiteral[] fragments = template.fragments(); - int numArgs = fragments.length; - this.contents[numArgsLocation++] = (byte) (numArgs >> 8); - this.contents[numArgsLocation] = (byte) numArgs; - localContentsOffset += 2; - - if ((numArgs * 2) + localContentsOffset >= this.contents.length) { - resizeContents(numArgs * 2); - } - for (StringLiteral frag : fragments) { - int intValIdx = - this.constantPool.literalIndex(frag.constant.stringValue()); - this.contents[localContentsOffset++] = (byte) (intValIdx >> 8); - this.contents[localContentsOffset++] = (byte) intValIdx; - } - return localContentsOffset; - } - private int generateLineNumberAttribute() { - int localContentsOffset = this.contentsOffset; - int attributesNumber = 0; - /* Create and add the line number attribute (used for debugging) - * Build the pairs of: - * (bytecodePC lineNumber) - * according to the table of start line indexes and the pcToSourceMap table - * contained into the codestream - */ - int[] pcToSourceMapTable; - if (((pcToSourceMapTable = this.codeStream.pcToSourceMap) != null) - && (this.codeStream.pcToSourceMapSize != 0)) { - int lineNumberNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); - if (localContentsOffset + 8 >= this.contents.length) { - resizeContents(8); - } - this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) lineNumberNameIndex; - int lineNumberTableOffset = localContentsOffset; - localContentsOffset += 6; - // leave space for attribute_length and line_number_table_length - int numberOfEntries = 0; - int length = this.codeStream.pcToSourceMapSize; - for (int i = 0; i < length;) { - // write the entry - if (localContentsOffset + 4 >= this.contents.length) { - resizeContents(4); - } - int pc = pcToSourceMapTable[i++]; - this.contents[localContentsOffset++] = (byte) (pc >> 8); - this.contents[localContentsOffset++] = (byte) pc; - int lineNumber = pcToSourceMapTable[i++]; - this.contents[localContentsOffset++] = (byte) (lineNumber >> 8); - this.contents[localContentsOffset++] = (byte) lineNumber; - numberOfEntries++; - } - // now we change the size of the line number attribute - int lineNumberAttr_length = numberOfEntries * 4 + 2; - this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 24); - this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 16); - this.contents[lineNumberTableOffset++] = (byte) (lineNumberAttr_length >> 8); - this.contents[lineNumberTableOffset++] = (byte) lineNumberAttr_length; - this.contents[lineNumberTableOffset++] = (byte) (numberOfEntries >> 8); - this.contents[lineNumberTableOffset++] = (byte) numberOfEntries; - attributesNumber = 1; - } - this.contentsOffset = localContentsOffset; - return attributesNumber; - } - // this is used for problem and synthetic methods - private int generateLineNumberAttribute(int problemLine) { - int localContentsOffset = this.contentsOffset; - if (localContentsOffset + 12 >= this.contents.length) { - resizeContents(12); - } - /* Create and add the line number attribute (used for debugging) - * Build the pairs of: - * (bytecodePC lineNumber) - * according to the table of start line indexes and the pcToSourceMap table - * contained into the codestream - */ - int lineNumberNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.LineNumberTableName); - this.contents[localContentsOffset++] = (byte) (lineNumberNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) lineNumberNameIndex; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 6; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 1; - // first entry at pc = 0 - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = (byte) (problemLine >> 8); - this.contents[localContentsOffset++] = (byte) problemLine; - // now we change the size of the line number attribute - this.contentsOffset = localContentsOffset; - return 1; - } - - private int generateLocalVariableTableAttribute(int code_length, boolean methodDeclarationIsStatic, boolean isSynthetic) { - int attributesNumber = 0; - int localContentsOffset = this.contentsOffset; - int numberOfEntries = 0; - int localVariableNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.LocalVariableTableName); - int maxOfEntries = 8 + 10 * (methodDeclarationIsStatic ? 0 : 1); - for (int i = 0; i < this.codeStream.allLocalsCounter; i++) { - LocalVariableBinding localVariableBinding = this.codeStream.locals[i]; - maxOfEntries += 10 * localVariableBinding.initializationCount; - } - // reserve enough space - if (localContentsOffset + maxOfEntries >= this.contents.length) { - resizeContents(maxOfEntries); - } - this.contents[localContentsOffset++] = (byte) (localVariableNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) localVariableNameIndex; - int localVariableTableOffset = localContentsOffset; - // leave space for attribute_length and local_variable_table_length - localContentsOffset += 6; - int nameIndex; - int descriptorIndex; - SourceTypeBinding declaringClassBinding = null; - if (!methodDeclarationIsStatic && !isSynthetic) { - numberOfEntries++; - this.contents[localContentsOffset++] = 0; // the startPC for this is always 0 - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = (byte) (code_length >> 8); - this.contents[localContentsOffset++] = (byte) code_length; - nameIndex = this.constantPool.literalIndex(ConstantPool.This); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) nameIndex; - declaringClassBinding = (SourceTypeBinding) - (this.codeStream.methodDeclaration != null ? this.codeStream.methodDeclaration.binding.declaringClass : this.codeStream.lambdaExpression.binding.declaringClass); - descriptorIndex = - this.constantPool.literalIndex( - declaringClassBinding.signature()); - this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); - this.contents[localContentsOffset++] = (byte) descriptorIndex; - this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0 - this.contents[localContentsOffset++] = 0; - } - // used to remember the local variable with a generic type - int genericLocalVariablesCounter = 0; - LocalVariableBinding[] genericLocalVariables = null; - int numberOfGenericEntries = 0; - - for (int i = 0, max = this.codeStream.allLocalsCounter; i < max; i++) { - LocalVariableBinding localVariable = this.codeStream.locals[i]; - int initializationCount = localVariable.initializationCount; - if (initializationCount == 0) continue; - if (localVariable.declaration == null) continue; - final TypeBinding localVariableTypeBinding = localVariable.type; - boolean isParameterizedType = localVariableTypeBinding.isParameterizedType() || localVariableTypeBinding.isTypeVariable(); - if (isParameterizedType) { - if (genericLocalVariables == null) { - // we cannot have more than max locals - genericLocalVariables = new LocalVariableBinding[max]; - } - genericLocalVariables[genericLocalVariablesCounter++] = localVariable; - } - for (int j = 0; j < initializationCount; j++) { - int startPC = localVariable.initializationPCs[j << 1]; - int endPC = localVariable.initializationPCs[(j << 1) + 1]; - if (startPC != endPC) { // only entries for non zero length - if (endPC == -1) { - localVariable.declaringScope.problemReporter().abortDueToInternalError( - Messages.bind(Messages.abort_invalidAttribute, new String(localVariable.name)), - (ASTNode) localVariable.declaringScope.methodScope().referenceContext); - } - if (isParameterizedType) { - numberOfGenericEntries++; - } - // now we can safely add the local entry - numberOfEntries++; - this.contents[localContentsOffset++] = (byte) (startPC >> 8); - this.contents[localContentsOffset++] = (byte) startPC; - int length = endPC - startPC; - this.contents[localContentsOffset++] = (byte) (length >> 8); - this.contents[localContentsOffset++] = (byte) length; - nameIndex = this.constantPool.literalIndex(localVariable.name); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) nameIndex; - descriptorIndex = this.constantPool.literalIndex(localVariableTypeBinding.signature()); - this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); - this.contents[localContentsOffset++] = (byte) descriptorIndex; - int resolvedPosition = localVariable.resolvedPosition; - this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); - this.contents[localContentsOffset++] = (byte) resolvedPosition; - } - } - } - int value = numberOfEntries * 10 + 2; - this.contents[localVariableTableOffset++] = (byte) (value >> 24); - this.contents[localVariableTableOffset++] = (byte) (value >> 16); - this.contents[localVariableTableOffset++] = (byte) (value >> 8); - this.contents[localVariableTableOffset++] = (byte) value; - this.contents[localVariableTableOffset++] = (byte) (numberOfEntries >> 8); - this.contents[localVariableTableOffset] = (byte) numberOfEntries; - attributesNumber++; - - final boolean currentInstanceIsGeneric = - !methodDeclarationIsStatic - && declaringClassBinding != null - && declaringClassBinding.typeVariables != Binding.NO_TYPE_VARIABLES; - if (genericLocalVariablesCounter != 0 || currentInstanceIsGeneric) { - // add the local variable type table attribute - numberOfGenericEntries += (currentInstanceIsGeneric ? 1 : 0); - maxOfEntries = 8 + numberOfGenericEntries * 10; - // reserve enough space - if (localContentsOffset + maxOfEntries >= this.contents.length) { - resizeContents(maxOfEntries); - } - int localVariableTypeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.LocalVariableTypeTableName); - this.contents[localContentsOffset++] = (byte) (localVariableTypeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) localVariableTypeNameIndex; - value = numberOfGenericEntries * 10 + 2; - this.contents[localContentsOffset++] = (byte) (value >> 24); - this.contents[localContentsOffset++] = (byte) (value >> 16); - this.contents[localContentsOffset++] = (byte) (value >> 8); - this.contents[localContentsOffset++] = (byte) value; - this.contents[localContentsOffset++] = (byte) (numberOfGenericEntries >> 8); - this.contents[localContentsOffset++] = (byte) numberOfGenericEntries; - if (currentInstanceIsGeneric) { - this.contents[localContentsOffset++] = 0; // the startPC for this is always 0 - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = (byte) (code_length >> 8); - this.contents[localContentsOffset++] = (byte) code_length; - nameIndex = this.constantPool.literalIndex(ConstantPool.This); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) nameIndex; - descriptorIndex = this.constantPool.literalIndex(declaringClassBinding.genericTypeSignature()); - this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); - this.contents[localContentsOffset++] = (byte) descriptorIndex; - this.contents[localContentsOffset++] = 0;// the resolved position for this is always 0 - this.contents[localContentsOffset++] = 0; - } - - for (int i = 0; i < genericLocalVariablesCounter; i++) { - LocalVariableBinding localVariable = genericLocalVariables[i]; - for (int j = 0; j < localVariable.initializationCount; j++) { - int startPC = localVariable.initializationPCs[j << 1]; - int endPC = localVariable.initializationPCs[(j << 1) + 1]; - if (startPC != endPC) { - // only entries for non zero length - // now we can safely add the local entry - this.contents[localContentsOffset++] = (byte) (startPC >> 8); - this.contents[localContentsOffset++] = (byte) startPC; - int length = endPC - startPC; - this.contents[localContentsOffset++] = (byte) (length >> 8); - this.contents[localContentsOffset++] = (byte) length; - nameIndex = this.constantPool.literalIndex(localVariable.name); - this.contents[localContentsOffset++] = (byte) (nameIndex >> 8); - this.contents[localContentsOffset++] = (byte) nameIndex; - descriptorIndex = this.constantPool.literalIndex(localVariable.type.genericTypeSignature()); - this.contents[localContentsOffset++] = (byte) (descriptorIndex >> 8); - this.contents[localContentsOffset++] = (byte) descriptorIndex; - int resolvedPosition = localVariable.resolvedPosition; - this.contents[localContentsOffset++] = (byte) (resolvedPosition >> 8); - this.contents[localContentsOffset++] = (byte) resolvedPosition; - } - } - } - attributesNumber++; - } - this.contentsOffset = localContentsOffset; - return attributesNumber; - } - /** - * INTERNAL USE-ONLY - * That method generates the attributes of a code attribute. - * They could be: - * - an exception attribute for each try/catch found inside the method - * - a deprecated attribute - * - a synthetic attribute for synthetic access methods - * - * It returns the number of attributes created for the code attribute. - * - * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding - * @return int - */ - public int generateMethodInfoAttributes(MethodBinding methodBinding) { - // leave two bytes for the attribute_number - this.contentsOffset += 2; - if (this.contentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - // now we can handle all the attribute for that method info: - // it could be: - // - a CodeAttribute - // - a ExceptionAttribute - // - a DeprecatedAttribute - // - a SyntheticAttribute - - // Exception attribute - ReferenceBinding[] thrownsExceptions; - int attributesNumber = 0; - if ((thrownsExceptions = methodBinding.thrownExceptions) != Binding.NO_EXCEPTIONS) { - // The method has a throw clause. So we need to add an exception attribute - // check that there is enough space to write all the bytes for the exception attribute - attributesNumber += generateExceptionsAttribute(thrownsExceptions); - } - if (methodBinding.isDeprecated()) { - // Deprecated attribute - attributesNumber += generateDeprecatedAttribute(); - } - if (this.targetJDK < ClassFileConstants.JDK1_5) { - if (methodBinding.isSynthetic()) { - attributesNumber += generateSyntheticAttribute(); - } - if (methodBinding.isVarargs()) { - attributesNumber += generateVarargsAttribute(); - } - } - // add signature attribute - char[] genericSignature = methodBinding.genericSignature(); - if (genericSignature != null) { - attributesNumber += generateSignatureAttribute(genericSignature); - } - if (this.targetJDK >= ClassFileConstants.JDK1_4) { - AbstractMethodDeclaration methodDeclaration = methodBinding.sourceMethod(); - if (methodBinding instanceof SyntheticMethodBinding) { - SyntheticMethodBinding syntheticMethod = (SyntheticMethodBinding) methodBinding; - if (syntheticMethod.purpose == SyntheticMethodBinding.SuperMethodAccess && CharOperation.equals(syntheticMethod.selector, syntheticMethod.targetMethod.selector)) - methodDeclaration = ((SyntheticMethodBinding)methodBinding).targetMethod.sourceMethod(); - if (syntheticMethod.recordComponentBinding != null) { - assert methodDeclaration == null; - long rcMask = TagBits.AnnotationForMethod | TagBits.AnnotationForTypeUse; - // record component (field) accessor method - ReferenceBinding declaringClass = methodBinding.declaringClass; - RecordComponent comp = getRecordComponent(declaringClass, methodBinding.selector); - if (comp != null) { - Annotation[] annotations = ASTNode.getRelevantAnnotations(comp.annotations, rcMask, null); - if (annotations != null) { - assert !methodBinding.isConstructor(); - attributesNumber += generateRuntimeAnnotations(annotations, TagBits.AnnotationForMethod); - } - if ((this.produceAttributes & ClassFileConstants.ATTR_TYPE_ANNOTATION) != 0) { - List allTypeAnnotationContexts = new ArrayList<>(); - if (annotations != null && (comp.bits & ASTNode.HasTypeAnnotations) != 0) { - comp.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_RETURN, allTypeAnnotationContexts); - } - TypeReference compType = comp.type; - if (compType != null && ((compType.bits & ASTNode.HasTypeAnnotations) != 0)) { - compType.getAllAnnotationContexts(AnnotationTargetTypeConstants.METHOD_RETURN, allTypeAnnotationContexts); - } - int size = allTypeAnnotationContexts.size(); - attributesNumber = completeRuntimeTypeAnnotations(attributesNumber, - null, - node -> size > 0, - () -> allTypeAnnotationContexts); - } - } - } - } - if (methodDeclaration != null) { - Annotation[] annotations = methodDeclaration.annotations; - if (annotations != null) { - attributesNumber += generateRuntimeAnnotations(annotations, methodBinding.isConstructor() ? TagBits.AnnotationForConstructor : TagBits.AnnotationForMethod); - } - if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) { - Argument[] arguments = methodDeclaration.arguments; - if (arguments != null) { - propagateRecordComponentArguments(methodDeclaration); - attributesNumber += generateRuntimeAnnotationsForParameters(arguments); - } - } - } else { - LambdaExpression lambda = methodBinding.sourceLambda(); - if (lambda != null) { - if ((methodBinding.tagBits & TagBits.HasParameterAnnotations) != 0) { - Argument[] arguments = lambda.arguments(); - if (arguments != null) { - int parameterCount = methodBinding.parameters.length; - int argumentCount = arguments.length; - if (parameterCount > argumentCount) { // synthetics prefixed - int redShift = parameterCount - argumentCount; - System.arraycopy(arguments, 0, arguments = new Argument[parameterCount], redShift, argumentCount); - for (int i = 0; i < redShift; i++) - arguments[i] = new Argument(CharOperation.NO_CHAR, 0, null, 0); - } - attributesNumber += generateRuntimeAnnotationsForParameters(arguments); - } - } - } - } - } - if ((methodBinding.tagBits & TagBits.HasMissingType) != 0) { - this.missingTypes = methodBinding.collectMissingTypes(this.missingTypes); - } - return attributesNumber; - } - private int completeRuntimeTypeAnnotations(int attributesNumber, - ASTNode node, - Predicate condition, - Supplier> supplier) { - int invisibleTypeAnnotationsCounter = 0; - int visibleTypeAnnotationsCounter = 0; - if (condition.test(node)) { - List allTypeAnnotationContexts = supplier.get(); - if (allTypeAnnotationContexts.size() > 0) { - AnnotationContext[] allTypeAnnotationContextsArray = new AnnotationContext[allTypeAnnotationContexts.size()]; - allTypeAnnotationContexts.toArray(allTypeAnnotationContextsArray); - for (int j = 0, max2 = allTypeAnnotationContextsArray.length; j < max2; j++) { - AnnotationContext annotationContext = allTypeAnnotationContextsArray[j]; - if ((annotationContext.visibility & AnnotationContext.INVISIBLE) != 0) { - invisibleTypeAnnotationsCounter++; - } else { - visibleTypeAnnotationsCounter++; - } - } - attributesNumber += generateRuntimeTypeAnnotations( - allTypeAnnotationContextsArray, - visibleTypeAnnotationsCounter, - invisibleTypeAnnotationsCounter); - } - } - return attributesNumber; - } - private void propagateRecordComponentArguments(AbstractMethodDeclaration methodDeclaration) { - if ((methodDeclaration.bits & (ASTNode.IsCanonicalConstructor | ASTNode.IsImplicit)) == 0) - return; - ReferenceBinding declaringClass = methodDeclaration.binding.declaringClass; - if (declaringClass instanceof SourceTypeBinding) { - assert declaringClass.isRecord(); - RecordComponentBinding[] rcbs = ((SourceTypeBinding) declaringClass).components(); - Argument[] arguments = methodDeclaration.arguments; - for (int i = 0, length = rcbs.length; i < length; i++) { - RecordComponentBinding rcb = rcbs[i]; - RecordComponent recordComponent = rcb.sourceRecordComponent(); - if ((recordComponent.bits & ASTNode.HasTypeAnnotations) != 0) { - methodDeclaration.bits |= ASTNode.HasTypeAnnotations; - arguments[i].bits |= ASTNode.HasTypeAnnotations; - } - long rcMask = TagBits.AnnotationForParameter | TagBits.AnnotationForTypeUse; - arguments[i].annotations = ASTNode.getRelevantAnnotations(recordComponent.annotations, rcMask, null); - } - } - } - - public int generateMethodInfoAttributes(MethodBinding methodBinding, AnnotationMethodDeclaration declaration) { - int attributesNumber = generateMethodInfoAttributes(methodBinding); - int attributeOffset = this.contentsOffset; - if ((declaration.modifiers & ClassFileConstants.AccAnnotationDefault) != 0) { - // add an annotation default attribute - attributesNumber += generateAnnotationDefaultAttribute(declaration, attributeOffset); - } - return attributesNumber; - } - /** - * INTERNAL USE-ONLY - * That method generates the header of a method info: - * The header consists in: - * - the access flags - * - the name index of the method name inside the constant pool - * - the descriptor index of the signature of the method inside the constant pool. - * - * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding - */ - public void generateMethodInfoHeader(MethodBinding methodBinding) { - generateMethodInfoHeader(methodBinding, methodBinding.modifiers); - } - - /** - * INTERNAL USE-ONLY - * That method generates the header of a method info: - * The header consists in: - * - the access flags - * - the name index of the method name inside the constant pool - * - the descriptor index of the signature of the method inside the constant pool. - * - * @param methodBinding org.eclipse.jdt.internal.compiler.lookup.MethodBinding - * @param accessFlags the access flags - */ - public void generateMethodInfoHeader(MethodBinding methodBinding, int accessFlags) { - // check that there is enough space to write all the bytes for the method info corresponding - // to the @methodBinding - this.methodCount++; // add one more method - if (this.contentsOffset + 10 >= this.contents.length) { - resizeContents(10); - } - if (this.targetJDK < ClassFileConstants.JDK1_5) { - // pre 1.5, synthetic is an attribute, not a modifier - // pre 1.5, varargs is an attribute, not a modifier (-target jsr14 mode) - accessFlags &= ~(ClassFileConstants.AccSynthetic | ClassFileConstants.AccVarargs); - } - if ((methodBinding.tagBits & TagBits.ClearPrivateModifier) != 0) { - accessFlags &= ~ClassFileConstants.AccPrivate; - } - if (this.targetJDK >= ClassFileConstants.JDK17) { - accessFlags &= ~(ClassFileConstants.AccStrictfp); - } - this.contents[this.contentsOffset++] = (byte) (accessFlags >> 8); - this.contents[this.contentsOffset++] = (byte) accessFlags; - int nameIndex = this.constantPool.literalIndex(methodBinding.selector); - this.contents[this.contentsOffset++] = (byte) (nameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) nameIndex; - int descriptorIndex = this.constantPool.literalIndex(methodBinding.signature(this)); - this.contents[this.contentsOffset++] = (byte) (descriptorIndex >> 8); - this.contents[this.contentsOffset++] = (byte) descriptorIndex; - } - - public void addSyntheticDeserializeLambda(SyntheticMethodBinding methodBinding, SyntheticMethodBinding[] syntheticMethodBindings ) { - generateMethodInfoHeader(methodBinding); - int methodAttributeOffset = this.contentsOffset; - // this will add exception attribute, synthetic attribute, deprecated attribute,... - int attributeNumber = generateMethodInfoAttributes(methodBinding); - // Code attribute - int codeAttributeOffset = this.contentsOffset; - attributeNumber++; // add code attribute - generateCodeAttributeHeader(); - this.codeStream.init(this); - this.codeStream.generateSyntheticBodyForDeserializeLambda(methodBinding, syntheticMethodBindings); - int code_length = this.codeStream.position; - if (code_length > 65535) { - this.referenceBinding.scope.problemReporter().bytecodeExceeds64KLimit( - methodBinding, this.referenceBinding.sourceStart(), this.referenceBinding.sourceEnd()); - } - completeCodeAttributeForSyntheticMethod( - methodBinding, - codeAttributeOffset, - ((SourceTypeBinding) methodBinding.declaringClass) - .scope - .referenceCompilationUnit() - .compilationResult - .getLineSeparatorPositions()); - this.contents[methodAttributeOffset++] = (byte) (attributeNumber >> 8); - this.contents[methodAttributeOffset] = (byte) attributeNumber; - } - - /** - * INTERNAL USE-ONLY - * That method generates the method info header of a clinit: - * The header consists in: - * - the access flags (always default access + static) - * - the name index of the method name (always {@code }) inside the constant pool - * - the descriptor index of the signature (always ()V) of the method inside the constant pool. - */ - public void generateMethodInfoHeaderForClinit() { - // check that there is enough space to write all the bytes for the method info corresponding - // to the @methodBinding - this.methodCount++; // add one more method - if (this.contentsOffset + 10 >= this.contents.length) { - resizeContents(10); - } - this.contents[this.contentsOffset++] = (byte) ((ClassFileConstants.AccDefault | ClassFileConstants.AccStatic) >> 8); - this.contents[this.contentsOffset++] = (byte) (ClassFileConstants.AccDefault | ClassFileConstants.AccStatic); - int nameIndex = this.constantPool.literalIndex(ConstantPool.Clinit); - this.contents[this.contentsOffset++] = (byte) (nameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) nameIndex; - int descriptorIndex = - this.constantPool.literalIndex(ConstantPool.ClinitSignature); - this.contents[this.contentsOffset++] = (byte) (descriptorIndex >> 8); - this.contents[this.contentsOffset++] = (byte) descriptorIndex; - // We know that we won't get more than 1 attribute: the code attribute - this.contents[this.contentsOffset++] = 0; - this.contents[this.contentsOffset++] = 1; - } - - /** - * INTERNAL USE-ONLY - * Generate the byte for problem method infos that correspond to missing abstract methods. - * http://dev.eclipse.org/bugs/show_bug.cgi?id=3179 - * - * @param methodDeclarations Array of all missing abstract methods - */ - public void generateMissingAbstractMethods(MethodDeclaration[] methodDeclarations, CompilationResult compilationResult) { - if (methodDeclarations != null) { - TypeDeclaration currentDeclaration = this.referenceBinding.scope.referenceContext; - int typeDeclarationSourceStart = currentDeclaration.sourceStart(); - int typeDeclarationSourceEnd = currentDeclaration.sourceEnd(); - for (int i = 0, max = methodDeclarations.length; i < max; i++) { - MethodDeclaration methodDeclaration = methodDeclarations[i]; - MethodBinding methodBinding = methodDeclaration.binding; - String readableName = new String(methodBinding.readableName()); - CategorizedProblem[] problems = compilationResult.problems; - int problemsCount = compilationResult.problemCount; - for (int j = 0; j < problemsCount; j++) { - CategorizedProblem problem = problems[j]; - if (problem != null - && problem.getID() == IProblem.AbstractMethodMustBeImplemented - && problem.getMessage().indexOf(readableName) != -1 - && problem.getSourceStart() >= typeDeclarationSourceStart - && problem.getSourceEnd() <= typeDeclarationSourceEnd) { - // we found a match - addMissingAbstractProblemMethod(methodDeclaration, methodBinding, problem, compilationResult); - } - } - } - } - } - - private void generateMissingTypesAttribute() { - int initialSize = this.missingTypes.size(); - int[] missingTypesIndexes = new int[initialSize]; - int numberOfMissingTypes = 0; - if (initialSize > 1) { - Collections.sort(this.missingTypes, new Comparator() { - @Override - public int compare(TypeBinding o1, TypeBinding o2) { - return CharOperation.compareTo(o1.constantPoolName(), o2.constantPoolName()); - } - }); - } - int previousIndex = 0; - next: for (int i = 0; i < initialSize; i++) { - int missingTypeIndex = this.constantPool.literalIndexForType(this.missingTypes.get(i)); - if (previousIndex == missingTypeIndex) { - continue next; - } - previousIndex = missingTypeIndex; - missingTypesIndexes[numberOfMissingTypes++] = missingTypeIndex; - } - // we don't need to resize as we interate from 0 to numberOfMissingTypes when recording the indexes in the .class file - int attributeLength = numberOfMissingTypes * 2 + 2; - if (this.contentsOffset + attributeLength + 6 >= this.contents.length) { - resizeContents(attributeLength + 6); - } - int missingTypesNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.MissingTypesName); - this.contents[this.contentsOffset++] = (byte) (missingTypesNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) missingTypesNameIndex; - - // generate attribute length - this.contents[this.contentsOffset++] = (byte) (attributeLength >> 24); - this.contents[this.contentsOffset++] = (byte) (attributeLength >> 16); - this.contents[this.contentsOffset++] = (byte) (attributeLength >> 8); - this.contents[this.contentsOffset++] = (byte) attributeLength; - - // generate number of missing types - this.contents[this.contentsOffset++] = (byte) (numberOfMissingTypes >> 8); - this.contents[this.contentsOffset++] = (byte) numberOfMissingTypes; - // generate entry for each missing type - for (int i = 0; i < numberOfMissingTypes; i++) { - int missingTypeIndex = missingTypesIndexes[i]; - this.contents[this.contentsOffset++] = (byte) (missingTypeIndex >> 8); - this.contents[this.contentsOffset++] = (byte) missingTypeIndex; - } - } - - private boolean jdk16packageInfoAnnotation(final long annotationMask, final long targetMask) { - if (this.targetJDK <= ClassFileConstants.JDK1_6 && - targetMask == TagBits.AnnotationForPackage && annotationMask != 0 && - (annotationMask & TagBits.AnnotationForPackage) == 0) { - return true; - } - return false; - } - /** - * @param targetMask allowed targets - * @return the number of attributes created while dumping the annotations in the .class file - */ - private int generateRuntimeAnnotations(final Annotation[] annotations, final long targetMask) { - int attributesNumber = 0; - final int length = annotations.length; - int visibleAnnotationsCounter = 0; - int invisibleAnnotationsCounter = 0; - for (int i = 0; i < length; i++) { - Annotation annotation; - if ((annotation = annotations[i].getPersistibleAnnotation()) == null) continue; // already packaged into container. - long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; - if (annotationMask != 0 && (annotationMask & targetMask) == 0) { - if (!jdk16packageInfoAnnotation(annotationMask, targetMask)) continue; - } - if (annotation.isRuntimeInvisible()) { - invisibleAnnotationsCounter++; - } else if (annotation.isRuntimeVisible()) { - visibleAnnotationsCounter++; - } - } - - int annotationAttributeOffset = this.contentsOffset; - if (invisibleAnnotationsCounter != 0) { - if (this.contentsOffset + 10 >= this.contents.length) { - resizeContents(10); - } - int runtimeInvisibleAnnotationsAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleAnnotationsName); - this.contents[this.contentsOffset++] = (byte) (runtimeInvisibleAnnotationsAttributeNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) runtimeInvisibleAnnotationsAttributeNameIndex; - int attributeLengthOffset = this.contentsOffset; - this.contentsOffset += 4; // leave space for the attribute length - - int annotationsLengthOffset = this.contentsOffset; - this.contentsOffset += 2; // leave space for the annotations length - - int counter = 0; - loop: for (int i = 0; i < length; i++) { - if (invisibleAnnotationsCounter == 0) break loop; - Annotation annotation; - if ((annotation = annotations[i].getPersistibleAnnotation()) == null) continue; // already packaged into container. - long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; - if (annotationMask != 0 && (annotationMask & targetMask) == 0) { - if (!jdk16packageInfoAnnotation(annotationMask, targetMask)) continue; - } - if (annotation.isRuntimeInvisible()) { - int currentAnnotationOffset = this.contentsOffset; - generateAnnotation(annotation, currentAnnotationOffset); - invisibleAnnotationsCounter--; - if (this.contentsOffset != currentAnnotationOffset) { - counter++; - } - } - } - if (counter != 0) { - this.contents[annotationsLengthOffset++] = (byte) (counter >> 8); - this.contents[annotationsLengthOffset++] = (byte) counter; - - int attributeLength = this.contentsOffset - attributeLengthOffset - 4; - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); - this.contents[attributeLengthOffset++] = (byte) attributeLength; - attributesNumber++; - } else { - this.contentsOffset = annotationAttributeOffset; - } - } - - annotationAttributeOffset = this.contentsOffset; - if (visibleAnnotationsCounter != 0) { - if (this.contentsOffset + 10 >= this.contents.length) { - resizeContents(10); - } - int runtimeVisibleAnnotationsAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleAnnotationsName); - this.contents[this.contentsOffset++] = (byte) (runtimeVisibleAnnotationsAttributeNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) runtimeVisibleAnnotationsAttributeNameIndex; - int attributeLengthOffset = this.contentsOffset; - this.contentsOffset += 4; // leave space for the attribute length - - int annotationsLengthOffset = this.contentsOffset; - this.contentsOffset += 2; // leave space for the annotations length - - int counter = 0; - loop: for (int i = 0; i < length; i++) { - if (visibleAnnotationsCounter == 0) break loop; - Annotation annotation; - if ((annotation = annotations[i].getPersistibleAnnotation()) == null) continue; // already packaged into container. - long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; - if (annotationMask != 0 && (annotationMask & targetMask) == 0) { - if (!jdk16packageInfoAnnotation(annotationMask, targetMask)) continue; - } - if (annotation.isRuntimeVisible()) { - visibleAnnotationsCounter--; - int currentAnnotationOffset = this.contentsOffset; - generateAnnotation(annotation, currentAnnotationOffset); - if (this.contentsOffset != currentAnnotationOffset) { - counter++; - } - } - } - if (counter != 0) { - this.contents[annotationsLengthOffset++] = (byte) (counter >> 8); - this.contents[annotationsLengthOffset++] = (byte) counter; - - int attributeLength = this.contentsOffset - attributeLengthOffset - 4; - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); - this.contents[attributeLengthOffset++] = (byte) attributeLength; - attributesNumber++; - } else { - this.contentsOffset = annotationAttributeOffset; - } - } - return attributesNumber; - } - - private int generateRuntimeAnnotationsForParameters(Argument[] arguments) { - final int argumentsLength = arguments.length; - final int VISIBLE_INDEX = 0; - final int INVISIBLE_INDEX = 1; - int invisibleParametersAnnotationsCounter = 0; - int visibleParametersAnnotationsCounter = 0; - int[][] annotationsCounters = new int[argumentsLength][2]; - for (int i = 0; i < argumentsLength; i++) { - Argument argument = arguments[i]; - Annotation[] annotations = argument.annotations; - if (annotations != null) { - for (int j = 0, max2 = annotations.length; j < max2; j++) { - Annotation annotation; - if ((annotation = annotations[j].getPersistibleAnnotation()) == null) continue; // already packaged into container. - long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; - if (annotationMask != 0 && (annotationMask & TagBits.AnnotationForParameter) == 0) continue; - if (annotation.isRuntimeInvisible()) { - annotationsCounters[i][INVISIBLE_INDEX]++; - invisibleParametersAnnotationsCounter++; - } else if (annotation.isRuntimeVisible()) { - annotationsCounters[i][VISIBLE_INDEX]++; - visibleParametersAnnotationsCounter++; - } - } - } - } - int attributesNumber = 0; - int annotationAttributeOffset = this.contentsOffset; - if (invisibleParametersAnnotationsCounter != 0) { - int globalCounter = 0; - if (this.contentsOffset + 7 >= this.contents.length) { - resizeContents(7); - } - int attributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleParameterAnnotationsName); - this.contents[this.contentsOffset++] = (byte) (attributeNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) attributeNameIndex; - int attributeLengthOffset = this.contentsOffset; - this.contentsOffset += 4; // leave space for the attribute length - - this.contents[this.contentsOffset++] = (byte) argumentsLength; - for (int i = 0; i < argumentsLength; i++) { - if (this.contentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - if (invisibleParametersAnnotationsCounter == 0) { - this.contents[this.contentsOffset++] = (byte) 0; - this.contents[this.contentsOffset++] = (byte) 0; - } else { - final int numberOfInvisibleAnnotations = annotationsCounters[i][INVISIBLE_INDEX]; - int invisibleAnnotationsOffset = this.contentsOffset; - // leave space for number of annotations - this.contentsOffset += 2; - int counter = 0; - if (numberOfInvisibleAnnotations != 0) { - Argument argument = arguments[i]; - Annotation[] annotations = argument.annotations; - for (int j = 0, max = annotations.length; j < max; j++) { - Annotation annotation; - if ((annotation = annotations[j].getPersistibleAnnotation()) == null) continue; // already packaged into container. - long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; - if (annotationMask != 0 && (annotationMask & TagBits.AnnotationForParameter) == 0) continue; - if (annotation.isRuntimeInvisible()) { - int currentAnnotationOffset = this.contentsOffset; - generateAnnotation(annotation, currentAnnotationOffset); - if (this.contentsOffset != currentAnnotationOffset) { - counter++; - globalCounter++; - } - invisibleParametersAnnotationsCounter--; - } - } - } - this.contents[invisibleAnnotationsOffset++] = (byte) (counter >> 8); - this.contents[invisibleAnnotationsOffset] = (byte) counter; - } - } - if (globalCounter != 0) { - int attributeLength = this.contentsOffset - attributeLengthOffset - 4; - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); - this.contents[attributeLengthOffset++] = (byte) attributeLength; - attributesNumber++; - } else { - // if globalCounter is 0, this means that the code generation for all visible annotations failed - this.contentsOffset = annotationAttributeOffset; - } - } - if (visibleParametersAnnotationsCounter != 0) { - int globalCounter = 0; - if (this.contentsOffset + 7 >= this.contents.length) { - resizeContents(7); - } - int attributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleParameterAnnotationsName); - this.contents[this.contentsOffset++] = (byte) (attributeNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) attributeNameIndex; - int attributeLengthOffset = this.contentsOffset; - this.contentsOffset += 4; // leave space for the attribute length - - this.contents[this.contentsOffset++] = (byte) argumentsLength; - for (int i = 0; i < argumentsLength; i++) { - if (this.contentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - if (visibleParametersAnnotationsCounter == 0) { - this.contents[this.contentsOffset++] = (byte) 0; - this.contents[this.contentsOffset++] = (byte) 0; - } else { - final int numberOfVisibleAnnotations = annotationsCounters[i][VISIBLE_INDEX]; - int visibleAnnotationsOffset = this.contentsOffset; - // leave space for number of annotations - this.contentsOffset += 2; - int counter = 0; - if (numberOfVisibleAnnotations != 0) { - Argument argument = arguments[i]; - Annotation[] annotations = argument.annotations; - for (int j = 0, max = annotations.length; j < max; j++) { - Annotation annotation; - if ((annotation = annotations[j].getPersistibleAnnotation()) == null) continue; // already packaged into container. - long annotationMask = annotation.resolvedType != null ? annotation.resolvedType.getAnnotationTagBits() & TagBits.AnnotationTargetMASK : 0; - if (annotationMask != 0 && (annotationMask & TagBits.AnnotationForParameter) == 0) continue; - if (annotation.isRuntimeVisible()) { - int currentAnnotationOffset = this.contentsOffset; - generateAnnotation(annotation, currentAnnotationOffset); - if (this.contentsOffset != currentAnnotationOffset) { - counter++; - globalCounter++; - } - visibleParametersAnnotationsCounter--; - } - } - } - this.contents[visibleAnnotationsOffset++] = (byte) (counter >> 8); - this.contents[visibleAnnotationsOffset] = (byte) counter; - } - } - if (globalCounter != 0) { - int attributeLength = this.contentsOffset - attributeLengthOffset - 4; - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); - this.contents[attributeLengthOffset++] = (byte) attributeLength; - attributesNumber++; - } else { - // if globalCounter is 0, this means that the code generation for all visible annotations failed - this.contentsOffset = annotationAttributeOffset; - } - } - return attributesNumber; - } - - /** - * @param annotationContexts the given annotation contexts - * @param visibleTypeAnnotationsNumber the given number of visible type annotations - * @param invisibleTypeAnnotationsNumber the given number of invisible type annotations - * @return the number of attributes created while dumping the annotations in the .class file - */ - private int generateRuntimeTypeAnnotations( - final AnnotationContext[] annotationContexts, - int visibleTypeAnnotationsNumber, - int invisibleTypeAnnotationsNumber) { - int attributesNumber = 0; - final int length = annotationContexts.length; - - int visibleTypeAnnotationsCounter = visibleTypeAnnotationsNumber; - int invisibleTypeAnnotationsCounter = invisibleTypeAnnotationsNumber; - int annotationAttributeOffset = this.contentsOffset; - if (invisibleTypeAnnotationsCounter != 0) { - if (this.contentsOffset + 10 >= this.contents.length) { - resizeContents(10); - } - int runtimeInvisibleAnnotationsAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.RuntimeInvisibleTypeAnnotationsName); - this.contents[this.contentsOffset++] = (byte) (runtimeInvisibleAnnotationsAttributeNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) runtimeInvisibleAnnotationsAttributeNameIndex; - int attributeLengthOffset = this.contentsOffset; - this.contentsOffset += 4; // leave space for the attribute length - - int annotationsLengthOffset = this.contentsOffset; - this.contentsOffset += 2; // leave space for the annotations length - - int counter = 0; - loop: for (int i = 0; i < length; i++) { - if (invisibleTypeAnnotationsCounter == 0) break loop; - AnnotationContext annotationContext = annotationContexts[i]; - if ((annotationContext.visibility & AnnotationContext.INVISIBLE) != 0) { - int currentAnnotationOffset = this.contentsOffset; - generateTypeAnnotation(annotationContext, currentAnnotationOffset); - invisibleTypeAnnotationsCounter--; - if (this.contentsOffset != currentAnnotationOffset) { - counter++; - } - } - } - if (counter != 0) { - this.contents[annotationsLengthOffset++] = (byte) (counter >> 8); - this.contents[annotationsLengthOffset++] = (byte) counter; - - int attributeLength = this.contentsOffset - attributeLengthOffset - 4; - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); - this.contents[attributeLengthOffset++] = (byte) attributeLength; - attributesNumber++; - } else { - this.contentsOffset = annotationAttributeOffset; - } - } - - annotationAttributeOffset = this.contentsOffset; - if (visibleTypeAnnotationsCounter != 0) { - if (this.contentsOffset + 10 >= this.contents.length) { - resizeContents(10); - } - int runtimeVisibleAnnotationsAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.RuntimeVisibleTypeAnnotationsName); - this.contents[this.contentsOffset++] = (byte) (runtimeVisibleAnnotationsAttributeNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) runtimeVisibleAnnotationsAttributeNameIndex; - int attributeLengthOffset = this.contentsOffset; - this.contentsOffset += 4; // leave space for the attribute length - - int annotationsLengthOffset = this.contentsOffset; - this.contentsOffset += 2; // leave space for the annotations length - - int counter = 0; - loop: for (int i = 0; i < length; i++) { - if (visibleTypeAnnotationsCounter == 0) break loop; - AnnotationContext annotationContext = annotationContexts[i]; - if ((annotationContext.visibility & AnnotationContext.VISIBLE) != 0) { - visibleTypeAnnotationsCounter--; - int currentAnnotationOffset = this.contentsOffset; - generateTypeAnnotation(annotationContext, currentAnnotationOffset); - if (this.contentsOffset != currentAnnotationOffset) { - counter++; - } - } - } - if (counter != 0) { - this.contents[annotationsLengthOffset++] = (byte) (counter >> 8); - this.contents[annotationsLengthOffset++] = (byte) counter; - - int attributeLength = this.contentsOffset - attributeLengthOffset - 4; - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 24); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 16); - this.contents[attributeLengthOffset++] = (byte) (attributeLength >> 8); - this.contents[attributeLengthOffset++] = (byte) attributeLength; - attributesNumber++; - } else { - this.contentsOffset = annotationAttributeOffset; - } - } - return attributesNumber; - } - - /** - * @param binding the given method binding - * @return the number of attributes created while dumping he method's parameters in the .class file (0 or 1) - */ - private int generateMethodParameters(final MethodBinding binding) { - - if (binding.sourceLambda() != null) - return 0; - int initialContentsOffset = this.contentsOffset; - int length = 0; // count of actual parameters - - AbstractMethodDeclaration methodDeclaration = binding.sourceMethod(); - - boolean isConstructor = binding.isConstructor(); - TypeBinding[] targetParameters = binding.parameters; - ReferenceBinding declaringClass = binding.declaringClass; - - if (declaringClass.isEnum()) { - if (isConstructor) { // insert String name,int ordinal - length = writeArgumentName(ConstantPool.EnumName, ClassFileConstants.AccSynthetic, length); - length = writeArgumentName(ConstantPool.EnumOrdinal, ClassFileConstants.AccSynthetic, length); - } else if (binding instanceof SyntheticMethodBinding - && CharOperation.equals(ConstantPool.ValueOf, binding.selector)) { // insert String name - length = writeArgumentName(ConstantPool.Name, ClassFileConstants.AccMandated, length); - targetParameters = Binding.NO_PARAMETERS; // Override "unknown" synthetics below - } - } - - boolean needSynthetics = isConstructor && declaringClass.isNestedType(); - if (needSynthetics) { - // Take into account the synthetic argument names - // This tracks JLS8, paragraph 8.8.9 - boolean anonymousWithLocalSuper = declaringClass.isAnonymousType() && declaringClass.superclass().isLocalType(); - boolean anonymousWithNestedSuper = declaringClass.isAnonymousType() && declaringClass.superclass().isNestedType(); - boolean isImplicitlyDeclared = ((! declaringClass.isPrivate()) || declaringClass.isAnonymousType()) && !anonymousWithLocalSuper; - ReferenceBinding[] syntheticArgumentTypes = declaringClass.syntheticEnclosingInstanceTypes(); - if (syntheticArgumentTypes != null) { - for (int i = 0, count = syntheticArgumentTypes.length; i < count; i++) { - // This behaviour tracks JLS 15.9.5.1 - // This covers that the parameter ending up in a nested class must be mandated "on the way in", even if it - // isn't the first. The practical relevance of this is questionable, since the constructor call will be - // generated by the same constructor. - boolean couldForwardToMandated = anonymousWithNestedSuper ? declaringClass.superclass().enclosingType().equals(syntheticArgumentTypes[i]) : true; - int modifier = couldForwardToMandated && isImplicitlyDeclared ? ClassFileConstants.AccMandated : ClassFileConstants.AccSynthetic; - char[] name = CharOperation.concat( - TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX, - String.valueOf(i).toCharArray()); // cannot use depth, can be identical - length = writeArgumentName(name, modifier | ClassFileConstants.AccFinal, length); - } - } - if (binding instanceof SyntheticMethodBinding) { - targetParameters = ((SyntheticMethodBinding)binding).targetMethod.parameters; - methodDeclaration = ((SyntheticMethodBinding)binding).targetMethod.sourceMethod(); - } - } - if (targetParameters != Binding.NO_PARAMETERS) { - Argument[] arguments = null; - if (methodDeclaration != null && methodDeclaration.arguments != null) { - arguments = methodDeclaration.arguments; - } - for (int i = 0, max = targetParameters.length, argumentsLength = arguments != null ? arguments.length : 0; i < max; i++) { - if (argumentsLength > i && arguments[i] != null) { - Argument argument = arguments[i]; - int modifiers = argument.binding.modifiers; - if (binding.isCompactConstructor()) - modifiers |= ClassFileConstants.AccMandated; - length = writeArgumentName(argument.name, modifiers, length); - } else { - length = writeArgumentName(null, ClassFileConstants.AccSynthetic, length); - } - } - } - if (needSynthetics) { - SyntheticArgumentBinding[] syntheticOuterArguments = declaringClass.syntheticOuterLocalVariables(); - int count = syntheticOuterArguments == null ? 0 : syntheticOuterArguments.length; - for (int i = 0; i < count; i++) { - length = writeArgumentName(syntheticOuterArguments[i].name, syntheticOuterArguments[i].modifiers | ClassFileConstants.AccSynthetic, length); - } - // move the extra padding arguments of the synthetic constructor invocation to the end - for (int i = targetParameters.length, extraLength = binding.parameters.length; i < extraLength; i++) { - TypeBinding parameter = binding.parameters[i]; - length = writeArgumentName(parameter.constantPoolName(), ClassFileConstants.AccSynthetic, length); - } - } - - if (length > 0) { - // so we actually output the parameter - int attributeLength = 1 + 4 * length; // u1 for count, u2+u2 per parameter - if (this.contentsOffset + 6 + attributeLength >= this.contents.length) { - resizeContents(6 + attributeLength); - } - int methodParametersNameIndex = this.constantPool.literalIndex(AttributeNamesConstants.MethodParametersName); - this.contents[initialContentsOffset++] = (byte) (methodParametersNameIndex >> 8); - this.contents[initialContentsOffset++] = (byte) methodParametersNameIndex; - this.contents[initialContentsOffset++] = (byte) (attributeLength >> 24); - this.contents[initialContentsOffset++] = (byte) (attributeLength >> 16); - this.contents[initialContentsOffset++] = (byte) (attributeLength >> 8); - this.contents[initialContentsOffset++] = (byte) attributeLength; - this.contents[initialContentsOffset++] = (byte) length; - return 1; - } - else { - return 0; - } - } - private int writeArgumentName(char[] name, int modifiers, int oldLength) { - int ensureRoomForBytes = 4; - if (oldLength == 0) { - // Make room for - ensureRoomForBytes += 7; - this.contentsOffset += 7; // Make room for attribute header + count byte - } - if (this.contentsOffset + ensureRoomForBytes > this.contents.length) { - resizeContents(ensureRoomForBytes); - } - int parameterNameIndex = name == null ? 0 : this.constantPool.literalIndex(name); - this.contents[this.contentsOffset++] = (byte) (parameterNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) parameterNameIndex; - int flags = modifiers & (ClassFileConstants.AccFinal | ClassFileConstants.AccSynthetic | ClassFileConstants.AccMandated); - this.contents[this.contentsOffset++] = (byte) (flags >> 8); - this.contents[this.contentsOffset++] = (byte) flags; - return oldLength + 1; - } - - private int generateSignatureAttribute(char[] genericSignature) { - int localContentsOffset = this.contentsOffset; - if (localContentsOffset + 8 >= this.contents.length) { - resizeContents(8); - } - int signatureAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.SignatureName); - this.contents[localContentsOffset++] = (byte) (signatureAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) signatureAttributeNameIndex; - // the length of a signature attribute is equals to 2 - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 2; - int signatureIndex = - this.constantPool.literalIndex(genericSignature); - this.contents[localContentsOffset++] = (byte) (signatureIndex >> 8); - this.contents[localContentsOffset++] = (byte) signatureIndex; - this.contentsOffset = localContentsOffset; - return 1; - } - - private int generateSourceAttribute(String fullFileName) { - int localContentsOffset = this.contentsOffset; - // check that there is enough space to write all the bytes for the field info corresponding - // to the @fieldBinding - if (localContentsOffset + 8 >= this.contents.length) { - resizeContents(8); - } - int sourceAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.SourceName); - this.contents[localContentsOffset++] = (byte) (sourceAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) sourceAttributeNameIndex; - // The length of a source file attribute is 2. This is a fixed-length - // attribute - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 2; - // write the source file name - int fileNameIndex = this.constantPool.literalIndex(fullFileName.toCharArray()); - this.contents[localContentsOffset++] = (byte) (fileNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) fileNameIndex; - this.contentsOffset = localContentsOffset; - return 1; - } - private int generateStackMapAttribute( - MethodBinding methodBinding, - int code_length, - int codeAttributeOffset, - int max_locals, - boolean isClinit, - Scope scope) { - int attributesNumber = 0; - int localContentsOffset = this.contentsOffset; - StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; - stackMapFrameCodeStream.removeFramePosition(code_length); - if (stackMapFrameCodeStream.hasFramePositions()) { - Map frames = new HashMap<>(); - List realFrames = traverse(isClinit ? null : methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit, scope); - int numberOfFrames = realFrames.size(); - if (numberOfFrames > 1) { - int stackMapTableAttributeOffset = localContentsOffset; - // add the stack map table attribute - if (localContentsOffset + 8 >= this.contents.length) { - resizeContents(8); - } - int stackMapAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.StackMapName); - this.contents[localContentsOffset++] = (byte) (stackMapAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) stackMapAttributeNameIndex; - - int stackMapAttributeLengthOffset = localContentsOffset; - // generate the attribute - localContentsOffset += 4; - if (localContentsOffset + 4 >= this.contents.length) { - resizeContents(4); - } - int numberOfFramesOffset = localContentsOffset; - localContentsOffset += 2; - if (localContentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - StackMapFrame currentFrame = realFrames.get(0); - for (int j = 1; j < numberOfFrames; j++) { - // select next frame - currentFrame = realFrames.get(j); - // generate current frame - // need to find differences between the current frame and the previous frame - int frameOffset = currentFrame.pc; - // FULL_FRAME - if (localContentsOffset + 5 >= this.contents.length) { - resizeContents(5); - } - this.contents[localContentsOffset++] = (byte) (frameOffset >> 8); - this.contents[localContentsOffset++] = (byte) frameOffset; - int numberOfLocalOffset = localContentsOffset; - localContentsOffset += 2; // leave two spots for number of locals - int numberOfLocalEntries = 0; - int numberOfLocals = currentFrame.getNumberOfLocals(); - int numberOfEntries = 0; - int localsLength = currentFrame.locals == null ? 0 : currentFrame.locals.length; - for (int i = 0; i < localsLength && numberOfLocalEntries < numberOfLocals; i++) { - if (localContentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - VerificationTypeInfo info = currentFrame.locals[i]; - if (info == null) { - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; - } else { - switch(info.id()) { - case T_boolean : - case T_byte : - case T_char : - case T_int : - case T_short : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; - break; - case T_float : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; - break; - case T_long : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; - i++; - break; - case T_double : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; - i++; - break; - case T_null : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; - break; - default: - this.contents[localContentsOffset++] = (byte) info.tag; - switch (info.tag) { - case VerificationTypeInfo.ITEM_UNINITIALIZED : - int offset = info.offset; - this.contents[localContentsOffset++] = (byte) (offset >> 8); - this.contents[localContentsOffset++] = (byte) offset; - break; - case VerificationTypeInfo.ITEM_OBJECT : - int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (indexForType >> 8); - this.contents[localContentsOffset++] = (byte) indexForType; - } - } - numberOfLocalEntries++; - } - numberOfEntries++; - } - if (localContentsOffset + 4 >= this.contents.length) { - resizeContents(4); - } - this.contents[numberOfLocalOffset++] = (byte) (numberOfEntries >> 8); - this.contents[numberOfLocalOffset] = (byte) numberOfEntries; - int numberOfStackItems = currentFrame.numberOfStackItems; - this.contents[localContentsOffset++] = (byte) (numberOfStackItems >> 8); - this.contents[localContentsOffset++] = (byte) numberOfStackItems; - for (int i = 0; i < numberOfStackItems; i++) { - if (localContentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - VerificationTypeInfo info = currentFrame.stackItems[i]; - if (info == null) { - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; - } else { - switch(info.id()) { - case T_boolean : - case T_byte : - case T_char : - case T_int : - case T_short : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; - break; - case T_float : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; - break; - case T_long : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; - break; - case T_double : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; - break; - case T_null : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; - break; - default: - this.contents[localContentsOffset++] = (byte) info.tag; - switch (info.tag) { - case VerificationTypeInfo.ITEM_UNINITIALIZED : - int offset = info.offset; - this.contents[localContentsOffset++] = (byte) (offset >> 8); - this.contents[localContentsOffset++] = (byte) offset; - break; - case VerificationTypeInfo.ITEM_OBJECT : - int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (indexForType >> 8); - this.contents[localContentsOffset++] = (byte) indexForType; - } - } - } - } - } - - numberOfFrames--; - if (numberOfFrames != 0) { - this.contents[numberOfFramesOffset++] = (byte) (numberOfFrames >> 8); - this.contents[numberOfFramesOffset] = (byte) numberOfFrames; - - int attributeLength = localContentsOffset - stackMapAttributeLengthOffset - 4; - this.contents[stackMapAttributeLengthOffset++] = (byte) (attributeLength >> 24); - this.contents[stackMapAttributeLengthOffset++] = (byte) (attributeLength >> 16); - this.contents[stackMapAttributeLengthOffset++] = (byte) (attributeLength >> 8); - this.contents[stackMapAttributeLengthOffset] = (byte) attributeLength; - attributesNumber++; - } else { - localContentsOffset = stackMapTableAttributeOffset; - } - } - } - this.contentsOffset = localContentsOffset; - return attributesNumber; - } - - private int generateStackMapTableAttribute( - MethodBinding methodBinding, - int code_length, - int codeAttributeOffset, - int max_locals, - boolean isClinit, - Scope scope) { - int attributesNumber = 0; - int localContentsOffset = this.contentsOffset; - StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; - stackMapFrameCodeStream.removeFramePosition(code_length); - if (stackMapFrameCodeStream.hasFramePositions()) { - Map frames = new HashMap<>(); - List realFrames = traverse(isClinit ? null: methodBinding, max_locals, this.contents, codeAttributeOffset + 14, code_length, frames, isClinit, scope); - int numberOfFrames = realFrames.size(); - if (numberOfFrames > 1) { - int stackMapTableAttributeOffset = localContentsOffset; - // add the stack map table attribute - if (localContentsOffset + 8 >= this.contents.length) { - resizeContents(8); - } - int stackMapTableAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.StackMapTableName); - this.contents[localContentsOffset++] = (byte) (stackMapTableAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) stackMapTableAttributeNameIndex; - - int stackMapTableAttributeLengthOffset = localContentsOffset; - // generate the attribute - localContentsOffset += 4; - if (localContentsOffset + 4 >= this.contents.length) { - resizeContents(4); - } - int numberOfFramesOffset = localContentsOffset; - localContentsOffset += 2; - if (localContentsOffset + 2 >= this.contents.length) { - resizeContents(2); - } - StackMapFrame currentFrame = realFrames.get(0); - StackMapFrame prevFrame = null; - for (int j = 1; j < numberOfFrames; j++) { - // select next frame - prevFrame = currentFrame; - currentFrame = realFrames.get(j); - // generate current frame - // need to find differences between the current frame and the previous frame - int offsetDelta = currentFrame.getOffsetDelta(prevFrame); - switch (currentFrame.getFrameType(prevFrame)) { - case StackMapFrame.APPEND_FRAME : - if (localContentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - int numberOfDifferentLocals = currentFrame.numberOfDifferentLocals(prevFrame); - this.contents[localContentsOffset++] = (byte) (251 + numberOfDifferentLocals); - this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); - this.contents[localContentsOffset++] = (byte) offsetDelta; - int index = currentFrame.getIndexOfDifferentLocals(numberOfDifferentLocals); - int numberOfLocals = currentFrame.getNumberOfLocals(); - for (int i = index; i < currentFrame.locals.length && numberOfDifferentLocals > 0; i++) { - if (localContentsOffset + 6 >= this.contents.length) { - resizeContents(6); - } - VerificationTypeInfo info = currentFrame.locals[i]; - if (info == null) { - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; - } else { - switch(info.id()) { - case T_boolean : - case T_byte : - case T_char : - case T_int : - case T_short : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; - break; - case T_float : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; - break; - case T_long : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; - i++; - break; - case T_double : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; - i++; - break; - case T_null : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; - break; - default: - this.contents[localContentsOffset++] = (byte) info.tag; - switch (info.tag) { - case VerificationTypeInfo.ITEM_UNINITIALIZED : - int offset = info.offset; - this.contents[localContentsOffset++] = (byte) (offset >> 8); - this.contents[localContentsOffset++] = (byte) offset; - break; - case VerificationTypeInfo.ITEM_OBJECT : - int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (indexForType >> 8); - this.contents[localContentsOffset++] = (byte) indexForType; - } - } - numberOfDifferentLocals--; - } - } - break; - case StackMapFrame.SAME_FRAME : - if (localContentsOffset + 1 >= this.contents.length) { - resizeContents(1); - } - this.contents[localContentsOffset++] = (byte) offsetDelta; - break; - case StackMapFrame.SAME_FRAME_EXTENDED : - if (localContentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - this.contents[localContentsOffset++] = (byte) 251; - this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); - this.contents[localContentsOffset++] = (byte) offsetDelta; - break; - case StackMapFrame.CHOP_FRAME : - if (localContentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - numberOfDifferentLocals = -currentFrame.numberOfDifferentLocals(prevFrame); - this.contents[localContentsOffset++] = (byte) (251 - numberOfDifferentLocals); - this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); - this.contents[localContentsOffset++] = (byte) offsetDelta; - break; - case StackMapFrame.SAME_LOCALS_1_STACK_ITEMS : - if (localContentsOffset + 4 >= this.contents.length) { - resizeContents(4); - } - this.contents[localContentsOffset++] = (byte) (offsetDelta + 64); - if (currentFrame.stackItems[0] == null) { - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; - } else { - switch(currentFrame.stackItems[0].id()) { - case T_boolean : - case T_byte : - case T_char : - case T_int : - case T_short : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; - break; - case T_float : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; - break; - case T_long : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; - break; - case T_double : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; - break; - case T_null : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; - break; - default: - VerificationTypeInfo info = currentFrame.stackItems[0]; - byte tag = (byte) info.tag; - this.contents[localContentsOffset++] = tag; - switch (tag) { - case VerificationTypeInfo.ITEM_UNINITIALIZED : - int offset = info.offset; - this.contents[localContentsOffset++] = (byte) (offset >> 8); - this.contents[localContentsOffset++] = (byte) offset; - break; - case VerificationTypeInfo.ITEM_OBJECT : - int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (indexForType >> 8); - this.contents[localContentsOffset++] = (byte) indexForType; - } - } - } - break; - case StackMapFrame.SAME_LOCALS_1_STACK_ITEMS_EXTENDED : - if (localContentsOffset + 6 >= this.contents.length) { - resizeContents(6); - } - this.contents[localContentsOffset++] = (byte) 247; - this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); - this.contents[localContentsOffset++] = (byte) offsetDelta; - if (currentFrame.stackItems[0] == null) { - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; - } else { - switch(currentFrame.stackItems[0].id()) { - case T_boolean : - case T_byte : - case T_char : - case T_int : - case T_short : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; - break; - case T_float : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; - break; - case T_long : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; - break; - case T_double : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; - break; - case T_null : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; - break; - default: - VerificationTypeInfo info = currentFrame.stackItems[0]; - byte tag = (byte) info.tag; - this.contents[localContentsOffset++] = tag; - switch (tag) { - case VerificationTypeInfo.ITEM_UNINITIALIZED : - int offset = info.offset; - this.contents[localContentsOffset++] = (byte) (offset >> 8); - this.contents[localContentsOffset++] = (byte) offset; - break; - case VerificationTypeInfo.ITEM_OBJECT : - int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (indexForType >> 8); - this.contents[localContentsOffset++] = (byte) indexForType; - } - } - } - break; - default : - // FULL_FRAME - if (localContentsOffset + 5 >= this.contents.length) { - resizeContents(5); - } - this.contents[localContentsOffset++] = (byte) 255; - this.contents[localContentsOffset++] = (byte) (offsetDelta >> 8); - this.contents[localContentsOffset++] = (byte) offsetDelta; - int numberOfLocalOffset = localContentsOffset; - localContentsOffset += 2; // leave two spots for number of locals - int numberOfLocalEntries = 0; - numberOfLocals = currentFrame.getNumberOfLocals(); - int numberOfEntries = 0; - int localsLength = currentFrame.locals == null ? 0 : currentFrame.locals.length; - for (int i = 0; i < localsLength && numberOfLocalEntries < numberOfLocals; i++) { - if (localContentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - VerificationTypeInfo info = currentFrame.locals[i]; - if (info == null) { - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; - } else { - switch(info.id()) { - case T_boolean : - case T_byte : - case T_char : - case T_int : - case T_short : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; - break; - case T_float : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; - break; - case T_long : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; - i++; - break; - case T_double : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; - i++; - break; - case T_null : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; - break; - default: - this.contents[localContentsOffset++] = (byte) info.tag; - switch (info.tag) { - case VerificationTypeInfo.ITEM_UNINITIALIZED : - int offset = info.offset; - this.contents[localContentsOffset++] = (byte) (offset >> 8); - this.contents[localContentsOffset++] = (byte) offset; - break; - case VerificationTypeInfo.ITEM_OBJECT : - int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (indexForType >> 8); - this.contents[localContentsOffset++] = (byte) indexForType; - } - } - numberOfLocalEntries++; - } - numberOfEntries++; - } - if (localContentsOffset + 4 >= this.contents.length) { - resizeContents(4); - } - this.contents[numberOfLocalOffset++] = (byte) (numberOfEntries >> 8); - this.contents[numberOfLocalOffset] = (byte) numberOfEntries; - int numberOfStackItems = currentFrame.numberOfStackItems; - this.contents[localContentsOffset++] = (byte) (numberOfStackItems >> 8); - this.contents[localContentsOffset++] = (byte) numberOfStackItems; - for (int i = 0; i < numberOfStackItems; i++) { - if (localContentsOffset + 3 >= this.contents.length) { - resizeContents(3); - } - VerificationTypeInfo info = currentFrame.stackItems[i]; - if (info == null) { - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_TOP; - } else { - switch(info.id()) { - case T_boolean : - case T_byte : - case T_char : - case T_int : - case T_short : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_INTEGER; - break; - case T_float : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_FLOAT; - break; - case T_long : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_LONG; - break; - case T_double : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_DOUBLE; - break; - case T_null : - this.contents[localContentsOffset++] = (byte) VerificationTypeInfo.ITEM_NULL; - break; - default: - this.contents[localContentsOffset++] = (byte) info.tag; - switch (info.tag) { - case VerificationTypeInfo.ITEM_UNINITIALIZED : - int offset = info.offset; - this.contents[localContentsOffset++] = (byte) (offset >> 8); - this.contents[localContentsOffset++] = (byte) offset; - break; - case VerificationTypeInfo.ITEM_OBJECT : - int indexForType = this.constantPool.literalIndexForType(info.constantPoolName()); - this.contents[localContentsOffset++] = (byte) (indexForType >> 8); - this.contents[localContentsOffset++] = (byte) indexForType; - } - } - } - } - } - } - - numberOfFrames--; - if (numberOfFrames != 0) { - this.contents[numberOfFramesOffset++] = (byte) (numberOfFrames >> 8); - this.contents[numberOfFramesOffset] = (byte) numberOfFrames; - - int attributeLength = localContentsOffset - stackMapTableAttributeLengthOffset - 4; - this.contents[stackMapTableAttributeLengthOffset++] = (byte) (attributeLength >> 24); - this.contents[stackMapTableAttributeLengthOffset++] = (byte) (attributeLength >> 16); - this.contents[stackMapTableAttributeLengthOffset++] = (byte) (attributeLength >> 8); - this.contents[stackMapTableAttributeLengthOffset] = (byte) attributeLength; - attributesNumber++; - } else { - localContentsOffset = stackMapTableAttributeOffset; - } - } - } - this.contentsOffset = localContentsOffset; - return attributesNumber; - } - - private int generateSyntheticAttribute() { - int localContentsOffset = this.contentsOffset; - if (localContentsOffset + 6 >= this.contents.length) { - resizeContents(6); - } - int syntheticAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.SyntheticName); - this.contents[localContentsOffset++] = (byte) (syntheticAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) syntheticAttributeNameIndex; - // the length of a synthetic attribute is equals to 0 - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contentsOffset = localContentsOffset; - return 1; - } - - private void generateTypeAnnotation(AnnotationContext annotationContext, int currentOffset) { - Annotation annotation = annotationContext.annotation.getPersistibleAnnotation(); - if (annotation == null || annotation.resolvedType == null) - return; - - int targetType = annotationContext.targetType; - - int[] locations = Annotation.getLocations( - annotationContext.typeReference, - annotationContext.annotation); - - if (this.contentsOffset + 5 >= this.contents.length) { - resizeContents(5); - } - this.contents[this.contentsOffset++] = (byte) targetType; - dumpTargetTypeContents(targetType, annotationContext); - dumpLocations(locations); - generateAnnotation(annotation, currentOffset); - } - - private int generateTypeAnnotationAttributeForTypeDeclaration() { - TypeDeclaration typeDeclaration = this.referenceBinding.scope.referenceContext; - if ((typeDeclaration.bits & ASTNode.HasTypeAnnotations) == 0) { - return 0; - } - int attributesNumber = 0; - TypeReference superclass = typeDeclaration.superclass; - List allTypeAnnotationContexts = new ArrayList<>(); - if (superclass != null && (superclass.bits & ASTNode.HasTypeAnnotations) != 0) { - superclass.getAllAnnotationContexts(AnnotationTargetTypeConstants.CLASS_EXTENDS, -1, allTypeAnnotationContexts); - } - TypeReference[] superInterfaces = typeDeclaration.superInterfaces; - if (superInterfaces != null) { - for (int i = 0; i < superInterfaces.length; i++) { - TypeReference superInterface = superInterfaces[i]; - if ((superInterface.bits & ASTNode.HasTypeAnnotations) == 0) { - continue; - } - superInterface.getAllAnnotationContexts(AnnotationTargetTypeConstants.CLASS_EXTENDS, i, allTypeAnnotationContexts); - } - } - // TODO: permittedTypes codegen - TypeParameter[] typeParameters = typeDeclaration.typeParameters; - if (typeParameters != null) { - for (int i = 0, max = typeParameters.length; i < max; i++) { - TypeParameter typeParameter = typeParameters[i]; - if ((typeParameter.bits & ASTNode.HasTypeAnnotations) != 0) { - typeParameter.getAllAnnotationContexts(AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER, i, allTypeAnnotationContexts); - } - } - } - int size = allTypeAnnotationContexts.size(); - attributesNumber = completeRuntimeTypeAnnotations(attributesNumber, - null, - node -> size > 0, - () -> allTypeAnnotationContexts); - return attributesNumber; - } - - - - - private int generateVarargsAttribute() { - int localContentsOffset = this.contentsOffset; - /* - * handle of the target jsr14 for varargs in the source - * Varargs attribute - * Check that there is enough space to write the attribute - */ - if (localContentsOffset + 6 >= this.contents.length) { - resizeContents(6); - } - int varargsAttributeNameIndex = - this.constantPool.literalIndex(AttributeNamesConstants.VarargsName); - this.contents[localContentsOffset++] = (byte) (varargsAttributeNameIndex >> 8); - this.contents[localContentsOffset++] = (byte) varargsAttributeNameIndex; - // the length of a varargs attribute is equals to 0 - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - this.contents[localContentsOffset++] = 0; - - this.contentsOffset = localContentsOffset; - return 1; - } - - /** - * EXTERNAL API - * Answer the actual bytes of the class file - * - * This method encodes the receiver structure into a byte array which is the content of the classfile. - * Returns the byte array that represents the encoded structure of the receiver. - * - * @return byte[] - */ - public byte[] getBytes() { - if (this.bytes == null) { - this.bytes = new byte[this.headerOffset + this.contentsOffset]; - System.arraycopy(this.header, 0, this.bytes, 0, this.headerOffset); - System.arraycopy(this.contents, 0, this.bytes, this.headerOffset, this.contentsOffset); - } - return this.bytes; - } - - /** - * Sets the actual bytes of the class file. - * - * This method is made public only to be accessible from org.eclipse.jdt.internal.core.builder.AbstractImageBuilder - * during compilation post processing to store the modified byte representation of the class. Using this method for - * any other purpose is discouraged and may lead to unpredictable results. - * - * @param newBytes - * array containing new bytes, will be stored "as is", all subsequent modification on given - * array will be reflected and vice versa. - */ - public void internalSetBytes(byte[] newBytes) { - this.bytes = newBytes; - } - - /** - * EXTERNAL API - * Answer the compound name of the class file. - * @return char[][] - * e.g. {{java}, {util}, {Hashtable}}. - */ - public char[][] getCompoundName() { - return CharOperation.splitOn('/', fileName()); - } - - private int getParametersCount(char[] methodSignature) { - int i = CharOperation.indexOf('(', methodSignature); - i++; - char currentCharacter = methodSignature[i]; - if (currentCharacter == ')') { - return 0; - } - int result = 0; - while (true) { - currentCharacter = methodSignature[i]; - if (currentCharacter == ')') { - return result; - } - switch (currentCharacter) { - case '[': - // array type - int scanType = scanType(methodSignature, i + 1); - result++; - i = scanType + 1; - break; - case 'L': - scanType = CharOperation.indexOf(';', methodSignature, - i + 1); - result++; - i = scanType + 1; - break; - case 'Z': - case 'B': - case 'C': - case 'D': - case 'F': - case 'I': - case 'J': - case 'S': - result++; - i++; - break; - default: - throw new IllegalArgumentException("Invalid starting type character : " + currentCharacter); //$NON-NLS-1$ - } - } - } - - private char[] getReturnType(char[] methodSignature) { - // skip type parameters - int paren = CharOperation.lastIndexOf(')', methodSignature); - // there could be thrown exceptions behind, thus scan one type exactly - return CharOperation.subarray(methodSignature, paren + 1, methodSignature.length); - } - - private final int i4At(byte[] reference, int relativeOffset, - int structOffset) { - int position = relativeOffset + structOffset; - return ((reference[position++] & 0xFF) << 24) - + ((reference[position++] & 0xFF) << 16) - + ((reference[position++] & 0xFF) << 8) - + (reference[position] & 0xFF); - } - - protected void initByteArrays(int members) { - this.header = new byte[INITIAL_HEADER_SIZE]; - this.contents = new byte[members < 15 ? INITIAL_CONTENTS_SIZE : INITIAL_HEADER_SIZE]; - } - - private void initializeHeader(ClassFile parentClassFile, int accessFlags) { - // generate the magic numbers inside the header - this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 24); - this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 16); - this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 8); - this.header[this.headerOffset++] = (byte) (0xCAFEBABEL >> 0); - - long targetVersion = this.targetJDK; - this.header[this.headerOffset++] = (byte) (targetVersion >> 8); // minor high - this.header[this.headerOffset++] = (byte) (targetVersion>> 0); // minor low - this.header[this.headerOffset++] = (byte) (targetVersion >> 24); // major high - this.header[this.headerOffset++] = (byte) (targetVersion >> 16); // major low - - this.constantPoolOffset = this.headerOffset; - this.headerOffset += 2; - this.constantPool.initialize(this); - this.enclosingClassFile = parentClassFile; - - // now we continue to generate the bytes inside the contents array - this.contents[this.contentsOffset++] = (byte) (accessFlags >> 8); - this.contents[this.contentsOffset++] = (byte) accessFlags; - } - - public void initialize(SourceTypeBinding aType, ClassFile parentClassFile, boolean createProblemType) { - - // Modifier manipulations for classfile - int accessFlags = aType.getAccessFlags(); - if (aType.isPrivate()) { // rewrite private to non-public - accessFlags &= ~ClassFileConstants.AccPublic; - } - if (aType.isProtected()) { // rewrite protected into public - accessFlags |= ClassFileConstants.AccPublic; - } - // clear all bits that are illegal for a class or an interface - accessFlags - &= ~( - ClassFileConstants.AccStrictfp - | ClassFileConstants.AccProtected - | ClassFileConstants.AccPrivate - | ClassFileConstants.AccStatic - | ClassFileConstants.AccSynchronized - | ClassFileConstants.AccNative); - - // set the AccSuper flag (has to be done after clearing AccSynchronized - since same value) - if (!aType.isInterface()) { // class or enum - accessFlags |= ClassFileConstants.AccSuper; - } - if (aType.isAnonymousType()) { - ReferenceBinding superClass = aType.superclass; - if (superClass == null || !(superClass.isEnum() && superClass.isSealed())) - accessFlags &= ~ClassFileConstants.AccFinal; - } - int finalAbstract = ClassFileConstants.AccFinal | ClassFileConstants.AccAbstract; - if ((accessFlags & finalAbstract) == finalAbstract) { - accessFlags &= ~finalAbstract; - } - initializeHeader(parentClassFile, accessFlags); - // innerclasses get their names computed at code gen time - - int classNameIndex = this.constantPool.literalIndexForType(aType); - this.contents[this.contentsOffset++] = (byte) (classNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) classNameIndex; - int superclassNameIndex; - if (aType.isInterface()) { - superclassNameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangObjectConstantPoolName); - } else { - if (aType.superclass != null) { - if ((aType.superclass.tagBits & TagBits.HasMissingType) != 0) { - superclassNameIndex = this.constantPool.literalIndexForType(ConstantPool.JavaLangObjectConstantPoolName); - } else { - superclassNameIndex = this.constantPool.literalIndexForType(aType.superclass); - } - } else { - superclassNameIndex = 0; - } - } - this.contents[this.contentsOffset++] = (byte) (superclassNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) superclassNameIndex; - ReferenceBinding[] superInterfacesBinding = aType.superInterfaces(); - int interfacesCount = superInterfacesBinding.length; - int interfacesCountPosition = this.contentsOffset; - this.contentsOffset += 2; - int interfaceCounter = 0; - for (int i = 0; i < interfacesCount; i++) { - ReferenceBinding binding = superInterfacesBinding[i]; - if ((binding.tagBits & TagBits.HasMissingType) != 0) { - continue; - } - if (this.contentsOffset + 4 >= this.contents.length) { - resizeContents(4); // 2 bytes this iteration plus 2 bytes after the loop - } - interfaceCounter++; - int interfaceIndex = this.constantPool.literalIndexForType(binding); - this.contents[this.contentsOffset++] = (byte) (interfaceIndex >> 8); - this.contents[this.contentsOffset++] = (byte) interfaceIndex; - } - this.contents[interfacesCountPosition++] = (byte) (interfaceCounter >> 8); - this.contents[interfacesCountPosition] = (byte) interfaceCounter; - this.creatingProblemType = createProblemType; - - // retrieve the enclosing one guaranteed to be the one matching the propagated flow info - // 1FF9ZBU: LFCOM:ALL - Local variable attributes busted (Sanity check) - this.codeStream.maxFieldCount = aType.scope.outerMostClassScope().referenceType().maxFieldCount; - } - - public void initializeForModule(ModuleBinding module) { - initializeHeader(null, ClassFileConstants.AccModule); - int classNameIndex = this.constantPool.literalIndexForType(TypeConstants.MODULE_INFO_NAME); - this.contents[this.contentsOffset++] = (byte) (classNameIndex >> 8); - this.contents[this.contentsOffset++] = (byte) classNameIndex; - this.codeStream.maxFieldCount = 0; - // superclass: - this.contents[this.contentsOffset++] = 0; - this.contents[this.contentsOffset++] = 0; - // superInterfacesCount - this.contents[this.contentsOffset++] = 0; - this.contents[this.contentsOffset++] = 0; - // fieldsCount - this.contents[this.contentsOffset++] = 0; - this.contents[this.contentsOffset++] = 0; - // methodsCount - this.contents[this.contentsOffset++] = 0; - this.contents[this.contentsOffset++] = 0; - } - - private void initializeDefaultLocals(StackMapFrame frame, - MethodBinding methodBinding, - int maxLocals, - int codeLength) { - if (maxLocals != 0) { - int resolvedPosition = 0; - // take into account enum constructor synthetic name+ordinal - final boolean isConstructor = methodBinding.isConstructor(); - if (isConstructor || !methodBinding.isStatic()) { - LocalVariableBinding localVariableBinding = new LocalVariableBinding(ConstantPool.This, methodBinding.declaringClass, 0, false); - localVariableBinding.resolvedPosition = 0; - this.codeStream.record(localVariableBinding); - localVariableBinding.recordInitializationStartPC(0); - localVariableBinding.recordInitializationEndPC(codeLength); - frame.putLocal(resolvedPosition, new VerificationTypeInfo( - isConstructor ? VerificationTypeInfo.ITEM_UNINITIALIZED_THIS : VerificationTypeInfo.ITEM_OBJECT, - methodBinding.declaringClass)); - resolvedPosition++; - } - - if (isConstructor) { - if (methodBinding.declaringClass.isEnum()) { - LocalVariableBinding localVariableBinding = new LocalVariableBinding(" name".toCharArray(), this.referenceBinding.scope.getJavaLangString(), 0, false); //$NON-NLS-1$ - localVariableBinding.resolvedPosition = resolvedPosition; - this.codeStream.record(localVariableBinding); - localVariableBinding.recordInitializationStartPC(0); - localVariableBinding.recordInitializationEndPC(codeLength); - - frame.putLocal(resolvedPosition, new VerificationTypeInfo(this.referenceBinding.scope.getJavaLangString())); - resolvedPosition++; - - localVariableBinding = new LocalVariableBinding(" ordinal".toCharArray(), TypeBinding.INT, 0, false); //$NON-NLS-1$ - localVariableBinding.resolvedPosition = resolvedPosition; - this.codeStream.record(localVariableBinding); - localVariableBinding.recordInitializationStartPC(0); - localVariableBinding.recordInitializationEndPC(codeLength); - frame.putLocal(resolvedPosition, new VerificationTypeInfo(TypeBinding.INT)); - resolvedPosition++; - } - - // take into account the synthetic parameters - if (methodBinding.declaringClass.isNestedType()) { - ReferenceBinding enclosingInstanceTypes[]; - if ((enclosingInstanceTypes = methodBinding.declaringClass.syntheticEnclosingInstanceTypes()) != null) { - for (int i = 0, max = enclosingInstanceTypes.length; i < max; i++) { - // an enclosingInstanceType can only be a reference - // binding. It cannot be - // LongBinding or DoubleBinding - LocalVariableBinding localVariableBinding = new LocalVariableBinding((" enclosingType" + i).toCharArray(), enclosingInstanceTypes[i], 0, false); //$NON-NLS-1$ - localVariableBinding.resolvedPosition = resolvedPosition; - this.codeStream.record(localVariableBinding); - localVariableBinding.recordInitializationStartPC(0); - localVariableBinding.recordInitializationEndPC(codeLength); - - frame.putLocal(resolvedPosition, - new VerificationTypeInfo(enclosingInstanceTypes[i])); - resolvedPosition++; - } - } - - TypeBinding[] arguments; - if ((arguments = methodBinding.parameters) != null) { - for (int i = 0, max = arguments.length; i < max; i++) { - final TypeBinding typeBinding = arguments[i]; - frame.putLocal(resolvedPosition, - new VerificationTypeInfo(typeBinding)); - switch (typeBinding.id) { - case TypeIds.T_double: - case TypeIds.T_long: - resolvedPosition += 2; - break; - default: - resolvedPosition++; - } - } - } - - SyntheticArgumentBinding syntheticArguments[]; - if ((syntheticArguments = methodBinding.declaringClass.syntheticOuterLocalVariables()) != null) { - for (int i = 0, max = syntheticArguments.length; i < max; i++) { - final TypeBinding typeBinding = syntheticArguments[i].type; - LocalVariableBinding localVariableBinding = new LocalVariableBinding((" synthetic" + i).toCharArray(), typeBinding, 0, false); //$NON-NLS-1$ - localVariableBinding.resolvedPosition = resolvedPosition; - this.codeStream.record(localVariableBinding); - localVariableBinding.recordInitializationStartPC(0); - localVariableBinding.recordInitializationEndPC(codeLength); - - frame.putLocal(resolvedPosition, - new VerificationTypeInfo(typeBinding)); - switch (typeBinding.id) { - case TypeIds.T_double: - case TypeIds.T_long: - resolvedPosition += 2; - break; - default: - resolvedPosition++; - } - } - } - } else { - TypeBinding[] arguments; - if ((arguments = methodBinding.parameters) != null) { - for (int i = 0, max = arguments.length; i < max; i++) { - final TypeBinding typeBinding = arguments[i]; - frame.putLocal(resolvedPosition, - new VerificationTypeInfo(typeBinding)); - switch (typeBinding.id) { - case TypeIds.T_double: - case TypeIds.T_long: - resolvedPosition += 2; - break; - default: - resolvedPosition++; - } - } - } - } - } else { - TypeBinding[] arguments; - if ((arguments = methodBinding.parameters) != null) { - for (int i = 0, max = arguments.length; i < max; i++) { - final TypeBinding typeBinding = arguments[i]; - // For the branching complexities in the generated $deserializeLambda$ we need the local variable - LocalVariableBinding localVariableBinding = new LocalVariableBinding((" synthetic"+i).toCharArray(), typeBinding, 0, true); //$NON-NLS-1$ - localVariableBinding.resolvedPosition = i; - this.codeStream.record(localVariableBinding); - localVariableBinding.recordInitializationStartPC(0); - localVariableBinding.recordInitializationEndPC(codeLength); - frame.putLocal(resolvedPosition, - new VerificationTypeInfo(typeBinding)); - switch (typeBinding.id) { - case TypeIds.T_double: - case TypeIds.T_long: - resolvedPosition += 2; - break; - default: - resolvedPosition++; - } - } - } - } - } - } - - private void initializeLocals(boolean isStatic, int currentPC, StackMapFrame currentFrame) { - VerificationTypeInfo[] locals = currentFrame.locals; - int localsLength = locals.length; - int i = 0; - if (!isStatic) { - // we don't want to reset the first local if the method is not static - i = 1; - } - for (; i < localsLength; i++) { - locals[i] = null; - } - i = 0; - locals: for (int max = this.codeStream.allLocalsCounter; i < max; i++) { - LocalVariableBinding localVariable = this.codeStream.locals[i]; - if (localVariable == null) continue; - int resolvedPosition = localVariable.resolvedPosition; - final TypeBinding localVariableTypeBinding = localVariable.type; - inits: for (int j = 0; j < localVariable.initializationCount; j++) { - int startPC = localVariable.initializationPCs[j << 1]; - int endPC = localVariable.initializationPCs[(j << 1) + 1]; - if (currentPC < startPC) { - continue inits; - } else if (currentPC < endPC) { - // the current local is an active local - if (currentFrame.locals[resolvedPosition] == null) { - currentFrame.locals[resolvedPosition] = - new VerificationTypeInfo( - localVariableTypeBinding); - } - continue locals; - } - } - } - } - /** - * INTERNAL USE-ONLY - * Returns the most enclosing classfile of the receiver. This is used know to store the constant pool name - * for all inner types of the receiver. - * @return org.eclipse.jdt.internal.compiler.codegen.ClassFile - */ - public ClassFile outerMostEnclosingClassFile() { - ClassFile current = this; - while (current.enclosingClassFile != null) - current = current.enclosingClassFile; - return current; - } - - public void recordInnerClasses(TypeBinding binding) { - recordInnerClasses(binding, false); - } - public void recordInnerClasses(TypeBinding binding, boolean onBottomForBug445231) { - if (this.innerClassesBindings == null) { - this.innerClassesBindings = new HashMap<>(INNER_CLASSES_SIZE); - } - ReferenceBinding innerClass = (ReferenceBinding) binding; - this.innerClassesBindings.put(innerClass.erasure().unannotated(), onBottomForBug445231); // should not emit yet another inner class for Outer.@Inner Inner. - ReferenceBinding enclosingType = innerClass.enclosingType(); - while (enclosingType != null - && enclosingType.isNestedType()) { - this.innerClassesBindings.put(enclosingType.erasure().unannotated(), onBottomForBug445231); - enclosingType = enclosingType.enclosingType(); - } - } - public void recordNestMember(SourceTypeBinding binding) { - SourceTypeBinding nestHost = binding != null ? binding.getNestHost() : null; - if (nestHost != null && !binding.equals(nestHost)) {// member - if (this.nestMembers == null) { - this.nestMembers = new HashSet<>(NESTED_MEMBER_SIZE); - } - this.nestMembers.add(binding); - } - } - public List getNestMembers() { - if (this.nestMembers == null) - return null; - List list = this.nestMembers - .stream() - .map(s -> new String(s.constantPoolName())) - .sorted() - .collect(Collectors.toList()); - return list; - } - - public int recordBootstrapMethod(FunctionalExpression expression) { - if (this.bootstrapMethods == null) { - this.bootstrapMethods = new ArrayList<>(); - } - if (expression instanceof ReferenceExpression) { - for (int i = 0; i < this.bootstrapMethods.size(); i++) { - Object node = this.bootstrapMethods.get(i); - if (node instanceof FunctionalExpression) { - FunctionalExpression fexp = (FunctionalExpression) node; - if (fexp.binding == expression.binding - && TypeBinding.equalsEquals(fexp.expectedType(), expression.expectedType())) - return expression.bootstrapMethodNumber = i; - } - } - } - this.bootstrapMethods.add(expression); - // Record which bootstrap method was assigned to the expression - return expression.bootstrapMethodNumber = this.bootstrapMethods.size() - 1; - } - - public int recordBootstrapMethod(SwitchStatement switchStatement) { - if (this.bootstrapMethods == null) { - this.bootstrapMethods = new ArrayList<>(); - } - this.bootstrapMethods.add(switchStatement); - return this.bootstrapMethods.size() - 1; - } - public int recordBootstrapMethod(ResolvedCase resolvedCase) { - if (this.bootstrapMethods == null) { - this.bootstrapMethods = new ArrayList<>(); - } - this.bootstrapMethods.add(resolvedCase); - return this.bootstrapMethods.size() - 1; - } - public int recordBootstrapMethod(TypeBinding type) { - if (this.bootstrapMethods == null) { - this.bootstrapMethods = new ArrayList<>(); - } else { - int idx = this.bootstrapMethods.indexOf(type); - if (idx != -1) { - return idx; - } - } - this.bootstrapMethods.add(type); - return this.bootstrapMethods.size() - 1; - } - public int recordBootstrapMethod(String expression) { - if (this.bootstrapMethods == null) { - this.bootstrapMethods = new ArrayList<>(); - } - this.bootstrapMethods.add(expression); - return this.bootstrapMethods.size() - 1; - } - public int recordBootstrapMethod(StringTemplate template) { - if (this.bootstrapMethods == null) { - this.bootstrapMethods = new ArrayList<>(); - } - this.bootstrapMethods.add(template); - return this.bootstrapMethods.size() - 1; - } - public void reset(/*@Nullable*/SourceTypeBinding typeBinding, CompilerOptions options) { - // the code stream is reinitialized for each method - if (typeBinding != null) { - this.referenceBinding = typeBinding; - this.isNestedType = typeBinding.isNestedType(); - } else { - this.referenceBinding = null; - this.isNestedType = false; - } - this.targetJDK = options.targetJDK; - this.produceAttributes = options.produceDebugAttributes; - if (this.targetJDK >= ClassFileConstants.JDK1_6) { - this.produceAttributes |= ClassFileConstants.ATTR_STACK_MAP_TABLE; - if (this.targetJDK >= ClassFileConstants.JDK1_8) { - this.produceAttributes |= ClassFileConstants.ATTR_TYPE_ANNOTATION; - if (!(this.codeStream instanceof TypeAnnotationCodeStream) && this.referenceBinding != null) - this.codeStream = new TypeAnnotationCodeStream(this); - if (options.produceMethodParameters) { - this.produceAttributes |= ClassFileConstants.ATTR_METHOD_PARAMETERS; - } - } - } else if (this.targetJDK == ClassFileConstants.CLDC_1_1) { - this.targetJDK = ClassFileConstants.JDK1_1; // put back 45.3 - this.produceAttributes |= ClassFileConstants.ATTR_STACK_MAP; - } - this.bytes = null; - this.constantPool.reset(); - this.codeStream.reset(this); - this.constantPoolOffset = 0; - this.contentsOffset = 0; - this.creatingProblemType = false; - this.enclosingClassFile = null; - this.headerOffset = 0; - this.methodCount = 0; - this.methodCountOffset = 0; - if (this.innerClassesBindings != null) { - this.innerClassesBindings.clear(); - } - if (this.nestMembers != null) { - this.nestMembers.clear(); - } - if (this.bootstrapMethods != null) { - this.bootstrapMethods.clear(); - } - this.missingTypes = null; - this.visitedTypes = null; - } - - /** - * Resize the pool contents - */ - private final void resizeContents(int minimalSize) { - int length = this.contents.length; - int toAdd = length; - if (toAdd < minimalSize) - toAdd = minimalSize; - System.arraycopy(this.contents, 0, this.contents = new byte[length + toAdd], 0, length); - } - - private VerificationTypeInfo retrieveLocal(int currentPC, int resolvedPosition) { - for (int i = 0, max = this.codeStream.allLocalsCounter; i < max; i++) { - LocalVariableBinding localVariable = this.codeStream.locals[i]; - if (localVariable == null) continue; - if (resolvedPosition == localVariable.resolvedPosition) { - inits: for (int j = 0; j < localVariable.initializationCount; j++) { - int startPC = localVariable.initializationPCs[j << 1]; - int endPC = localVariable.initializationPCs[(j << 1) + 1]; - if (currentPC < startPC) { - continue inits; - } else if (currentPC < endPC) { - // the current local is an active local - return new VerificationTypeInfo(localVariable.type); - } - } - } - } - return null; - } - - private int scanType(char[] methodSignature, int index) { - switch (methodSignature[index]) { - case '[': - // array type - return scanType(methodSignature, index + 1); - case 'L': - return CharOperation.indexOf(';', methodSignature, index + 1); - case 'Z': - case 'B': - case 'C': - case 'D': - case 'F': - case 'I': - case 'J': - case 'S': - return index; - default: - throw newIllegalArgumentException(methodSignature, index); - } - } - - private static IllegalArgumentException newIllegalArgumentException(char[] string, int index) { - return new IllegalArgumentException("\"" + String.valueOf(string) + "\" at " + index); //$NON-NLS-1$ //$NON-NLS-2$ - } - - /** - * INTERNAL USE-ONLY - * This methods leaves the space for method counts recording. - */ - public void setForMethodInfos() { - // leave some space for the methodCount - this.methodCountOffset = this.contentsOffset; - this.contentsOffset += 2; - } - - private List filterFakeFrames(Set realJumpTargets, Map frames, int codeLength) { - // no more frame to generate - // filter out "fake" frames - realJumpTargets.remove(Integer.valueOf(codeLength)); - List result = new ArrayList<>(); - for (Iterator iterator = realJumpTargets.iterator(); iterator.hasNext(); ) { - Integer jumpTarget = iterator.next(); - StackMapFrame frame = frames.get(jumpTarget); - if (frame != null) { - result.add(frame); - } - } - Collections.sort(result, new Comparator() { - @Override - public int compare(StackMapFrame frame, StackMapFrame frame2) { - return frame.pc - frame2.pc; - } - }); - return result; - } - - private TypeBinding getTypeBinding(char[] typeConstantPoolName, Scope scope, boolean checkcast) { - if (typeConstantPoolName.length == 1 && !checkcast) { - // base type - switch(typeConstantPoolName[0]) { - case 'Z': - return TypeBinding.BOOLEAN; - case 'B': - return TypeBinding.BYTE; - case 'C': - return TypeBinding.CHAR; - case 'D': - return TypeBinding.DOUBLE; - case 'F': - return TypeBinding.FLOAT; - case 'I': - return TypeBinding.INT; - case 'J': - return TypeBinding.LONG; - case 'S': - return TypeBinding.SHORT; - default: - return null; - } - } else if (typeConstantPoolName[0] == '[') { - int dimensions = getDimensions(typeConstantPoolName); - if (typeConstantPoolName.length - dimensions == 1) { - // array of base types - TypeBinding baseType = null; - switch(typeConstantPoolName[typeConstantPoolName.length - 1]) { - case 'Z': - baseType = TypeBinding.BOOLEAN; - break; - case 'B': - baseType = TypeBinding.BYTE; - break; - case 'C': - baseType = TypeBinding.CHAR; - break; - case 'D': - baseType = TypeBinding.DOUBLE; - break; - case 'F': - baseType = TypeBinding.FLOAT; - break; - case 'I': - baseType = TypeBinding.INT; - break; - case 'J': - baseType = TypeBinding.LONG; - break; - case 'S': - baseType = TypeBinding.SHORT; - break; - case 'V': - baseType = TypeBinding.VOID; - } - return scope.createArrayType(baseType, dimensions); - } else { - // array of object types - char[] typeName = CharOperation.subarray(typeConstantPoolName, dimensions + 1, typeConstantPoolName.length - 1); - TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName)); - if (!type.isValidBinding()) { - ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; - if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0 - || (problemReferenceBinding.problemId() & ProblemReasons.NotVisible) != 0) { - type = problemReferenceBinding.closestMatch(); - } else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) { - // check local inner types to see if this is a anonymous type - Set innerTypeBindings = this.innerClassesBindings.keySet(); - for (TypeBinding binding : innerTypeBindings) { - if (CharOperation.equals(binding.constantPoolName(), typeName)) { - type = binding; - break; - } - } - } - } - return scope.createArrayType(type, dimensions); - } - } else { - char[] typeName = checkcast ? typeConstantPoolName : CharOperation.subarray(typeConstantPoolName, 1, typeConstantPoolName.length - 1); - TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName)); - if (!type.isValidBinding()) { - ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; - if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0 - || (problemReferenceBinding.problemId() & ProblemReasons.NotVisible) != 0) { - type = problemReferenceBinding.closestMatch(); - } else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) { - // check local inner types to see if this is a anonymous type - Set innerTypeBindings = this.innerClassesBindings.keySet(); - for (TypeBinding binding : innerTypeBindings) { - if (CharOperation.equals(binding.constantPoolName(), typeName)) { - type = binding; - break; - } - } - } - } - return type; - } - } - - private TypeBinding getNewTypeBinding(char[] typeConstantPoolName, Scope scope) { - char[] typeName = typeConstantPoolName; - if (this.innerClassesBindings != null && isLikelyLocalTypeName(typeName)) { - // find local type in innerClassesBindings: - Set innerTypeBindings = this.innerClassesBindings.keySet(); - for (TypeBinding binding : innerTypeBindings) { - if (CharOperation.equals(binding.constantPoolName(), typeName)) - return binding; - } - } - TypeBinding type = (TypeBinding) scope.getTypeOrPackage(CharOperation.splitOn('/', typeName)); - if (!type.isValidBinding()) { - ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; - if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0 - || (problemReferenceBinding.problemId() & ProblemReasons.NotVisible) != 0) { - type = problemReferenceBinding.closestMatch(); - } - } - return type; - } - - private boolean isLikelyLocalTypeName(char[] typeName) { - int dollarPos = CharOperation.lastIndexOf('$', typeName); - while (dollarPos != -1 && dollarPos+1 < typeName.length) { - if (Character.isDigit(typeName[dollarPos+1])) - return true; // name segment starts with a digit => likely a local type (but still "$0" etc. could be part of the source name) - dollarPos = CharOperation.lastIndexOf('$', typeName, 0, dollarPos-1); - } - return false; - } - - private TypeBinding getANewArrayTypeBinding(char[] typeConstantPoolName, Scope scope) { - if (typeConstantPoolName[0] == '[') { - int dimensions = getDimensions(typeConstantPoolName); - if (typeConstantPoolName.length - dimensions == 1) { - // array of base types - TypeBinding baseType = null; - switch(typeConstantPoolName[typeConstantPoolName.length - 1]) { - case 'Z': - baseType = TypeBinding.BOOLEAN; - break; - case 'B': - baseType = TypeBinding.BYTE; - break; - case 'C': - baseType = TypeBinding.CHAR; - break; - case 'D': - baseType = TypeBinding.DOUBLE; - break; - case 'F': - baseType = TypeBinding.FLOAT; - break; - case 'I': - baseType = TypeBinding.INT; - break; - case 'J': - baseType = TypeBinding.LONG; - break; - case 'S': - baseType = TypeBinding.SHORT; - break; - case 'V': - baseType = TypeBinding.VOID; - } - return scope.createArrayType(baseType, dimensions); - } else { - // array of object types - char[] elementTypeClassName = CharOperation.subarray(typeConstantPoolName, dimensions + 1, typeConstantPoolName.length - 1); - TypeBinding type = (TypeBinding) scope.getTypeOrPackage( - CharOperation.splitOn('/', elementTypeClassName)); - if (!type.isValidBinding()) { - ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; - if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0 - || (problemReferenceBinding.problemId() & ProblemReasons.NotVisible) != 0) { - type = problemReferenceBinding.closestMatch(); - } else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) { - // check local inner types to see if this is a anonymous type - Set innerTypeBindings = this.innerClassesBindings.keySet(); - for (TypeBinding binding : innerTypeBindings) { - if (CharOperation.equals(binding.constantPoolName(), elementTypeClassName)) { - type = binding; - break; - } - } - } - } - return scope.createArrayType(type, dimensions); - } - } else { - TypeBinding type = (TypeBinding) scope.getTypeOrPackage( - CharOperation.splitOn('/', typeConstantPoolName)); - if (!type.isValidBinding()) { - ProblemReferenceBinding problemReferenceBinding = (ProblemReferenceBinding) type; - if ((problemReferenceBinding.problemId() & ProblemReasons.InternalNameProvided) != 0 - || (problemReferenceBinding.problemId() & ProblemReasons.NotVisible) != 0) { - type = problemReferenceBinding.closestMatch(); - } else if ((problemReferenceBinding.problemId() & ProblemReasons.NotFound) != 0 && this.innerClassesBindings != null) { - // check local inner types to see if this is a anonymous type - Set innerTypeBindings = this.innerClassesBindings.keySet(); - for (TypeBinding binding : innerTypeBindings) { - if (CharOperation.equals(binding.constantPoolName(), typeConstantPoolName)) { - type = binding; - break; - } - } - } - } - return type; - } - } - - public List traverse( - MethodBinding methodBinding, - int maxLocals, - byte[] bytecodes, - int codeOffset, - int codeLength, - Map frames, - boolean isClinit, - Scope scope) { - Set realJumpTarget = new HashSet<>(); - - StackMapFrameCodeStream stackMapFrameCodeStream = (StackMapFrameCodeStream) this.codeStream; - int[] framePositions = stackMapFrameCodeStream.getFramePositions(); - int pc = codeOffset; - int index; - int[] constantPoolOffsets = this.constantPool.offsets; - byte[] poolContents = this.constantPool.poolContent; - - // set initial values for frame positions - int indexInFramePositions = 0; - int framePositionsLength = framePositions.length; - int currentFramePosition = framePositions[0]; - - // set initial values for exception markers - int indexInExceptionMarkers = 0; - ExceptionMarker[] exceptionMarkers= stackMapFrameCodeStream.getExceptionMarkers(); - int exceptionsMarkersLength = exceptionMarkers == null ? 0 : exceptionMarkers.length; - boolean hasExceptionMarkers = exceptionsMarkersLength != 0; - ExceptionMarker exceptionMarker = null; - if (hasExceptionMarkers) { - exceptionMarker = exceptionMarkers[0]; - } - - StackMapFrame frame = new StackMapFrame(maxLocals); - if (!isClinit) { - initializeDefaultLocals(frame, methodBinding, maxLocals, codeLength); - } - frame.pc = -1; - add(frames, frame.duplicate(), scope); - addRealJumpTarget(realJumpTarget, -1); - for (int i = 0, max = this.codeStream.exceptionLabelsCounter; i < max; i++) { - ExceptionLabel exceptionLabel = this.codeStream.exceptionLabels[i]; - if (exceptionLabel != null) { - addRealJumpTarget(realJumpTarget, exceptionLabel.position); - } - } - while (true) { - int currentPC = pc - codeOffset; - if (hasExceptionMarkers && exceptionMarker.pc == currentPC) { - frame.numberOfStackItems = 0; - frame.addStackItem(new VerificationTypeInfo(exceptionMarker.getBinding())); - indexInExceptionMarkers++; - if (indexInExceptionMarkers < exceptionsMarkersLength) { - exceptionMarker = exceptionMarkers[indexInExceptionMarkers]; - } else { - hasExceptionMarkers = false; - } - } - if (currentFramePosition < currentPC) { - do { - indexInFramePositions++; - if (indexInFramePositions < framePositionsLength) { - currentFramePosition = framePositions[indexInFramePositions]; - } else { - currentFramePosition = Integer.MAX_VALUE; - } - } while (currentFramePosition < currentPC); - } - if (currentFramePosition == currentPC) { - // need to build a new frame and create a stack map attribute entry - StackMapFrame currentFrame = frames.get(Integer.valueOf(currentPC)); - if (currentFrame == null) { - currentFrame = createNewFrame(currentPC, frame, isClinit, methodBinding); - add(frames, currentFrame, scope); - } else { - frame = currentFrame.merge(frame.duplicate(), scope).duplicate(); - } - indexInFramePositions++; - if (indexInFramePositions < framePositionsLength) { - currentFramePosition = framePositions[indexInFramePositions]; - } else { - currentFramePosition = Integer.MAX_VALUE; - } - } - byte opcode = (byte) u1At(bytecodes, 0, pc); - inspectFrame(currentPC, frame); - switch (opcode) { - case Opcodes.OPC_nop: - pc++; - break; - case Opcodes.OPC_aconst_null: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.NULL)); - pc++; - break; - case Opcodes.OPC_iconst_m1: - case Opcodes.OPC_iconst_0: - case Opcodes.OPC_iconst_1: - case Opcodes.OPC_iconst_2: - case Opcodes.OPC_iconst_3: - case Opcodes.OPC_iconst_4: - case Opcodes.OPC_iconst_5: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); - pc++; - break; - case Opcodes.OPC_lconst_0: - case Opcodes.OPC_lconst_1: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); - pc++; - break; - case Opcodes.OPC_fconst_0: - case Opcodes.OPC_fconst_1: - case Opcodes.OPC_fconst_2: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); - pc++; - break; - case Opcodes.OPC_dconst_0: - case Opcodes.OPC_dconst_1: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); - pc++; - break; - case Opcodes.OPC_bipush: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.BYTE)); - pc += 2; - break; - case Opcodes.OPC_sipush: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.SHORT)); - pc += 3; - break; - case Opcodes.OPC_ldc: - index = u1At(bytecodes, 1, pc); - switch (u1At(poolContents, 0, constantPoolOffsets[index])) { - case ClassFileConstants.StringTag: - frame - .addStackItem(new VerificationTypeInfo(scope.getJavaLangString())); - break; - case ClassFileConstants.IntegerTag: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); - break; - case ClassFileConstants.FloatTag: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); - break; - case ClassFileConstants.ClassTag: - frame.addStackItem(new VerificationTypeInfo(scope.getJavaLangClass())); - } - pc += 2; - break; - case Opcodes.OPC_ldc_w: - index = u2At(bytecodes, 1, pc); - switch (u1At(poolContents, 0, constantPoolOffsets[index])) { - case ClassFileConstants.StringTag: - frame - .addStackItem(new VerificationTypeInfo(scope.getJavaLangString())); - break; - case ClassFileConstants.IntegerTag: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); - break; - case ClassFileConstants.FloatTag: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); - break; - case ClassFileConstants.ClassTag: - frame.addStackItem(new VerificationTypeInfo(scope.getJavaLangClass())); - } - pc += 3; - break; - case Opcodes.OPC_ldc2_w: - index = u2At(bytecodes, 1, pc); - switch (u1At(poolContents, 0, constantPoolOffsets[index])) { - case ClassFileConstants.DoubleTag: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); - break; - case ClassFileConstants.LongTag: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); - break; - } - pc += 3; - break; - case Opcodes.OPC_iload: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); - pc += 2; - break; - case Opcodes.OPC_lload: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); - pc += 2; - break; - case Opcodes.OPC_fload: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); - pc += 2; - break; - case Opcodes.OPC_dload: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); - pc += 2; - break; - case Opcodes.OPC_aload: - index = u1At(bytecodes, 1, pc); - VerificationTypeInfo localsN = retrieveLocal(currentPC, index); - frame.addStackItem(localsN); - pc += 2; - break; - case Opcodes.OPC_iload_0: - case Opcodes.OPC_iload_1: - case Opcodes.OPC_iload_2: - case Opcodes.OPC_iload_3: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); - pc++; - break; - case Opcodes.OPC_lload_0: - case Opcodes.OPC_lload_1: - case Opcodes.OPC_lload_2: - case Opcodes.OPC_lload_3: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); - pc++; - break; - case Opcodes.OPC_fload_0: - case Opcodes.OPC_fload_1: - case Opcodes.OPC_fload_2: - case Opcodes.OPC_fload_3: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); - pc++; - break; - case Opcodes.OPC_dload_0: - case Opcodes.OPC_dload_1: - case Opcodes.OPC_dload_2: - case Opcodes.OPC_dload_3: - frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); - pc++; - break; - case Opcodes.OPC_aload_0: - VerificationTypeInfo locals0 = frame.locals[0]; - if (locals0 == null || locals0.tag != VerificationTypeInfo.ITEM_UNINITIALIZED_THIS) { - // special case to handle uninitialized object - locals0 = retrieveLocal(currentPC, 0); - } - frame.addStackItem(locals0); - pc++; - break; - case Opcodes.OPC_aload_1: - VerificationTypeInfo locals1 = retrieveLocal(currentPC, 1); - frame.addStackItem(locals1); - pc++; - break; - case Opcodes.OPC_aload_2: - VerificationTypeInfo locals2 = retrieveLocal(currentPC, 2); - frame.addStackItem(locals2); - pc++; - break; - case Opcodes.OPC_aload_3: - VerificationTypeInfo locals3 = retrieveLocal(currentPC, 3); - frame.addStackItem(locals3); - pc++; - break; - case Opcodes.OPC_iaload: - frame.numberOfStackItems -=2; - frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); - pc++; - break; - case Opcodes.OPC_laload: - frame.numberOfStackItems -=2; - frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); - pc++; - break; - case Opcodes.OPC_faload: - frame.numberOfStackItems -=2; - frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); - pc++; - break; - case Opcodes.OPC_daload: - frame.numberOfStackItems -=2; - frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); - pc++; - break; - case Opcodes.OPC_aaload: - frame.numberOfStackItems--; - frame.replaceWithElementType(); - pc++; - break; - case Opcodes.OPC_baload: - frame.numberOfStackItems -=2; - frame.addStackItem(new VerificationTypeInfo(TypeBinding.BYTE)); - pc++; - break; - case Opcodes.OPC_caload: - frame.numberOfStackItems -=2; - frame.addStackItem(new VerificationTypeInfo(TypeBinding.CHAR)); - pc++; - break; - case Opcodes.OPC_saload: - frame.numberOfStackItems -=2; - frame.addStackItem(new VerificationTypeInfo(TypeBinding.SHORT)); - pc++; - break; - case Opcodes.OPC_istore: - case Opcodes.OPC_lstore: - case Opcodes.OPC_fstore: - case Opcodes.OPC_dstore: - frame.numberOfStackItems--; - pc += 2; - break; - case Opcodes.OPC_astore: - index = u1At(bytecodes, 1, pc); - frame.numberOfStackItems--; - pc += 2; - break; - case Opcodes.OPC_astore_0: - frame.locals[0] = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - pc++; - break; - case Opcodes.OPC_astore_1: - case Opcodes.OPC_astore_2: - case Opcodes.OPC_astore_3: - case Opcodes.OPC_istore_0: - case Opcodes.OPC_istore_1: - case Opcodes.OPC_istore_2: - case Opcodes.OPC_istore_3: - case Opcodes.OPC_lstore_0: - case Opcodes.OPC_lstore_1: - case Opcodes.OPC_lstore_2: - case Opcodes.OPC_lstore_3: - case Opcodes.OPC_fstore_0: - case Opcodes.OPC_fstore_1: - case Opcodes.OPC_fstore_2: - case Opcodes.OPC_fstore_3: - case Opcodes.OPC_dstore_0: - case Opcodes.OPC_dstore_1: - case Opcodes.OPC_dstore_2: - case Opcodes.OPC_dstore_3: - frame.numberOfStackItems--; - pc++; - break; - case Opcodes.OPC_iastore: - case Opcodes.OPC_lastore: - case Opcodes.OPC_fastore: - case Opcodes.OPC_dastore: - case Opcodes.OPC_aastore: - case Opcodes.OPC_bastore: - case Opcodes.OPC_castore: - case Opcodes.OPC_sastore: - frame.numberOfStackItems-=3; - pc++; - break; - case Opcodes.OPC_pop: - frame.numberOfStackItems--; - pc++; - break; - case Opcodes.OPC_pop2: - int numberOfStackItems = frame.numberOfStackItems; - switch(frame.stackItems[numberOfStackItems - 1].id()) { - case TypeIds.T_long : - case TypeIds.T_double : - frame.numberOfStackItems--; - break; - default: - frame.numberOfStackItems -= 2; - } - pc++; - break; - case Opcodes.OPC_dup: - frame.addStackItem(frame.stackItems[frame.numberOfStackItems - 1]); - pc++; - break; - case Opcodes.OPC_dup_x1: - VerificationTypeInfo info = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - VerificationTypeInfo info2 = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - frame.addStackItem(info); - frame.addStackItem(info2); - frame.addStackItem(info); - pc++; - break; - case Opcodes.OPC_dup_x2: - info = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - info2 = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - switch(info2.id()) { - case TypeIds.T_long : - case TypeIds.T_double : - frame.addStackItem(info); - frame.addStackItem(info2); - frame.addStackItem(info); - break; - default: - numberOfStackItems = frame.numberOfStackItems; - VerificationTypeInfo info3 = frame.stackItems[numberOfStackItems - 1]; - frame.numberOfStackItems--; - frame.addStackItem(info); - frame.addStackItem(info3); - frame.addStackItem(info2); - frame.addStackItem(info); - } - pc++; - break; - case Opcodes.OPC_dup2: - info = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - switch(info.id()) { - case TypeIds.T_double : - case TypeIds.T_long : - frame.addStackItem(info); - frame.addStackItem(info); - break; - default: - info2 = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - frame.addStackItem(info2); - frame.addStackItem(info); - frame.addStackItem(info2); - frame.addStackItem(info); - } - pc++; - break; - case Opcodes.OPC_dup2_x1: - info = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - info2 = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - switch(info.id()) { - case TypeIds.T_double : - case TypeIds.T_long : - frame.addStackItem(info); - frame.addStackItem(info2); - frame.addStackItem(info); - break; - default: - VerificationTypeInfo info3 = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - frame.addStackItem(info2); - frame.addStackItem(info); - frame.addStackItem(info3); - frame.addStackItem(info2); - frame.addStackItem(info); - } - pc++; - break; - case Opcodes.OPC_dup2_x2: - numberOfStackItems = frame.numberOfStackItems; - info = frame.stackItems[numberOfStackItems - 1]; - frame.numberOfStackItems--; - info2 = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - switch(info.id()) { - case TypeIds.T_long : - case TypeIds.T_double : - switch(info2.id()) { - case TypeIds.T_long : - case TypeIds.T_double : - // form 4 - frame.addStackItem(info); - frame.addStackItem(info2); - frame.addStackItem(info); - break; - default: - // form 2 - numberOfStackItems = frame.numberOfStackItems; - VerificationTypeInfo info3 = frame.stackItems[numberOfStackItems - 1]; - frame.numberOfStackItems--; - frame.addStackItem(info); - frame.addStackItem(info3); - frame.addStackItem(info2); - frame.addStackItem(info); - } - break; - default: - numberOfStackItems = frame.numberOfStackItems; - VerificationTypeInfo info3 = frame.stackItems[numberOfStackItems - 1]; - frame.numberOfStackItems--; - switch(info3.id()) { - case TypeIds.T_long : - case TypeIds.T_double : - // form 3 - frame.addStackItem(info2); - frame.addStackItem(info); - frame.addStackItem(info3); - frame.addStackItem(info2); - frame.addStackItem(info); - break; - default: - // form 1 - numberOfStackItems = frame.numberOfStackItems; - VerificationTypeInfo info4 = frame.stackItems[numberOfStackItems - 1]; - frame.numberOfStackItems--; - frame.addStackItem(info2); - frame.addStackItem(info); - frame.addStackItem(info4); - frame.addStackItem(info3); - frame.addStackItem(info2); - frame.addStackItem(info); - } - } - pc++; - break; - case Opcodes.OPC_swap: - numberOfStackItems = frame.numberOfStackItems; - info = frame.stackItems[numberOfStackItems - 1]; - info2 = frame.stackItems[numberOfStackItems - 2]; - frame.stackItems[numberOfStackItems - 1] = info2; - frame.stackItems[numberOfStackItems - 2] = info; - pc++; - break; - case Opcodes.OPC_iadd: - case Opcodes.OPC_ladd: - case Opcodes.OPC_fadd: - case Opcodes.OPC_dadd: - case Opcodes.OPC_isub: - case Opcodes.OPC_lsub: - case Opcodes.OPC_fsub: - case Opcodes.OPC_dsub: - case Opcodes.OPC_imul: - case Opcodes.OPC_lmul: - case Opcodes.OPC_fmul: - case Opcodes.OPC_dmul: - case Opcodes.OPC_idiv: - case Opcodes.OPC_ldiv: - case Opcodes.OPC_fdiv: - case Opcodes.OPC_ddiv: - case Opcodes.OPC_irem: - case Opcodes.OPC_lrem: - case Opcodes.OPC_frem: - case Opcodes.OPC_drem: - case Opcodes.OPC_ishl: - case Opcodes.OPC_lshl: - case Opcodes.OPC_ishr: - case Opcodes.OPC_lshr: - case Opcodes.OPC_iushr: - case Opcodes.OPC_lushr: - case Opcodes.OPC_iand: - case Opcodes.OPC_land: - case Opcodes.OPC_ior: - case Opcodes.OPC_lor: - case Opcodes.OPC_ixor: - case Opcodes.OPC_lxor: - frame.numberOfStackItems--; - pc++; - break; - case Opcodes.OPC_ineg: - case Opcodes.OPC_lneg: - case Opcodes.OPC_fneg: - case Opcodes.OPC_dneg: - pc++; - break; - case Opcodes.OPC_iinc: - pc += 3; - break; - case Opcodes.OPC_i2l: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.LONG); - pc++; - break; - case Opcodes.OPC_i2f: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.FLOAT); - pc++; - break; - case Opcodes.OPC_i2d: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.DOUBLE); - pc++; - break; - case Opcodes.OPC_l2i: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); - pc++; - break; - case Opcodes.OPC_l2f: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.FLOAT); - pc++; - break; - case Opcodes.OPC_l2d: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.DOUBLE); - pc++; - break; - case Opcodes.OPC_f2i: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); - pc++; - break; - case Opcodes.OPC_f2l: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.LONG); - pc++; - break; - case Opcodes.OPC_f2d: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.DOUBLE); - pc++; - break; - case Opcodes.OPC_d2i: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); - pc++; - break; - case Opcodes.OPC_d2l: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.LONG); - pc++; - break; - case Opcodes.OPC_d2f: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.FLOAT); - pc++; - break; - case Opcodes.OPC_i2b: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.BYTE); - pc++; - break; - case Opcodes.OPC_i2c: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.CHAR); - pc++; - break; - case Opcodes.OPC_i2s: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.SHORT); - pc++; - break; - case Opcodes.OPC_lcmp: - case Opcodes.OPC_fcmpl: - case Opcodes.OPC_fcmpg: - case Opcodes.OPC_dcmpl: - case Opcodes.OPC_dcmpg: - frame.numberOfStackItems-=2; - frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); - pc++; - break; - case Opcodes.OPC_ifeq: - case Opcodes.OPC_ifne: - case Opcodes.OPC_iflt: - case Opcodes.OPC_ifge: - case Opcodes.OPC_ifgt: - case Opcodes.OPC_ifle: - frame.numberOfStackItems--; - int jumpPC = currentPC + i2At(bytecodes, 1, pc); - addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); - pc += 3; - break; - case Opcodes.OPC_if_icmpeq: - case Opcodes.OPC_if_icmpne: - case Opcodes.OPC_if_icmplt: - case Opcodes.OPC_if_icmpge: - case Opcodes.OPC_if_icmpgt: - case Opcodes.OPC_if_icmple: - case Opcodes.OPC_if_acmpeq: - case Opcodes.OPC_if_acmpne: - frame.numberOfStackItems -= 2; - jumpPC = currentPC + i2At(bytecodes, 1, pc); - addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); - pc += 3; - break; - case Opcodes.OPC_goto: - jumpPC = currentPC + i2At(bytecodes, 1, pc); - addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); - pc += 3; - addRealJumpTarget(realJumpTarget, pc - codeOffset); - break; - case Opcodes.OPC_tableswitch: - frame.numberOfStackItems--; - pc++; - while (((pc - codeOffset) & 0x03) != 0) { - pc++; - } - // default offset - jumpPC = currentPC + i4At(bytecodes, 0, pc); - addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); - pc += 4; // default - int low = i4At(bytecodes, 0, pc); - pc += 4; - int high = i4At(bytecodes, 0, pc); - pc += 4; - int length = high - low + 1; - for (int i = 0; i < length; i++) { - // pair offset - jumpPC = currentPC + i4At(bytecodes, 0, pc); - addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); - pc += 4; - } - break; - case Opcodes.OPC_lookupswitch: - frame.numberOfStackItems--; - pc++; - while (((pc - codeOffset) & 0x03) != 0) { - pc++; - } - jumpPC = currentPC + i4At(bytecodes, 0, pc); - addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); - pc += 4; // default offset - int npairs = (int) u4At(bytecodes, 0, pc); - pc += 4; // npair value - for (int i = 0; i < npairs; i++) { - pc += 4; // case value - // pair offset - jumpPC = currentPC + i4At(bytecodes, 0, pc); - addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); - pc += 4; - } - break; - case Opcodes.OPC_ireturn: - case Opcodes.OPC_lreturn: - case Opcodes.OPC_freturn: - case Opcodes.OPC_dreturn: - case Opcodes.OPC_areturn: - frame.numberOfStackItems--; - pc++; - addRealJumpTarget(realJumpTarget, pc - codeOffset); - break; - case Opcodes.OPC_return: - pc++; - addRealJumpTarget(realJumpTarget, pc - codeOffset); - break; - case Opcodes.OPC_getstatic: - index = u2At(bytecodes, 1, pc); - int nameAndTypeIndex = u2At(poolContents, 3, - constantPoolOffsets[index]); - int utf8index = u2At(poolContents, 3, - constantPoolOffsets[nameAndTypeIndex]); - char[] descriptor = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - TypeBinding typeBinding = getTypeBinding(descriptor, scope, false); - if (typeBinding != null) { - frame.addStackItem(new VerificationTypeInfo(typeBinding)); - } - pc += 3; - break; - case Opcodes.OPC_putstatic: - frame.numberOfStackItems--; - pc += 3; - break; - case Opcodes.OPC_getfield: - index = u2At(bytecodes, 1, pc); - nameAndTypeIndex = u2At(poolContents, 3, - constantPoolOffsets[index]); - utf8index = u2At(poolContents, 3, - constantPoolOffsets[nameAndTypeIndex]); - descriptor = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - frame.numberOfStackItems--; - typeBinding = getTypeBinding(descriptor, scope, false); - if (typeBinding != null) { - frame.addStackItem(new VerificationTypeInfo(typeBinding)); - } - pc += 3; - break; - case Opcodes.OPC_putfield: - frame.numberOfStackItems -= 2; - pc += 3; - break; - case Opcodes.OPC_invokevirtual: - index = u2At(bytecodes, 1, pc); - nameAndTypeIndex = u2At(poolContents, 3, - constantPoolOffsets[index]); - utf8index = u2At(poolContents, 3, - constantPoolOffsets[nameAndTypeIndex]); - descriptor = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - utf8index = u2At(poolContents, 1, - constantPoolOffsets[nameAndTypeIndex]); - char[] name = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - frame.numberOfStackItems -= (getParametersCount(descriptor) + 1); - char[] returnType = getReturnType(descriptor); - typeBinding = getTypeBinding(returnType, scope, false); - if (typeBinding != null) { - frame.addStackItem(new VerificationTypeInfo(typeBinding)); - } - pc += 3; - break; - case Opcodes.OPC_invokedynamic: - index = u2At(bytecodes, 1, pc); - nameAndTypeIndex = u2At(poolContents, 3, - constantPoolOffsets[index]); - utf8index = u2At(poolContents, 3, - constantPoolOffsets[nameAndTypeIndex]); - descriptor = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - frame.numberOfStackItems -= getParametersCount(descriptor); - returnType = getReturnType(descriptor); - typeBinding = getTypeBinding(returnType, scope, false); - if (typeBinding != null) { - frame.addStackItem(new VerificationTypeInfo(typeBinding)); - } - pc += 5; - break; - case Opcodes.OPC_invokespecial: - index = u2At(bytecodes, 1, pc); - nameAndTypeIndex = u2At(poolContents, 3, - constantPoolOffsets[index]); - utf8index = u2At(poolContents, 3, - constantPoolOffsets[nameAndTypeIndex]); - descriptor = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - utf8index = u2At(poolContents, 1, - constantPoolOffsets[nameAndTypeIndex]); - name = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - frame.numberOfStackItems -= getParametersCount(descriptor); - if (CharOperation.equals(ConstantPool.Init, name)) { - // constructor - frame.stackItems[frame.numberOfStackItems - 1].tag = VerificationTypeInfo.ITEM_OBJECT; - } - frame.numberOfStackItems--; - returnType = getReturnType(descriptor); - typeBinding = getTypeBinding(returnType, scope, false); - if (typeBinding != null) { - frame.addStackItem(new VerificationTypeInfo(typeBinding)); - } - pc += 3; - break; - case Opcodes.OPC_invokestatic: - index = u2At(bytecodes, 1, pc); - nameAndTypeIndex = u2At(poolContents, 3, - constantPoolOffsets[index]); - utf8index = u2At(poolContents, 3, - constantPoolOffsets[nameAndTypeIndex]); - descriptor = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - utf8index = u2At(poolContents, 1, - constantPoolOffsets[nameAndTypeIndex]); - name = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - frame.numberOfStackItems -= getParametersCount(descriptor); - returnType = getReturnType(descriptor); - typeBinding = getTypeBinding(returnType, scope, false); - if (typeBinding != null) { - frame.addStackItem(new VerificationTypeInfo(typeBinding)); - } - pc += 3; - break; - case Opcodes.OPC_invokeinterface: - index = u2At(bytecodes, 1, pc); - nameAndTypeIndex = u2At(poolContents, 3, - constantPoolOffsets[index]); - utf8index = u2At(poolContents, 3, - constantPoolOffsets[nameAndTypeIndex]); - descriptor = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - utf8index = u2At(poolContents, 1, - constantPoolOffsets[nameAndTypeIndex]); - name = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - // we don't need count and args - // u1At(bytecodes, 3, pc); // count - // u1At(bytecodes, 4, pc); // extra args - frame.numberOfStackItems -= (getParametersCount(descriptor) + 1); - returnType = getReturnType(descriptor); - typeBinding = getTypeBinding(returnType, scope, false); - if (typeBinding != null) { - frame.addStackItem(new VerificationTypeInfo(typeBinding)); - } - pc += 5; - break; - case Opcodes.OPC_new: - index = u2At(bytecodes, 1, pc); - utf8index = u2At(poolContents, 1, - constantPoolOffsets[index]); - char[] className = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - typeBinding = getNewTypeBinding(className, scope); - VerificationTypeInfo verificationTypeInfo = new VerificationTypeInfo(VerificationTypeInfo.ITEM_UNINITIALIZED, typeBinding); - verificationTypeInfo.offset = currentPC; - frame.addStackItem(verificationTypeInfo); - pc += 3; - break; - case Opcodes.OPC_newarray: - TypeBinding arrayType = null; - switch (u1At(bytecodes, 1, pc)) { - case ClassFileConstants.INT_ARRAY : - arrayType = scope.createArrayType(TypeBinding.INT, 1); - break; - case ClassFileConstants.BYTE_ARRAY : - arrayType = scope.createArrayType(TypeBinding.BYTE, 1); - break; - case ClassFileConstants.BOOLEAN_ARRAY : - arrayType = scope.createArrayType(TypeBinding.BOOLEAN, 1); - break; - case ClassFileConstants.SHORT_ARRAY : - arrayType = scope.createArrayType(TypeBinding.SHORT, 1); - break; - case ClassFileConstants.CHAR_ARRAY : - arrayType = scope.createArrayType(TypeBinding.CHAR, 1); - break; - case ClassFileConstants.LONG_ARRAY : - arrayType = scope.createArrayType(TypeBinding.LONG, 1); - break; - case ClassFileConstants.FLOAT_ARRAY : - arrayType = scope.createArrayType(TypeBinding.FLOAT, 1); - break; - case ClassFileConstants.DOUBLE_ARRAY : - arrayType = scope.createArrayType(TypeBinding.DOUBLE, 1); - break; - } - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(arrayType); - pc += 2; - break; - case Opcodes.OPC_anewarray: - index = u2At(bytecodes, 1, pc); - utf8index = u2At(poolContents, 1, - constantPoolOffsets[index]); - className = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - frame.numberOfStackItems--; - typeBinding = getANewArrayTypeBinding(className, scope); - if (typeBinding != null) { - if (typeBinding.isArrayType()) { - ArrayBinding arrayBinding = (ArrayBinding) typeBinding; - frame.addStackItem(new VerificationTypeInfo(scope.createArrayType(arrayBinding.leafComponentType(), arrayBinding.dimensions + 1))); - } else { - frame.addStackItem(new VerificationTypeInfo(scope.createArrayType(typeBinding, 1))); - } - } - pc += 3; - break; - case Opcodes.OPC_arraylength: - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); - pc++; - break; - case Opcodes.OPC_athrow: - frame.numberOfStackItems--; - pc++; - addRealJumpTarget(realJumpTarget, pc - codeOffset); - break; - case Opcodes.OPC_checkcast: - index = u2At(bytecodes, 1, pc); - utf8index = u2At(poolContents, 1, - constantPoolOffsets[index]); - className = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - typeBinding = getTypeBinding(className, scope, true); - if (typeBinding != null) { - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(typeBinding); - } - pc += 3; - break; - case Opcodes.OPC_instanceof: - // no need to know the class index = u2At(bytecodes, 1, pc); - frame.stackItems[frame.numberOfStackItems - 1] = new VerificationTypeInfo(TypeBinding.INT); - pc += 3; - break; - case Opcodes.OPC_monitorenter: - case Opcodes.OPC_monitorexit: - frame.numberOfStackItems--; - pc++; - break; - case Opcodes.OPC_wide: - opcode = (byte) u1At(bytecodes, 1, pc); - if (opcode == Opcodes.OPC_iinc) { - // index = u2At(bytecodes, 2, pc); - // i2At(bytecodes, 4, pc); // const - // we don't need the index and the const value - pc += 6; - } else { - index = u2At(bytecodes, 2, pc); - // need to handle iload, fload, aload, lload, dload, istore, fstore, astore, lstore or dstore - switch(opcode) { - case Opcodes.OPC_iload : - frame.addStackItem(new VerificationTypeInfo(TypeBinding.INT)); - break; - case Opcodes.OPC_fload : - frame.addStackItem(new VerificationTypeInfo(TypeBinding.FLOAT)); - break; - case Opcodes.OPC_aload : - localsN = frame.locals[index]; - if (localsN == null) { - localsN = retrieveLocal(currentPC, index); - } - frame.addStackItem(localsN); - break; - case Opcodes.OPC_lload : - frame.addStackItem(new VerificationTypeInfo(TypeBinding.LONG)); - break; - case Opcodes.OPC_dload : - frame.addStackItem(new VerificationTypeInfo(TypeBinding.DOUBLE)); - break; - case Opcodes.OPC_istore : - frame.numberOfStackItems--; - break; - case Opcodes.OPC_fstore : - frame.numberOfStackItems--; - break; - case Opcodes.OPC_astore : - frame.locals[index] = frame.stackItems[frame.numberOfStackItems - 1]; - frame.numberOfStackItems--; - break; - case Opcodes.OPC_lstore : - frame.numberOfStackItems--; - break; - case Opcodes.OPC_dstore : - frame.numberOfStackItems--; - break; - } - pc += 4; - } - break; - case Opcodes.OPC_multianewarray: - index = u2At(bytecodes, 1, pc); - utf8index = u2At(poolContents, 1, - constantPoolOffsets[index]); - className = utf8At(poolContents, - constantPoolOffsets[utf8index] + 3, u2At( - poolContents, 1, - constantPoolOffsets[utf8index])); - int dimensions = u1At(bytecodes, 3, pc); // dimensions - frame.numberOfStackItems -= dimensions; - // class name is already the name of the right array type with all dimensions - typeBinding = getTypeBinding(className, scope, false); - if (typeBinding != null) { - frame.addStackItem(new VerificationTypeInfo(typeBinding)); - } - pc += 4; - break; - case Opcodes.OPC_ifnull: - case Opcodes.OPC_ifnonnull: - frame.numberOfStackItems--; - jumpPC = currentPC + i2At(bytecodes, 1, pc); - addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); - pc += 3; - break; - case Opcodes.OPC_goto_w: - jumpPC = currentPC + i4At(bytecodes, 1, pc); - addRealJumpTarget(realJumpTarget, jumpPC, frames, createNewFrame(jumpPC, frame, isClinit, methodBinding), scope); - pc += 5; - addRealJumpTarget(realJumpTarget, pc - codeOffset); // handle infinite loop - break; - default: // should not occur - if (this.codeStream.methodDeclaration != null) { - this.codeStream.methodDeclaration.scope.problemReporter().abortDueToInternalError( - Messages.bind( - Messages.abort_invalidOpcode, - new Object[] { - Byte.valueOf(opcode), - Integer.valueOf(pc), - new String(methodBinding.shortReadableName()), - }), - this.codeStream.methodDeclaration); - } else { - this.codeStream.lambdaExpression.scope.problemReporter().abortDueToInternalError( - Messages.bind( - Messages.abort_invalidOpcode, - new Object[] { - Byte.valueOf(opcode), - Integer.valueOf(pc), - new String(methodBinding.shortReadableName()), - }), - this.codeStream.lambdaExpression); - } - break; - } - if (pc >= (codeLength + codeOffset)) { - break; - } - } - return filterFakeFrames(realJumpTarget, frames, codeLength); - } - - private void inspectFrame(int currentPC, StackMapFrame frame) { - // Plant a breakpoint at the call site to conveniently hover. - } - - private StackMapFrame createNewFrame(int currentPC, StackMapFrame frame, boolean isClinit, MethodBinding methodBinding) { - StackMapFrame newFrame = frame.duplicate(); - newFrame.pc = currentPC; - // initialize locals - initializeLocals(isClinit ? true : methodBinding.isStatic(), currentPC, newFrame); - return newFrame; - } - - private int getDimensions(char[] returnType) { - int dimensions = 0; - while (returnType[dimensions] == '[') { - dimensions++; - } - return dimensions; - } - - private void addRealJumpTarget(Set realJumpTarget, int pc) { - realJumpTarget.add(Integer.valueOf(pc)); - } - - private void addRealJumpTarget(Set realJumpTarget, int pc, Map frames, StackMapFrame frame, Scope scope) { - realJumpTarget.add(Integer.valueOf(pc)); - add(frames, frame, scope); - } - - private void add(Map frames, StackMapFrame frame, Scope scope) { - Integer key = Integer.valueOf(frame.pc); - StackMapFrame existingFrame = frames.get(key); - if(existingFrame == null) { - frames.put(key, frame); - } else { - // we need to merge - frames.put(key, existingFrame.merge(frame, scope)); - } - } - - private final int u1At(byte[] reference, int relativeOffset, - int structOffset) { - return (reference[relativeOffset + structOffset] & 0xFF); - } - - private final int u2At(byte[] reference, int relativeOffset, - int structOffset) { - int position = relativeOffset + structOffset; - return ((reference[position++] & 0xFF) << 8) - + (reference[position] & 0xFF); - } - - private final long u4At(byte[] reference, int relativeOffset, - int structOffset) { - int position = relativeOffset + structOffset; - return (((reference[position++] & 0xFFL) << 24) - + ((reference[position++] & 0xFF) << 16) - + ((reference[position++] & 0xFF) << 8) + (reference[position] & 0xFF)); - } - - private final int i2At(byte[] reference, int relativeOffset, int structOffset) { - int position = relativeOffset + structOffset; - return (reference[position++] << 8) + (reference[position] & 0xFF); - } - - public char[] utf8At(byte[] reference, int absoluteOffset, - int bytesAvailable) { - int length = bytesAvailable; - char outputBuf[] = new char[bytesAvailable]; - int outputPos = 0; - int readOffset = absoluteOffset; - - while (length != 0) { - int x = reference[readOffset++] & 0xFF; - length--; - if ((0x80 & x) != 0) { - if ((x & 0x20) != 0) { - length -= 2; - x = ((x & 0xF) << 12) - | ((reference[readOffset++] & 0x3F) << 6) - | (reference[readOffset++] & 0x3F); - } else { - length--; - x = ((x & 0x1F) << 6) | (reference[readOffset++] & 0x3F); - } - } - outputBuf[outputPos++] = (char) x; - } - - if (outputPos != bytesAvailable) { - System.arraycopy(outputBuf, 0, (outputBuf = new char[outputPos]), - 0, outputPos); - } - return outputBuf; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ClassFilePool.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ClassFilePool.java deleted file mode 100644 index 7c0c8fa..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ClassFilePool.java +++ /dev/null @@ -1,75 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler; - -import java.util.Arrays; - -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; - -public class ClassFilePool { - public static final int POOL_SIZE = 25; // need to have enough for 2 units - ClassFile[] classFiles; - -private ClassFilePool() { - // prevent instantiation - this.classFiles = new ClassFile[POOL_SIZE]; -} - -public static ClassFilePool newInstance() { - return new ClassFilePool(); -} - -public synchronized ClassFile acquire(SourceTypeBinding typeBinding) { - for (int i = 0; i < POOL_SIZE; i++) { - ClassFile classFile = this.classFiles[i]; - if (classFile == null) { - ClassFile newClassFile = new ClassFile(typeBinding); - this.classFiles[i] = newClassFile; - newClassFile.isShared = true; - return newClassFile; - } - if (!classFile.isShared) { - classFile.reset(typeBinding, typeBinding.scope.compilerOptions()); - classFile.isShared = true; - return classFile; - } - } - return new ClassFile(typeBinding); -} -public synchronized ClassFile acquireForModule(ModuleBinding moduleBinding, CompilerOptions options) { - for (int i = 0; i < POOL_SIZE; i++) { - ClassFile classFile = this.classFiles[i]; - if (classFile == null) { - ClassFile newClassFile = new ClassFile(moduleBinding, options); - this.classFiles[i] = newClassFile; - newClassFile.isShared = true; - return newClassFile; - } - if (!classFile.isShared) { - classFile.reset(null, options); - classFile.isShared = true; - return classFile; - } - } - return new ClassFile(moduleBinding, options); -} -public synchronized void release(ClassFile classFile) { - classFile.isShared = false; -} -public void reset() { - Arrays.fill(this.classFiles, null); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/CompilationResult.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/CompilationResult.java deleted file mode 100644 index fff9399..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/CompilationResult.java +++ /dev/null @@ -1,494 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Christoph Läubrich - Enhance the BuildContext with the discovered annotations #674 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler; - -import java.util.ArrayList; -/** - * A compilation result consists of all information returned by the compiler for - * a single compiled compilation source unit. This includes: - *
    - *
  • the compilation unit that was compiled - *
  • for each type produced by compiling the compilation unit, its binary and optionally its principal structure - *
  • any problems (errors or warnings) produced - *
  • dependency info - *
- * - * The principle structure and binary may be null if the compiler could not produce them. - * If neither could be produced, there is no corresponding entry for the type. - * - * The dependency info includes type references such as supertypes, field types, method - * parameter and return types, local variable types, types of intermediate expressions, etc. - * It also includes the namespaces (packages) in which names were looked up. - * It does not include finer grained dependencies such as information about - * specific fields and methods which were referenced, but does contain their - * declaring types and any other types used to locate such fields or methods. - */ -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jdt.core.compiler.CategorizedProblem; -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; -import org.eclipse.jdt.internal.compiler.util.Util; - -@SuppressWarnings({ "rawtypes", "unchecked" }) -public class CompilationResult { - - public CategorizedProblem problems[]; - public CategorizedProblem tasks[]; - public int problemCount; - public int taskCount; - public ICompilationUnit compilationUnit; - private Map problemsMap; - private Set firstErrors; - private final int maxProblemPerUnit; - public char[][][] qualifiedReferences; - public char[][] simpleNameReferences; - public char[][] rootReferences; - public boolean hasAnnotations = false; - public boolean hasFunctionalTypes = false; - public int lineSeparatorPositions[]; - public RecoveryScannerData recoveryScannerData; - public Map compiledTypes = new Hashtable(11); - public int unitIndex, totalUnitsKnown; - public boolean hasBeenAccepted = false; - public char[] fileName; - public boolean hasInconsistentToplevelHierarchies = false; // record the fact some toplevel types have inconsistent hierarchies - public boolean hasSyntaxError = false; - public char[][] packageName; - public boolean checkSecondaryTypes = false; // check for secondary types which were created after the initial buildTypeBindings call - private int numberOfErrors; - private boolean hasMandatoryErrors; - public List annotations = new ArrayList<>(1); - private List scheduledProblems; - - private static final int[] EMPTY_LINE_ENDS = Util.EMPTY_INT_ARRAY; - private static final Comparator PROBLEM_COMPARATOR = new Comparator() { - @Override - public int compare(Object o1, Object o2) { - return ((CategorizedProblem) o1).getSourceStart() - ((CategorizedProblem) o2).getSourceStart(); - } - }; - -public CompilationResult(char[] fileName, int unitIndex, int totalUnitsKnown, int maxProblemPerUnit){ - this.fileName = fileName; - this.unitIndex = unitIndex; - this.totalUnitsKnown = totalUnitsKnown; - this.maxProblemPerUnit = maxProblemPerUnit; -} - -public CompilationResult(ICompilationUnit compilationUnit, int unitIndex, int totalUnitsKnown, int maxProblemPerUnit){ - this.fileName = compilationUnit.getFileName(); - this.compilationUnit = compilationUnit; - this.unitIndex = unitIndex; - this.totalUnitsKnown = totalUnitsKnown; - this.maxProblemPerUnit = maxProblemPerUnit; -} - -private int computePriority(CategorizedProblem problem){ - final int P_STATIC = 10000; - final int P_OUTSIDE_METHOD = 40000; - final int P_FIRST_ERROR = 20000; - final int P_ERROR = 100000; - - int priority = 10000 - problem.getSourceLineNumber(); // early problems first - if (priority < 0) priority = 0; - if (problem.isError()){ - priority += P_ERROR; - } - ReferenceContext context = this.problemsMap == null ? null : this.problemsMap.get(problem); - if (context != null){ - if (context instanceof AbstractMethodDeclaration){ - AbstractMethodDeclaration method = (AbstractMethodDeclaration) context; - if (method.isStatic()) { - priority += P_STATIC; - } - } else { - priority += P_OUTSIDE_METHOD; - } - if (this.firstErrors.contains(problem)){ // if context is null, firstErrors is null too - priority += P_FIRST_ERROR; - } - } else { - priority += P_OUTSIDE_METHOD; - } - return priority; -} - -public CategorizedProblem[] getAllProblems() { - CategorizedProblem[] onlyProblems = getProblems(); - int onlyProblemCount = onlyProblems != null ? onlyProblems.length : 0; - CategorizedProblem[] onlyTasks = getTasks(); - int onlyTaskCount = onlyTasks != null ? onlyTasks.length : 0; - if (onlyTaskCount == 0) { - return onlyProblems; - } - if (onlyProblemCount == 0) { - return onlyTasks; - } - int totalNumberOfProblem = onlyProblemCount + onlyTaskCount; - CategorizedProblem[] allProblems = new CategorizedProblem[totalNumberOfProblem]; - int allProblemIndex = 0; - int taskIndex = 0; - int problemIndex = 0; - while (taskIndex + problemIndex < totalNumberOfProblem) { - CategorizedProblem nextTask = null; - CategorizedProblem nextProblem = null; - if (taskIndex < onlyTaskCount) { - nextTask = onlyTasks[taskIndex]; - } - if (problemIndex < onlyProblemCount) { - nextProblem = onlyProblems[problemIndex]; - } - // select the next problem - CategorizedProblem currentProblem = null; - if (nextProblem != null) { - if (nextTask != null) { - if (nextProblem.getSourceStart() < nextTask.getSourceStart()) { - currentProblem = nextProblem; - problemIndex++; - } else { - currentProblem = nextTask; - taskIndex++; - } - } else { - currentProblem = nextProblem; - problemIndex++; - } - } else { - if (nextTask != null) { - currentProblem = nextTask; - taskIndex++; - } - } - allProblems[allProblemIndex++] = currentProblem; - } - return allProblems; -} - -public ClassFile[] getClassFiles() { - ClassFile[] classFiles = new ClassFile[this.compiledTypes.size()]; - this.compiledTypes.values().toArray(classFiles); - return classFiles; -} - -/** - * Answer the initial compilation unit corresponding to the present compilation result - */ -public ICompilationUnit getCompilationUnit(){ - return this.compilationUnit; -} - -/** - * Answer the errors encountered during compilation. - */ -public CategorizedProblem[] getErrors() { - CategorizedProblem[] reportedProblems = getProblems(); - int errorCount = 0; - for (int i = 0; i < this.problemCount; i++) { - if (reportedProblems[i].isError()) errorCount++; - } - if (errorCount == this.problemCount) return reportedProblems; - CategorizedProblem[] errors = new CategorizedProblem[errorCount]; - int index = 0; - for (int i = 0; i < this.problemCount; i++) { - if (reportedProblems[i].isError()) errors[index++] = reportedProblems[i]; - } - return errors; -} - - -/** - * Answer the initial file name - */ -public char[] getFileName(){ - return this.fileName; -} - -public int[] getLineSeparatorPositions() { - return this.lineSeparatorPositions == null ? CompilationResult.EMPTY_LINE_ENDS : this.lineSeparatorPositions; -} - -/** - * Answer the problems (errors and warnings) encountered during compilation. - * - * This is not a compiler internal API - it has side-effects ! - * It is intended to be used only once all problems have been detected, - * and makes sure the problems slot as the exact size of the number of - * problems. - */ -public CategorizedProblem[] getProblems() { - // Re-adjust the size of the problems if necessary. - if (this.problems != null) { - if (this.problemCount != this.problems.length) { - System.arraycopy(this.problems, 0, (this.problems = new CategorizedProblem[this.problemCount]), 0, this.problemCount); - } - - if (this.maxProblemPerUnit > 0 && this.problemCount > this.maxProblemPerUnit){ - quickPrioritize(this.problems, 0, this.problemCount - 1); - this.problemCount = this.maxProblemPerUnit; - System.arraycopy(this.problems, 0, (this.problems = new CategorizedProblem[this.problemCount]), 0, this.problemCount); - } - - // Stable sort problems per source positions. - Arrays.sort(this.problems, 0, this.problems.length, CompilationResult.PROBLEM_COMPARATOR); - //quickSort(problems, 0, problems.length-1); - } - return this.problems; -} -/** - * Same as getProblems() but don't answer problems that actually concern the enclosing package. - */ -public CategorizedProblem[] getCUProblems() { - // Re-adjust the size of the problems if necessary and filter package problems - if (this.problems != null) { - CategorizedProblem[] filteredProblems = new CategorizedProblem[this.problemCount]; - int keep = 0; - for (int i=0; i< this.problemCount; i++) { - CategorizedProblem problem = this.problems[i]; - if (problem.getID() != IProblem.MissingNonNullByDefaultAnnotationOnPackage) { - filteredProblems[keep++] = problem; - } else if (this.compilationUnit != null) { - if (CharOperation.equals(this.compilationUnit.getMainTypeName(), TypeConstants.PACKAGE_INFO_NAME)) { - filteredProblems[keep++] = problem; - } - } - } - if (keep < this.problemCount) { - System.arraycopy(filteredProblems, 0, filteredProblems = new CategorizedProblem[keep], 0, keep); - this.problemCount = keep; - } - this.problems = filteredProblems; - if (this.maxProblemPerUnit > 0 && this.problemCount > this.maxProblemPerUnit){ - quickPrioritize(this.problems, 0, this.problemCount - 1); - this.problemCount = this.maxProblemPerUnit; - System.arraycopy(this.problems, 0, (this.problems = new CategorizedProblem[this.problemCount]), 0, this.problemCount); - } - - // Stable sort problems per source positions. - Arrays.sort(this.problems, 0, this.problems.length, CompilationResult.PROBLEM_COMPARATOR); - //quickSort(problems, 0, problems.length-1); - } - return this.problems; -} - -/** - * Answer the tasks (TO-DO, ...) encountered during compilation. - * - * This is not a compiler internal API - it has side-effects ! - * It is intended to be used only once all problems have been detected, - * and makes sure the problems slot as the exact size of the number of - * problems. - */ -public CategorizedProblem[] getTasks() { - // Re-adjust the size of the tasks if necessary. - if (this.tasks != null) { - - if (this.taskCount != this.tasks.length) { - System.arraycopy(this.tasks, 0, (this.tasks = new CategorizedProblem[this.taskCount]), 0, this.taskCount); - } - // Stable sort problems per source positions. - Arrays.sort(this.tasks, 0, this.tasks.length, CompilationResult.PROBLEM_COMPARATOR); - //quickSort(tasks, 0, tasks.length-1); - } - return this.tasks; -} - -public boolean hasErrors() { - return this.numberOfErrors != 0; -} - -public boolean hasMandatoryErrors() { - return this.hasMandatoryErrors; -} - -public boolean hasProblems() { - return this.problemCount != 0; -} - -public boolean hasTasks() { - return this.taskCount != 0; -} - -public boolean hasWarnings() { - if (this.problems != null) - for (int i = 0; i < this.problemCount; i++) { - if (this.problems[i].isWarning()) - return true; - } - return false; -} - -private void quickPrioritize(CategorizedProblem[] problemList, int left, int right) { - if (left >= right) return; - // sort the problems by their priority... starting with the highest priority - int original_left = left; - int original_right = right; - int mid = computePriority(problemList[left + (right - left) / 2]); - do { - while (computePriority(problemList[right]) < mid) - right--; - while (mid < computePriority(problemList[left])) - left++; - if (left <= right) { - CategorizedProblem tmp = problemList[left]; - problemList[left] = problemList[right]; - problemList[right] = tmp; - left++; - right--; - } - } while (left <= right); - if (original_left < right) - quickPrioritize(problemList, original_left, right); - if (left < original_right) - quickPrioritize(problemList, left, original_right); -} - -/* - * Record the compilation unit result's package name - */ -public void recordPackageName(char[][] packName) { - this.packageName = packName; -} - -public void record(CategorizedProblem newProblem, ReferenceContext referenceContext) { - record(newProblem, referenceContext, true); - return; -} - -public void record(CategorizedProblem newProblem, ReferenceContext referenceContext, boolean mandatoryError) { - //new Exception("VERBOSE PROBLEM REPORTING").printStackTrace(); - if(newProblem.getID() == IProblem.Task) { - recordTask(newProblem); - return; - } - if (this.problemCount == 0) { - this.problems = new CategorizedProblem[5]; - } else if (this.problemCount == this.problems.length) { - System.arraycopy(this.problems, 0, (this.problems = new CategorizedProblem[this.problemCount * 2]), 0, this.problemCount); - } - this.problems[this.problemCount++] = newProblem; - if (referenceContext != null){ - if (this.problemsMap == null) this.problemsMap = new HashMap(5); - if (this.firstErrors == null) this.firstErrors = new HashSet(5); - if (newProblem.isError() && !referenceContext.hasErrors()) this.firstErrors.add(newProblem); - this.problemsMap.put(newProblem, referenceContext); - } - if (newProblem.isError()) { - this.numberOfErrors++; - if (mandatoryError) this.hasMandatoryErrors = true; - if ((newProblem.getID() & IProblem.Syntax) != 0) { - this.hasSyntaxError = true; - } - } -} - -ReferenceContext getContext(CategorizedProblem problem) { - if (problem != null) { - return this.problemsMap.get(problem); - } - return null; -} - -/** - * For now, remember the compiled type using its compound name. - */ -public void record(char[] typeName, ClassFile classFile) { - SourceTypeBinding sourceType = classFile.referenceBinding; - if (sourceType != null && !sourceType.isLocalType() && sourceType.isHierarchyInconsistent()) { - this.hasInconsistentToplevelHierarchies = true; - } - this.compiledTypes.put(typeName, classFile); -} - -private void recordTask(CategorizedProblem newProblem) { - if (this.taskCount == 0) { - this.tasks = new CategorizedProblem[5]; - } else if (this.taskCount == this.tasks.length) { - System.arraycopy(this.tasks, 0, (this.tasks = new CategorizedProblem[this.taskCount * 2]), 0, this.taskCount); - } - this.tasks[this.taskCount++] = newProblem; -} -public void removeProblem(CategorizedProblem problem) { - if (this.problemsMap != null) this.problemsMap.remove(problem); - if (this.firstErrors != null) this.firstErrors.remove(problem); - if (problem.isError()) { - this.numberOfErrors--; - } - this.problemCount--; -} -public CompilationResult tagAsAccepted(){ - this.hasBeenAccepted = true; - this.problemsMap = null; // flush - this.firstErrors = null; // flush - return this; -} - -@Override -public String toString(){ - StringBuilder buffer = new StringBuilder(); - if (this.fileName != null){ - buffer.append("Filename : ").append(this.fileName).append('\n'); //$NON-NLS-1$ - } - if (this.compiledTypes != null){ - buffer.append("COMPILED type(s) \n"); //$NON-NLS-1$ - Iterator keys = this.compiledTypes.keySet().iterator(); - while (keys.hasNext()) { - char[] typeName = (char[]) keys.next(); - buffer.append("\t - ").append(typeName).append('\n'); //$NON-NLS-1$ - - } - } else { - buffer.append("No COMPILED type\n"); //$NON-NLS-1$ - } - if (this.problems != null){ - buffer.append(this.problemCount).append(" PROBLEM(s) detected \n"); //$NON-NLS-1$ - for (int i = 0; i < this.problemCount; i++){ - buffer.append("\t - ").append(this.problems[i]).append('\n'); //$NON-NLS-1$ - } - } else { - buffer.append("No PROBLEM\n"); //$NON-NLS-1$ - } - return buffer.toString(); -} - -public void scheduleProblem(Runnable task) { - if (this.scheduledProblems == null) - this.scheduledProblems = new ArrayList<>(); - this.scheduledProblems.add(task); -} - -public void materializeProblems() { - if (this.scheduledProblems != null) { - for (Runnable task : this.scheduledProblems) { - task.run(); - } - } -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/Compiler.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/Compiler.java deleted file mode 100644 index d608607..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/Compiler.java +++ /dev/null @@ -1,1117 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - contributions for - * bug 337868 - [compiler][model] incomplete support for package-info.java when using SearchableEnvironment - * bug 186342 - [compiler][null] Using annotations for null checking - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler; - -import org.eclipse.jdt.core.compiler.*; -import org.eclipse.jdt.internal.compiler.env.*; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.ast.*; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.parser.*; -import org.eclipse.jdt.internal.compiler.problem.*; -import org.eclipse.jdt.internal.compiler.util.*; - -import java.io.*; -import java.util.*; - -public class Compiler implements ITypeRequestor, ProblemSeverities { - public Parser parser; - public ICompilerRequestor requestor; - public CompilerOptions options; - public ProblemReporter problemReporter; - protected PrintWriter out; // output for messages that are not sent to problemReporter - public CompilerStats stats; - public CompilationProgress progress; - public int remainingIterations = 1; - - // management of unit to be processed - //public CompilationUnitResult currentCompilationUnitResult; - public CompilationUnitDeclaration[] unitsToProcess; - public int totalUnits; // (totalUnits-1) gives the last unit in unitToProcess - - private Map aptProblems; - - // name lookup - public LookupEnvironment lookupEnvironment; - - // ONCE STABILIZED, THESE SHOULD RETURN TO A FINAL FIELD - public static boolean DEBUG = false; - public int parseThreshold = -1; - - public AbstractAnnotationProcessorManager annotationProcessorManager; - public int annotationProcessorStartIndex = 0; - public ReferenceBinding[] referenceBindings; - public boolean useSingleThread = true; // by default the compiler will not use worker threads to read/process/write - - // number of initial units parsed at once (-1: none) - - /* - * Static requestor reserved to listening compilation results in debug mode, - * so as for example to monitor compiler activity independantly from a particular - * builder implementation. It is reset at the end of compilation, and should not - * persist any information after having been reset. - */ - public static IDebugRequestor DebugRequestor = null; - - /** - * Answer a new compiler using the given name environment and compiler options. - * The environment and options will be in effect for the lifetime of the compiler. - * When the compiler is run, compilation results are sent to the given requestor. - * - * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment - * Environment used by the compiler in order to resolve type and package - * names. The name environment implements the actual connection of the compiler - * to the outside world (e.g. in batch mode the name environment is performing - * pure file accesses, reuse previous build state or connection to repositories). - * Note: the name environment is responsible for implementing the actual classpath - * rules. - * - * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy - * Configurable part for problem handling, allowing the compiler client to - * specify the rules for handling problems (stop on first error or accumulate - * them all) and at the same time perform some actions such as opening a dialog - * in UI when compiling interactively. - * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies - * - * @param settings java.util.Map - * The settings that control the compiler behavior. - * - * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor - * Component which will receive and persist all compilation results and is intended - * to consume them as they are produced. Typically, in a batch compiler, it is - * responsible for writing out the actual .class files to the file system. - * @see org.eclipse.jdt.internal.compiler.CompilationResult - * - * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory - * Factory used inside the compiler to create problem descriptors. It allows the - * compiler client to supply its own representation of compilation problems in - * order to avoid object conversions. Note that the factory is not supposed - * to accumulate the created problems, the compiler will gather them all and hand - * them back as part of the compilation unit result. - * - * @deprecated this constructor is kept to preserve 3.1 and 3.2M4 compatibility - */ - public Compiler( - INameEnvironment environment, - IErrorHandlingPolicy policy, - Map settings, - final ICompilerRequestor requestor, - IProblemFactory problemFactory) { - this(environment, policy, new CompilerOptions(settings), requestor, problemFactory, null /* printwriter */, null /* progress */); - } - - /** - * Answer a new compiler using the given name environment and compiler options. - * The environment and options will be in effect for the lifetime of the compiler. - * When the compiler is run, compilation results are sent to the given requestor. - * - * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment - * Environment used by the compiler in order to resolve type and package - * names. The name environment implements the actual connection of the compiler - * to the outside world (e.g. in batch mode the name environment is performing - * pure file accesses, reuse previous build state or connection to repositories). - * Note: the name environment is responsible for implementing the actual classpath - * rules. - * - * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy - * Configurable part for problem handling, allowing the compiler client to - * specify the rules for handling problems (stop on first error or accumulate - * them all) and at the same time perform some actions such as opening a dialog - * in UI when compiling interactively. - * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies - * - * @param settings java.util.Map - * The settings that control the compiler behavior. - * - * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor - * Component which will receive and persist all compilation results and is intended - * to consume them as they are produced. Typically, in a batch compiler, it is - * responsible for writing out the actual .class files to the file system. - * @see org.eclipse.jdt.internal.compiler.CompilationResult - * - * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory - * Factory used inside the compiler to create problem descriptors. It allows the - * compiler client to supply its own representation of compilation problems in - * order to avoid object conversions. Note that the factory is not supposed - * to accumulate the created problems, the compiler will gather them all and hand - * them back as part of the compilation unit result. - * - * @param parseLiteralExpressionsAsConstants boolean - * This parameter is used to optimize the literals or leave them as they are in the source. - * If you put true, "Hello" + " world" will be converted to "Hello world". - * - * @deprecated this constructor is kept to preserve 3.1 and 3.2M4 compatibility - */ - public Compiler( - INameEnvironment environment, - IErrorHandlingPolicy policy, - Map settings, - final ICompilerRequestor requestor, - IProblemFactory problemFactory, - boolean parseLiteralExpressionsAsConstants) { - this(environment, policy, new CompilerOptions(settings, parseLiteralExpressionsAsConstants), requestor, problemFactory, null /* printwriter */, null /* progress */); - } - - /** - * Answer a new compiler using the given name environment and compiler options. - * The environment and options will be in effect for the lifetime of the compiler. - * When the compiler is run, compilation results are sent to the given requestor. - * - * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment - * Environment used by the compiler in order to resolve type and package - * names. The name environment implements the actual connection of the compiler - * to the outside world (e.g. in batch mode the name environment is performing - * pure file accesses, reuse previous build state or connection to repositories). - * Note: the name environment is responsible for implementing the actual classpath - * rules. - * - * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy - * Configurable part for problem handling, allowing the compiler client to - * specify the rules for handling problems (stop on first error or accumulate - * them all) and at the same time perform some actions such as opening a dialog - * in UI when compiling interactively. - * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies - * - * @param options org.eclipse.jdt.internal.compiler.impl.CompilerOptions - * The options that control the compiler behavior. - * - * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor - * Component which will receive and persist all compilation results and is intended - * to consume them as they are produced. Typically, in a batch compiler, it is - * responsible for writing out the actual .class files to the file system. - * @see org.eclipse.jdt.internal.compiler.CompilationResult - * - * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory - * Factory used inside the compiler to create problem descriptors. It allows the - * compiler client to supply its own representation of compilation problems in - * order to avoid object conversions. Note that the factory is not supposed - * to accumulate the created problems, the compiler will gather them all and hand - * them back as part of the compilation unit result. - */ - public Compiler( - INameEnvironment environment, - IErrorHandlingPolicy policy, - CompilerOptions options, - final ICompilerRequestor requestor, - IProblemFactory problemFactory) { - this(environment, policy, options, requestor, problemFactory, null /* printwriter */, null /* progress */); - } - - /** - * Answer a new compiler using the given name environment and compiler options. - * The environment and options will be in effect for the lifetime of the compiler. - * When the compiler is run, compilation results are sent to the given requestor. - * - * @param environment org.eclipse.jdt.internal.compiler.api.env.INameEnvironment - * Environment used by the compiler in order to resolve type and package - * names. The name environment implements the actual connection of the compiler - * to the outside world (e.g. in batch mode the name environment is performing - * pure file accesses, reuse previous build state or connection to repositories). - * Note: the name environment is responsible for implementing the actual classpath - * rules. - * - * @param policy org.eclipse.jdt.internal.compiler.api.problem.IErrorHandlingPolicy - * Configurable part for problem handling, allowing the compiler client to - * specify the rules for handling problems (stop on first error or accumulate - * them all) and at the same time perform some actions such as opening a dialog - * in UI when compiling interactively. - * @see org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies - * - * @param options org.eclipse.jdt.internal.compiler.impl.CompilerOptions - * The options that control the compiler behavior. - * - * @param requestor org.eclipse.jdt.internal.compiler.api.ICompilerRequestor - * Component which will receive and persist all compilation results and is intended - * to consume them as they are produced. Typically, in a batch compiler, it is - * responsible for writing out the actual .class files to the file system. - * @see org.eclipse.jdt.internal.compiler.CompilationResult - * - * @param problemFactory org.eclipse.jdt.internal.compiler.api.problem.IProblemFactory - * Factory used inside the compiler to create problem descriptors. It allows the - * compiler client to supply its own representation of compilation problems in - * order to avoid object conversions. Note that the factory is not supposed - * to accumulate the created problems, the compiler will gather them all and hand - * them back as part of the compilation unit result. - * @deprecated - */ - public Compiler( - INameEnvironment environment, - IErrorHandlingPolicy policy, - CompilerOptions options, - final ICompilerRequestor requestor, - IProblemFactory problemFactory, - PrintWriter out) { - this(environment, policy, options, requestor, problemFactory, out, null /* progress */); - } - - public Compiler( - INameEnvironment environment, - IErrorHandlingPolicy policy, - CompilerOptions options, - final ICompilerRequestor requestor, - IProblemFactory problemFactory, - PrintWriter out, - CompilationProgress progress) { - - this.options = options; - this.progress = progress; - - // wrap requestor in DebugRequestor if one is specified - if(DebugRequestor == null) { - this.requestor = requestor; - } else { - this.requestor = new ICompilerRequestor(){ - @Override - public void acceptResult(CompilationResult result){ - if (DebugRequestor.isActive()){ - DebugRequestor.acceptDebugResult(result); - } - requestor.acceptResult(result); - } - }; - } - this.problemReporter = new ProblemReporter(policy, this.options, problemFactory); - this.lookupEnvironment = new LookupEnvironment(this, this.options, this.problemReporter, environment); - this.out = out == null ? new PrintWriter(System.out, true) : out; - this.stats = new CompilerStats(); - initializeParser(); - } - - /** - * Add an additional binary type - */ - @Override - public void accept(IBinaryType binaryType, PackageBinding packageBinding, AccessRestriction accessRestriction) { - if (this.options.verbose) { - this.out.println( - Messages.bind(Messages.compilation_loadBinary, new String(binaryType.getName()))); -// new Exception("TRACE BINARY").printStackTrace(System.out); -// System.out.println(); - } - LookupEnvironment env = packageBinding.environment; - env.createBinaryTypeFrom(binaryType, packageBinding, accessRestriction); - } - - /** - * Add an additional compilation unit into the loop - * -> build compilation unit declarations, their bindings and record their results. - */ - @Override - public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) { - // Switch the current policy and compilation result for this unit to the requested one. - CompilationResult unitResult = - new CompilationResult(sourceUnit, this.totalUnits, this.totalUnits, this.options.maxProblemsPerUnit); - unitResult.checkSecondaryTypes = true; - try { - if (this.options.verbose) { - String count = String.valueOf(this.totalUnits + 1); - this.out.println( - Messages.bind(Messages.compilation_request, - new String[] { - count, - count, - new String(sourceUnit.getFileName()) - })); - } - // diet parsing for large collection of unit - CompilationUnitDeclaration parsedUnit; - if (this.totalUnits < this.parseThreshold) { - parsedUnit = this.parser.parse(sourceUnit, unitResult); - } else { - parsedUnit = this.parser.dietParse(sourceUnit, unitResult); - } - // initial type binding creation - this.lookupEnvironment.buildTypeBindings(parsedUnit, accessRestriction); - addCompilationUnit(sourceUnit, parsedUnit); - - // binding resolution - this.lookupEnvironment.completeTypeBindings(parsedUnit); - } catch (AbortCompilationUnit e) { - // at this point, currentCompilationUnitResult may not be sourceUnit, but some other - // one requested further along to resolve sourceUnit. - if (unitResult.compilationUnit == sourceUnit) { // only report once - this.requestor.acceptResult(unitResult.tagAsAccepted()); - } else { - throw e; // want to abort enclosing request to compile - } - } - } - - /** - * Add additional source types - */ - @Override - public void accept(ISourceType[] sourceTypes, PackageBinding packageBinding, AccessRestriction accessRestriction) { - this.problemReporter.abortDueToInternalError( - Messages.bind(Messages.abort_againstSourceModel, new String[] { String.valueOf(sourceTypes[0].getName()), String.valueOf(sourceTypes[0].getFileName()) })); - } - - protected synchronized void addCompilationUnit( - ICompilationUnit sourceUnit, - CompilationUnitDeclaration parsedUnit) { - - if (this.unitsToProcess == null) - return; // not collecting units - - // append the unit to the list of ones to process later on - int size = this.unitsToProcess.length; - if (this.totalUnits == size) - // when growing reposition units starting at position 0 - System.arraycopy( - this.unitsToProcess, - 0, - (this.unitsToProcess = new CompilationUnitDeclaration[size * 2]), - 0, - this.totalUnits); - this.unitsToProcess[this.totalUnits++] = parsedUnit; - } - - /** - * Add the initial set of compilation units into the loop - * -> build compilation unit declarations, their bindings and record their results. - */ - protected void beginToCompile(ICompilationUnit[] sourceUnits) { - int maxUnits = sourceUnits.length; - this.totalUnits = 0; - this.unitsToProcess = new CompilationUnitDeclaration[maxUnits]; - - internalBeginToCompile(sourceUnits, maxUnits); - } - - /** - * Checks whether the compilation has been canceled and reports the given progress to the compiler progress. - */ - protected void reportProgress(String taskDecription) { - if (this.progress != null) { - if (this.progress.isCanceled()) { - // Only AbortCompilation can stop the compiler cleanly. - // We check cancellation again following the call to compile. - throw new AbortCompilation(true, null); - } - this.progress.setTaskName(taskDecription); - } - } - - /** - * Checks whether the compilation has been canceled and reports the given work increment to the compiler progress. - */ - protected void reportWorked(int workIncrement, int currentUnitIndex) { - if (this.progress != null) { - if (this.progress.isCanceled()) { - // Only AbortCompilation can stop the compiler cleanly. - // We check cancellation again following the call to compile. - throw new AbortCompilation(true, null); - } - this.progress.worked(workIncrement, (this.totalUnits* this.remainingIterations) - currentUnitIndex - 1); - } - } - - public void compile(ICompilationUnit[] sourceUnits) { - compile(sourceUnits, false); - } - /** - * General API - * -> compile each of supplied files - * -> recompile any required types for which we have an incomplete principle structure - */ - private void compile(ICompilationUnit[] sourceUnits, boolean lastRound) { - this.stats.startTime = System.currentTimeMillis(); - try { - // build and record parsed units - reportProgress(Messages.compilation_beginningToCompile); - - if (this.options.complianceLevel >= ClassFileConstants.JDK9) { - // in Java 9 the compiler must never ask the oracle for a module that is contained in the input units: - sortModuleDeclarationsFirst(sourceUnits); - } - if (this.annotationProcessorManager == null) { - beginToCompile(sourceUnits); - } else { - ICompilationUnit[] originalUnits = sourceUnits.clone(); // remember source units in case a source type collision occurs - try { - beginToCompile(sourceUnits); - if (!lastRound) { - processAnnotations(); - } - if (!this.options.generateClassFiles) { - // -proc:only was set on the command line - return; - } - } catch (SourceTypeCollisionException e) { - backupAptProblems(); - reset(); - // a generated type was referenced before it was created - // the compiler either created a MissingType or found a BinaryType for it - // so add the processor's generated files & start over, - // but remember to only pass the generated files to the annotation processor - int originalLength = originalUnits.length; - int newProcessedLength = e.newAnnotationProcessorUnits.length; - ICompilationUnit[] combinedUnits = new ICompilationUnit[originalLength + newProcessedLength]; - System.arraycopy(originalUnits, 0, combinedUnits, 0, originalLength); - System.arraycopy(e.newAnnotationProcessorUnits, 0, combinedUnits, originalLength, newProcessedLength); - this.annotationProcessorStartIndex = originalLength; - compile(combinedUnits, e.isLastRound); - return; - } - } - // Restore the problems before the results are processed and cleaned up. - restoreAptProblems(); - processCompiledUnits(0, lastRound); - } catch (AbortCompilation e) { - this.handleInternalException(e, null); - } - if (this.options.verbose) { - if (this.totalUnits > 1) { - this.out.println( - Messages.bind(Messages.compilation_units, String.valueOf(this.totalUnits))); - } else { - this.out.println( - Messages.bind(Messages.compilation_unit, String.valueOf(this.totalUnits))); - } - } - } - - private void sortModuleDeclarationsFirst(ICompilationUnit[] sourceUnits) { - Arrays.sort(sourceUnits, (u1, u2) -> { - char[] fn1 = u1.getFileName(); - char[] fn2 = u2.getFileName(); - boolean isMod1 = CharOperation.endsWith(fn1, TypeConstants.MODULE_INFO_FILE_NAME) || CharOperation.endsWith(fn1, TypeConstants.MODULE_INFO_CLASS_NAME); - boolean isMod2 = CharOperation.endsWith(fn2, TypeConstants.MODULE_INFO_FILE_NAME) || CharOperation.endsWith(fn2, TypeConstants.MODULE_INFO_CLASS_NAME); - if (isMod1 == isMod2) - return 0; - return isMod1 ? -1 : 1; - }); - } - - static class APTProblem { - CategorizedProblem problem; - ReferenceContext context; - APTProblem(CategorizedProblem problem, ReferenceContext context) { - this.problem = problem; - this.context = context; - } - } - - protected void backupAptProblems() { - if (this.unitsToProcess == null) return; - for (int i = 0; i < this.totalUnits; i++) { - CompilationUnitDeclaration unitDecl = this.unitsToProcess[i]; - CompilationResult result = unitDecl.compilationResult; - if (result != null && result.hasErrors()) { - CategorizedProblem[] errors = result.getErrors(); - for (CategorizedProblem problem : errors) { - if (problem.getCategoryID() == CategorizedProblem.CAT_UNSPECIFIED) { - if (this.aptProblems == null) { - this.aptProblems = new HashMap<>(); - } - APTProblem[] problems = this.aptProblems.get(new String(unitDecl.getFileName())); - if (problems == null) { - this.aptProblems.put( - new String(unitDecl.getFileName()), - new APTProblem[] { new APTProblem(problem, result.getContext(problem)) }); - } else { - APTProblem[] temp = new APTProblem[problems.length + 1]; - System.arraycopy(problems, 0, temp, 0, problems.length); - temp[problems.length] = new APTProblem(problem, result.getContext(problem)); - this.aptProblems.put(new String(unitDecl.getFileName()), temp); - } - } - } - } - } - } - - protected void restoreAptProblems() { - if (this.unitsToProcess != null && this.aptProblems!= null) { - for (int i = 0; i < this.totalUnits; i++) { - CompilationUnitDeclaration unitDecl = this.unitsToProcess[i]; - APTProblem[] problems = this.aptProblems.get(new String(unitDecl.getFileName())); - if (problems != null) { - for (APTProblem problem : problems) { - unitDecl.compilationResult.record(problem.problem, problem.context); - } - } - } - } - this.aptProblems = null; // No need for this. - } - - protected void processCompiledUnits(int startingIndex, boolean lastRound) throws java.lang.Error { - CompilationUnitDeclaration unit = null; - ProcessTaskManager processingTask = null; - try { - if (this.useSingleThread) { - // process all units (some more could be injected in the loop by the lookup environment) - for (int i = startingIndex; i < this.totalUnits; i++) { - unit = this.unitsToProcess[i]; - if (unit.compilationResult != null && unit.compilationResult.hasBeenAccepted) - continue; - reportProgress(Messages.bind(Messages.compilation_processing, new String(unit.getFileName()))); - try { - if (this.options.verbose) - this.out.println( - Messages.bind(Messages.compilation_process, - new String[] { - String.valueOf(i + 1), - String.valueOf(this.totalUnits), - new String(this.unitsToProcess[i].getFileName()) - })); - process(unit, i); - } finally { - // cleanup compilation unit result, but only if not annotation processed. - if (this.annotationProcessorManager == null || shouldCleanup(i)) - unit.cleanUp(); - } - if (this.annotationProcessorManager == null) { - this.unitsToProcess[i] = null; // release reference to processed unit declaration - } - - reportWorked(1, i); - this.stats.lineCount += unit.compilationResult.lineSeparatorPositions.length; - long acceptStart = System.currentTimeMillis(); - this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); - this.stats.generateTime += System.currentTimeMillis() - acceptStart; // record accept time as part of generation - if (this.options.verbose) - this.out.println( - Messages.bind(Messages.compilation_done, - new String[] { - String.valueOf(i + 1), - String.valueOf(this.totalUnits), - new String(unit.getFileName()) - })); - } - } else { - processingTask = new ProcessTaskManager(this, startingIndex); - int acceptedCount = 0; - // process all units (some more could be injected in the loop by the lookup environment) - // the processTask can continue to process units until its fixed sized cache is full then it must wait - // for this this thread to accept the units as they appear (it only waits if no units are available) - while (true) { - try { - unit = processingTask.removeNextUnit(); // waits if no units are in the processed queue - } catch (Error | RuntimeException e) { - unit = processingTask.unitToProcess; - throw e; - } - if (unit == null) break; - reportWorked(1, acceptedCount++); - this.stats.lineCount += unit.compilationResult.lineSeparatorPositions.length; - this.requestor.acceptResult(unit.compilationResult.tagAsAccepted()); - if (this.options.verbose) - this.out.println( - Messages.bind(Messages.compilation_done, - new String[] { - String.valueOf(acceptedCount), - String.valueOf(this.totalUnits), - new String(unit.getFileName()) - })); - } - } - if (!lastRound) { - if (this.annotationProcessorManager != null && this.totalUnits > this.annotationProcessorStartIndex) { - int backup = this.annotationProcessorStartIndex; - int prevUnits = this.totalUnits; - processAnnotations(); - // Clean up the units that were left out previously for annotation processing. - for (int i = backup; i < prevUnits; i++) { - this.unitsToProcess[i].cleanUp(); - } - processCompiledUnits(backup, lastRound); - } - } - } catch (AbortCompilation e) { - this.handleInternalException(e, unit); - } catch (Error | RuntimeException e) { - this.handleInternalException(e, unit, null); - throw e; // rethrow - } finally { - if (processingTask != null) { - processingTask.shutdown(); - processingTask = null; - } - reset(); - this.annotationProcessorStartIndex = 0; - this.stats.endTime = System.currentTimeMillis(); - this.stats.overallTime += this.stats.endTime - this.stats.startTime; - } - } - - public synchronized CompilationUnitDeclaration getUnitToProcess(int next) { - if (next < this.totalUnits) { - CompilationUnitDeclaration unit = this.unitsToProcess[next]; - if (this.annotationProcessorManager == null || next < this.annotationProcessorStartIndex) { - this.unitsToProcess[next] = null; // release reference to processed unit declaration - } - return unit; - } - return null; - } - - /* - * Returns whether the compilation unit at the given index should be - * cleaned up after processing. This basically means whether or not - * the unit is still required for annotation processing. - */ - public boolean shouldCleanup(int index) { - return index < this.annotationProcessorStartIndex; - } - - public void setBinaryTypes(ReferenceBinding[] binaryTypes) { - this.referenceBindings = binaryTypes; - } - /* - * Compiler crash recovery in case of unexpected runtime exceptions - */ - protected void handleInternalException( - Throwable internalException, - CompilationUnitDeclaration unit, - CompilationResult result) { - - if (result == null && unit != null) { - result = unit.compilationResult; // current unit being processed ? - } - // Lookup environment may be in middle of connecting types - if (result == null && this.lookupEnvironment.unitBeingCompleted != null) { - result = this.lookupEnvironment.unitBeingCompleted.compilationResult; - } - if (result == null) { - synchronized (this) { - if (this.unitsToProcess != null && this.totalUnits > 0) - result = this.unitsToProcess[this.totalUnits - 1].compilationResult; - } - } - // last unit in beginToCompile ? - - boolean needToPrint = true; - if (result != null) { - /* create and record a compilation problem */ - // only keep leading portion of the trace - String[] pbArguments = new String[] { - Messages.bind(Messages.compilation_internalError, Util.getExceptionSummary(internalException)), - }; - - result - .record( - this.problemReporter - .createProblem( - result.getFileName(), - IProblem.Unclassified, - pbArguments, - pbArguments, - Error, // severity - 0, // source start - 0, // source end - 0, // line number - 0),// column number - unit, true); - - /* hand back the compilation result */ - if (!result.hasBeenAccepted) { - this.requestor.acceptResult(result.tagAsAccepted()); - needToPrint = false; - } - } - if (needToPrint) { - /* dump a stack trace to the console */ - internalException.printStackTrace(); - } - } - - /* - * Compiler recovery in case of internal AbortCompilation event - */ - protected void handleInternalException( - AbortCompilation abortException, - CompilationUnitDeclaration unit) { - - /* special treatment for SilentAbort: silently cancelling the compilation process */ - if (abortException.isSilent) { - if (abortException.silentException == null) { - return; - } - throw abortException.silentException; - } - - /* uncomment following line to see where the abort came from */ - // abortException.printStackTrace(); - - // Exception may tell which compilation result it is related, and which problem caused it - CompilationResult result = abortException.compilationResult; - if (result == null && unit != null) { - result = unit.compilationResult; // current unit being processed ? - } - // Lookup environment may be in middle of connecting types - if (result == null && this.lookupEnvironment.unitBeingCompleted != null) { - result = this.lookupEnvironment.unitBeingCompleted.compilationResult; - } - if (result == null) { - synchronized (this) { - if (this.unitsToProcess != null && this.totalUnits > 0) - result = this.unitsToProcess[this.totalUnits - 1].compilationResult; - } - } - // last unit in beginToCompile ? - if (result != null && !result.hasBeenAccepted) { - /* distant problem which could not be reported back there? */ - if (abortException.problem != null) { - recordDistantProblem: { - CategorizedProblem distantProblem = abortException.problem; - CategorizedProblem[] knownProblems = result.problems; - for (int i = 0; i < result.problemCount; i++) { - if (knownProblems[i] == distantProblem) { // already recorded - break recordDistantProblem; - } - } - if (distantProblem instanceof DefaultProblem) { // fixup filename TODO (philippe) should improve API to make this official - ((DefaultProblem) distantProblem).setOriginatingFileName(result.getFileName()); - } - result.record(distantProblem, unit, true); - } - } else { - /* distant internal exception which could not be reported back there */ - if (abortException.exception != null) { - this.handleInternalException(abortException.exception, null, result); - return; - } - } - /* hand back the compilation result */ - if (!result.hasBeenAccepted) { - this.requestor.acceptResult(result.tagAsAccepted()); - } - } else { - abortException.printStackTrace(); - } - } - - public void initializeParser() { - - this.parser = new Parser(this.problemReporter, this.options.parseLiteralExpressionsAsConstants); - } - - private void abortIfPreviewNotAllowed(ICompilationUnit[] sourceUnits, int maxUnits) { - if (!this.options.enablePreviewFeatures) - return; - try { - if (this.options.sourceLevel != ClassFileConstants.getLatestJDKLevel()) { - this.problemReporter.abortDueToPreviewEnablingNotAllowed(CompilerOptions.versionFromJdkLevel(this.options.sourceLevel), CompilerOptions.getLatestVersion()); - } - } catch (AbortCompilation a) { - // best effort to find a way for reporting this problem: report on the first source - if (a.compilationResult == null) { - a.compilationResult = new CompilationResult(sourceUnits[0], 0, maxUnits, this.options.maxProblemsPerUnit); - } - throw a; - } - } - /** - * Add the initial set of compilation units into the loop - * -> build compilation unit declarations, their bindings and record their results. - */ - protected void internalBeginToCompile(ICompilationUnit[] sourceUnits, int maxUnits) { - abortIfPreviewNotAllowed(sourceUnits,maxUnits); - if (!this.useSingleThread && maxUnits >= ReadManager.THRESHOLD) - this.parser.readManager = new ReadManager(sourceUnits, maxUnits); - try { - // Switch the current policy and compilation result for this unit to the requested one. - for (int i = 0; i < maxUnits; i++) { - CompilationResult unitResult = null; - try { - if (this.options.verbose) { - this.out.println( - Messages.bind(Messages.compilation_request, - new String[] { - String.valueOf(i + 1), - String.valueOf(maxUnits), - new String(sourceUnits[i].getFileName()) - })); - } - // diet parsing for large collection of units - CompilationUnitDeclaration parsedUnit; - unitResult = new CompilationResult(sourceUnits[i], i, maxUnits, this.options.maxProblemsPerUnit); - long parseStart = System.currentTimeMillis(); - if (this.totalUnits < this.parseThreshold) { - parsedUnit = this.parser.parse(sourceUnits[i], unitResult); - } else { - parsedUnit = this.parser.dietParse(sourceUnits[i], unitResult); - } - long resolveStart = System.currentTimeMillis(); - this.stats.parseTime += resolveStart - parseStart; - // initial type binding creation - this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); - this.stats.resolveTime += System.currentTimeMillis() - resolveStart; - addCompilationUnit(sourceUnits[i], parsedUnit); - ImportReference currentPackage = parsedUnit.currentPackage; - if (currentPackage != null) { - unitResult.recordPackageName(currentPackage.tokens); - } - //} catch (AbortCompilationUnit e) { - // requestor.acceptResult(unitResult.tagAsAccepted()); - } catch (AbortCompilation a) { - // best effort to find a way for reporting this problem: - if (a.compilationResult == null) - a.compilationResult = unitResult; - throw a; - } finally { - sourceUnits[i] = null; // no longer hold onto the unit - } - } - } finally { // especially on AbortCompilation - if (this.parser.readManager != null) { - this.parser.readManager.shutdown(); - this.parser.readManager = null; - } - } - // binding resolution - this.lookupEnvironment.completeTypeBindings(); - } - - /** - * Process a compilation unit already parsed and build. - */ - public void process(CompilationUnitDeclaration unit, int i) { - this.lookupEnvironment.unitBeingCompleted = unit; - long parseStart = System.currentTimeMillis(); - - this.parser.getMethodBodies(unit); - - long resolveStart = System.currentTimeMillis(); - this.stats.parseTime += resolveStart - parseStart; - - // fault in fields & methods - if (unit.scope != null) - unit.scope.faultInTypes(); - - // verify inherited methods - if (unit.scope != null) - unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier()); - - // type checking - unit.resolve(); - - long analyzeStart = System.currentTimeMillis(); - this.stats.resolveTime += analyzeStart - resolveStart; - - //No need of analysis or generation of code if statements are not required - if (!this.options.ignoreMethodBodies) unit.analyseCode(); // flow analysis - - long generateStart = System.currentTimeMillis(); - this.stats.analyzeTime += generateStart - analyzeStart; - - if (!this.options.ignoreMethodBodies) unit.generateCode(); // code generation - - // reference info - if (this.options.produceReferenceInfo && unit.scope != null) - unit.scope.storeDependencyInfo(); - - // finalize problems (suppressWarnings) - unit.finalizeProblems(); - - this.stats.generateTime += System.currentTimeMillis() - generateStart; - - // refresh the total number of units known at this stage - unit.compilationResult.totalUnitsKnown = this.totalUnits; - - this.lookupEnvironment.unitBeingCompleted = null; - } - - protected void processAnnotations() { - int newUnitSize = 0; - int newClassFilesSize = 0; - int bottom = this.annotationProcessorStartIndex; - int top = this.totalUnits; - ReferenceBinding[] binaryTypeBindingsTemp = this.referenceBindings; - if (top == 0 && binaryTypeBindingsTemp == null) return; - this.referenceBindings = null; - do { - // extract units to process - int length = top - bottom; - CompilationUnitDeclaration[] currentUnits = new CompilationUnitDeclaration[length]; - int index = 0; - for (int i = bottom; i < top; i++) { - CompilationUnitDeclaration currentUnit = this.unitsToProcess[i]; - currentUnits[index++] = currentUnit; - } - if (index != length) { - System.arraycopy(currentUnits, 0, (currentUnits = new CompilationUnitDeclaration[index]), 0, index); - } - this.annotationProcessorManager.processAnnotations(currentUnits, binaryTypeBindingsTemp, false); - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=407841 - // It is possible that during the #processAnnotations() call, some units in the next batch would have been - // brought forward and compiled already. If there are any such, process them for annotations then and there. - // This would avoid the complications of marking some units as compiled but not-annotation-processed-yet. - if (top < this.totalUnits) { - length = this.totalUnits - top; // NOTE: Reuse the same variable, but make sure it's not used after this point - CompilationUnitDeclaration[] addedUnits = new CompilationUnitDeclaration[length]; - System.arraycopy(this.unitsToProcess, top, addedUnits, 0, length); - this.annotationProcessorManager.processAnnotations(addedUnits, binaryTypeBindingsTemp, false); - } - this.annotationProcessorStartIndex = top; - ICompilationUnit[] newUnits = this.annotationProcessorManager.getNewUnits(); - newUnitSize = newUnits.length; - ReferenceBinding[] newClassFiles = this.annotationProcessorManager.getNewClassFiles(); - binaryTypeBindingsTemp = newClassFiles; - newClassFilesSize = newClassFiles.length; - if (newUnitSize != 0) { - ICompilationUnit[] newProcessedUnits = newUnits.clone(); // remember new units in case a source type collision occurs - try { - this.lookupEnvironment.isProcessingAnnotations = true; - internalBeginToCompile(newUnits, newUnitSize); - } catch (SourceTypeCollisionException e) { - e.newAnnotationProcessorUnits = newProcessedUnits; - throw e; - } finally { - this.lookupEnvironment.isProcessingAnnotations = false; - this.annotationProcessorManager.reset(); - } - bottom = top; - top = this.totalUnits; // last unit added - this.annotationProcessorStartIndex = top; - } else { - bottom = top; - this.annotationProcessorManager.reset(); - } - } while (newUnitSize != 0 || newClassFilesSize != 0); - - this.annotationProcessorManager.processAnnotations(null, null, true); - // process potential units added in the final round see 329156 - ICompilationUnit[] newUnits = this.annotationProcessorManager.getNewUnits(); - newUnitSize = newUnits.length; - try { - if (newUnitSize != 0) { - ICompilationUnit[] newProcessedUnits = newUnits.clone(); // remember new units in case a source type collision occurs - try { - this.lookupEnvironment.isProcessingAnnotations = true; - internalBeginToCompile(newUnits, newUnitSize); - } catch (SourceTypeCollisionException e) { - e.isLastRound = true; - e.newAnnotationProcessorUnits = newProcessedUnits; - throw e; - } - } - } finally { - this.lookupEnvironment.isProcessingAnnotations = false; - this.annotationProcessorManager.reset(); - this.annotationProcessorManager.cleanUp(); - } - // Units added in final round don't get annotation processed - this.annotationProcessorStartIndex = this.totalUnits; - } - - public void reset() { - this.lookupEnvironment.reset(); - this.parser.scanner.source = null; - this.unitsToProcess = null; - if (DebugRequestor != null) DebugRequestor.reset(); - this.problemReporter.reset(); - } - - /** - * Internal API used to resolve a given compilation unit. Can run a subset of the compilation process - */ - public CompilationUnitDeclaration resolve( - CompilationUnitDeclaration unit, - ICompilationUnit sourceUnit, - boolean verifyMethods, - boolean analyzeCode, - boolean generateCode) { - - try { - if (unit == null) { - // build and record parsed units - this.parseThreshold = 0; // will request a full parse - beginToCompile(new ICompilationUnit[] { sourceUnit }); - // find the right unit from what was injected via accept(ICompilationUnit,..): - for (int i=0; i= this.size) - this.availableIndex = 0; - if (this.sleepCount <= -1) - notify(); // wake up writing thread to accept next unit - could be the last one - must avoid deadlock -} - -public CompilationUnitDeclaration removeNextUnit() throws Error { - CompilationUnitDeclaration next = null; - boolean yield = false; - synchronized (this) { - next = this.units[this.currentIndex]; - if (next == null || this.caughtException != null) { - do { - if (this.processingThread == null) { - if (this.caughtException != null) { - // rethrow the caught exception from the processingThread in the main compiler thread - if (this.caughtException instanceof Error) - throw (Error) this.caughtException; - throw (RuntimeException) this.caughtException; - } - return null; - } - //System.out.print('r'); - //if (this.sleepCount > 0) throw new IllegalStateException(Integer.valueOf(this.sleepCount).toString()); - this.sleepCount = -1; - try { - wait(100); - } catch (InterruptedException ignore) { - // ignore - } - this.sleepCount = 0; - next = this.units[this.currentIndex]; - } while (next == null); - } - - this.units[this.currentIndex++] = null; - if (this.currentIndex >= this.size) - this.currentIndex = 0; - if (this.sleepCount >= 1 && ++this.sleepCount > 4) { - notify(); // wake up processing thread to add next unit but only after removing some elements first - yield = this.sleepCount > 8; - } - } - if (yield) - Thread.yield(); - return next; -} - -@Override -public void run() { - boolean noAnnotations = this.compiler.annotationProcessorManager == null; - while (this.processingThread != null) { - this.unitToProcess = null; - int index = -1; - boolean cleanup = noAnnotations || this.compiler.shouldCleanup(this.unitIndex); - try { - synchronized (this) { - if (this.processingThread == null) return; - - this.unitToProcess = this.compiler.getUnitToProcess(this.unitIndex); - if (this.unitToProcess == null) { - this.processingThread = null; - return; - } - index = this.unitIndex++; - if (this.unitToProcess.compilationResult.hasBeenAccepted) - continue; - } - - try { - this.compiler.reportProgress(Messages.bind(Messages.compilation_processing, new String(this.unitToProcess.getFileName()))); - if (this.compiler.options.verbose) - this.compiler.out.println( - Messages.bind(Messages.compilation_process, - new String[] { - String.valueOf(index + 1), - String.valueOf(this.compiler.totalUnits), - new String(this.unitToProcess.getFileName()) - })); - this.compiler.process(this.unitToProcess, index); - } finally { - // cleanup compilation unit result, but only if not annotation processed. - if (this.unitToProcess != null && cleanup) - this.unitToProcess.cleanUp(); - } - - addNextUnit(this.unitToProcess); - } catch (Error | RuntimeException e) { - synchronized (this) { - this.processingThread = null; - this.caughtException = e; - } - return; - } - } -} - -public void shutdown() { - try { - Thread t = null; - synchronized (this) { - if (this.processingThread != null) { - t = this.processingThread; - this.processingThread = null; - notifyAll(); - } - } - if (t != null) - t.join(250); // do not wait forever - } catch (InterruptedException ignored) { - // ignore - } -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ReadManager.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ReadManager.java deleted file mode 100644 index 42ab9de..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ReadManager.java +++ /dev/null @@ -1,184 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008, 2013 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler; - -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; - -public class ReadManager implements Runnable { - ICompilationUnit[] units; - int nextFileToRead; - ICompilationUnit[] filesRead; - char[][] contentsRead; - int readyToReadPosition; - int nextAvailablePosition; - Thread[] readingThreads; - char[] readInProcessMarker = new char[0]; - int sleepingThreadCount; - private Throwable caughtException; - - static final int START_CUSHION = 5; - public static final int THRESHOLD = 10; - static final int CACHE_SIZE = 15; // do not waste memory by keeping too many files in memory - -public ReadManager(ICompilationUnit[] files, int length) { - // start the background threads to read the file's contents - int threadCount = Runtime.getRuntime().availableProcessors() + 1; - if (threadCount < 2) { - threadCount = 0; - } else if (threadCount > CACHE_SIZE) { - threadCount = CACHE_SIZE; - } - - if (threadCount > 0) { - synchronized (this) { - this.units = new ICompilationUnit[length]; - System.arraycopy(files, 0, this.units, 0, length); - this.nextFileToRead = START_CUSHION; // skip some files to reduce the number of times we have to wait - this.filesRead = new ICompilationUnit[CACHE_SIZE]; - this.contentsRead = new char[CACHE_SIZE][]; - this.readyToReadPosition = 0; - this.nextAvailablePosition = 0; - this.sleepingThreadCount = 0; - this.readingThreads = new Thread[threadCount]; - for (int i = threadCount; --i >= 0;) { - this.readingThreads[i] = new Thread(this, "Compiler Source File Reader"); //$NON-NLS-1$ - this.readingThreads[i].setDaemon(true); - this.readingThreads[i].start(); - } - } - } -} - -public char[] getContents(ICompilationUnit unit) throws Error { - Thread[] rThreads = this.readingThreads; - if (rThreads == null || this.units.length == 0) { - if (this.caughtException != null) { - // rethrow the caught exception from the readingThreads in the main compiler thread - if (this.caughtException instanceof Error) - throw (Error) this.caughtException; - throw (RuntimeException) this.caughtException; - } - return unit.getContents(); - } - - boolean yield = this.sleepingThreadCount == rThreads.length; - char[] result = null; - synchronized (this) { - if (unit == this.filesRead[this.readyToReadPosition]) { - result = this.contentsRead[this.readyToReadPosition]; - while (result == this.readInProcessMarker || result == null) { - // let the readingThread know we're waiting - //System.out.print('|'); - this.contentsRead[this.readyToReadPosition] = null; - try { - wait(250); - } catch (InterruptedException ignore) { // ignore - } - if (this.caughtException != null) { - // rethrow the caught exception from the readingThreads in the main compiler thread - if (this.caughtException instanceof Error) - throw (Error) this.caughtException; - throw (RuntimeException) this.caughtException; - } - result = this.contentsRead[this.readyToReadPosition]; - } - // free spot for next file - this.filesRead[this.readyToReadPosition] = null; - this.contentsRead[this.readyToReadPosition] = null; - if (++this.readyToReadPosition >= this.contentsRead.length) - this.readyToReadPosition = 0; - if (this.sleepingThreadCount > 0) { - //System.out.print('+'); - //System.out.print(this.nextFileToRead); - notify(); - } - } else { - // must make sure we're reading ahead of the unit - int unitIndex = 0; - for (int l = this.units.length; unitIndex < l; unitIndex++) - if (this.units[unitIndex] == unit) break; - if (unitIndex == this.units.length) { - // attempting to read a unit that was not included in the initial files - should not happen - this.units = new ICompilationUnit[0]; // stop looking for more - } else if (unitIndex >= this.nextFileToRead) { - // start over - //System.out.println(unitIndex + " vs " + this.nextFileToRead); - this.nextFileToRead = unitIndex + START_CUSHION; - this.readyToReadPosition = 0; - this.nextAvailablePosition = 0; - this.filesRead = new ICompilationUnit[CACHE_SIZE]; - this.contentsRead = new char[CACHE_SIZE][]; - notifyAll(); - } - } - } - if (yield) - Thread.yield(); // ensure other threads get a chance - if (result != null) - return result; - //System.out.print('-'); - return unit.getContents(); -} - -@Override -public void run() { - try { - while (this.readingThreads != null && this.nextFileToRead < this.units.length) { - ICompilationUnit unit = null; - int position = -1; - synchronized (this) { - if (this.readingThreads == null) return; - - while (this.filesRead[this.nextAvailablePosition] != null) { - this.sleepingThreadCount++; - try { - wait(250); // wait until a spot in contents is available - } catch (InterruptedException e) { // ignore - } - this.sleepingThreadCount--; - if (this.readingThreads == null) return; - } - - if (this.nextFileToRead >= this.units.length) return; - unit = this.units[this.nextFileToRead++]; - position = this.nextAvailablePosition; - if (++this.nextAvailablePosition >= this.contentsRead.length) - this.nextAvailablePosition = 0; - this.filesRead[position] = unit; - this.contentsRead[position] = this.readInProcessMarker; // mark the spot so we know its being read - } - char[] result = unit.getContents(); - synchronized (this) { - if (this.filesRead[position] == unit) { - if (this.contentsRead[position] == null) // wake up main thread which is waiting for this file - notifyAll(); - this.contentsRead[position] = result; - } - } - } - } catch (Error | RuntimeException e) { - synchronized (this) { - this.caughtException = e; - shutdown(); - } - return; - } -} - -public synchronized void shutdown() { - this.readingThreads = null; // mark the read manager as shutting down so that the reading threads stop - notifyAll(); -} -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java deleted file mode 100644 index 8998514..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/AnnotationDiscoveryVisitor.java +++ /dev/null @@ -1,289 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.apt.model.ElementImpl; -import org.eclipse.jdt.internal.compiler.apt.model.Factory; -import org.eclipse.jdt.internal.compiler.apt.util.ManyToMany; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.ast.Argument; -import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; -import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration; -import org.eclipse.jdt.internal.compiler.ast.RecordComponent; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.ast.TypeParameter; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.AptSourceLocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -/** - * This class is used to visit the JDT compiler internal AST to discover annotations, - * in the course of dispatching to annotation processors. - */ -public class AnnotationDiscoveryVisitor extends ASTVisitor { - final BaseProcessingEnvImpl _env; - final Factory _factory; - /** - * Collects a many-to-many map of annotation types to - * the elements they appear on. - */ - final ManyToMany _annoToElement; - - public AnnotationDiscoveryVisitor(BaseProcessingEnvImpl env) { - this._env = env; - this._factory = env.getFactory(); - this._annoToElement = new ManyToMany<>(); - } - - @Override - public boolean visit(Argument argument, BlockScope scope) { - Annotation[] annotations = argument.annotations; - ReferenceContext referenceContext = scope.referenceContext(); - if (referenceContext instanceof AbstractMethodDeclaration) { - MethodBinding binding = ((AbstractMethodDeclaration) referenceContext).binding; - if (binding != null) { - TypeDeclaration typeDeclaration = scope.referenceType(); - typeDeclaration.binding.resolveTypesFor(binding); - if (argument.binding != null) { - argument.binding = new AptSourceLocalVariableBinding(argument.binding, binding); - } - } - if (annotations != null && argument.binding != null) { - this.resolveAnnotations( - scope, - annotations, - argument.binding); - } - } - return false; - } - - @Override - public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope scope) { - Annotation[] annotations = constructorDeclaration.annotations; - if (annotations != null) { - MethodBinding constructorBinding = constructorDeclaration.binding; - if (constructorBinding == null) { - return false; - } - ((SourceTypeBinding) constructorBinding.declaringClass).resolveTypesFor(constructorBinding); - this.resolveAnnotations( - constructorDeclaration.scope, - annotations, - constructorBinding); - } - - TypeParameter[] typeParameters = constructorDeclaration.typeParameters; - if (typeParameters != null) { - int typeParametersLength = typeParameters.length; - for (int i = 0; i < typeParametersLength; i++) { - typeParameters[i].traverse(this, constructorDeclaration.scope); - } - } - - Argument[] arguments = constructorDeclaration.arguments; - if (arguments != null) { - int argumentLength = arguments.length; - for (int i = 0; i < argumentLength; i++) { - arguments[i].traverse(this, constructorDeclaration.scope); - } - } - return false; - } - - @Override - public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) { - Annotation[] annotations = fieldDeclaration.annotations; - if (annotations != null) { - FieldBinding fieldBinding = fieldDeclaration.binding; - if (fieldBinding == null) { - return false; - } - ((SourceTypeBinding) fieldBinding.declaringClass).resolveTypeFor(fieldBinding); - if (fieldDeclaration.binding == null) { - return false; - } - this.resolveAnnotations(scope, annotations, fieldBinding); - } - return false; - } - - @Override - public boolean visit(RecordComponent recordComponent, BlockScope scope) { - Annotation[] annotations = recordComponent.annotations; - if (annotations != null) { - RecordComponentBinding recordComponentBinding = recordComponent.binding; - if (recordComponentBinding == null) { - return false; - } - ((SourceTypeBinding) recordComponentBinding.declaringRecord).resolveTypeFor(recordComponentBinding); - if (recordComponent.binding == null) { - return false; - } - this.resolveAnnotations(scope, annotations, recordComponentBinding); - } - return false; - } - @Override - public boolean visit(TypeParameter typeParameter, ClassScope scope) { - Annotation[] annotations = typeParameter.annotations; - if (annotations != null) { - TypeVariableBinding binding = typeParameter.binding; - if (binding == null) { - return false; - } - this.resolveAnnotations(scope.referenceContext.initializerScope, annotations, binding); - } - return false; - } - - @Override - public boolean visit(TypeParameter typeParameter, BlockScope scope) { - Annotation[] annotations = typeParameter.annotations; - if (annotations != null) { - TypeVariableBinding binding = typeParameter.binding; - if (binding == null) { - return false; - } - // when we get here, it is guaranteed that class type parameters are connected, but method type parameters may not be. - MethodBinding methodBinding = (MethodBinding) binding.declaringElement; - ((SourceTypeBinding) methodBinding.declaringClass).resolveTypesFor(methodBinding); - this.resolveAnnotations(scope, annotations, binding); - } - return false; - } - - @Override - public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) { - Annotation[] annotations = methodDeclaration.annotations; - if (annotations != null) { - MethodBinding methodBinding = methodDeclaration.binding; - if (methodBinding == null) { - return false; - } - ((SourceTypeBinding) methodBinding.declaringClass).resolveTypesFor(methodBinding); - this.resolveAnnotations( - methodDeclaration.scope, - annotations, - methodBinding); - } - - TypeParameter[] typeParameters = methodDeclaration.typeParameters; - if (typeParameters != null) { - int typeParametersLength = typeParameters.length; - for (int i = 0; i < typeParametersLength; i++) { - typeParameters[i].traverse(this, methodDeclaration.scope); - } - } - - Argument[] arguments = methodDeclaration.arguments; - if (arguments != null) { - int argumentLength = arguments.length; - for (int i = 0; i < argumentLength; i++) { - arguments[i].traverse(this, methodDeclaration.scope); - } - } - return false; - } - - @Override - public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) { - SourceTypeBinding binding = memberTypeDeclaration.binding; - if (binding == null) { - return false; - } - Annotation[] annotations = memberTypeDeclaration.annotations; - if (annotations != null) { - this.resolveAnnotations( - memberTypeDeclaration.staticInitializerScope, - annotations, - binding); - } - return true; - } - - @Override - public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope scope) { - SourceTypeBinding binding = typeDeclaration.binding; - if (binding == null) { - return false; - } - Annotation[] annotations = typeDeclaration.annotations; - if (annotations != null) { - this.resolveAnnotations( - typeDeclaration.staticInitializerScope, - annotations, - binding); - } - return true; - } - @Override - public boolean visit(ModuleDeclaration module, CompilationUnitScope scope) { - ModuleBinding binding = module.binding; - if (binding == null) { - return false; - } - //module.resolveTypeDirectives(scope); - // The above call also resolvesAnnotations <=== actually this doesn't populate _annoToElement which is what we need - - Annotation[] annotations = module.annotations; - if (annotations != null) { - this.resolveAnnotations(module.scope, - annotations, - binding); - } - return true; - } - - private void resolveAnnotations(BlockScope scope, Annotation[] annotations, Binding currentBinding) { - - int length = annotations == null ? 0 : annotations.length; - if (length == 0) - return; - - boolean old = scope.insideTypeAnnotation; - scope.insideTypeAnnotation = true; - currentBinding.getAnnotationTagBits(); - scope.insideTypeAnnotation = old; - ElementImpl element = (ElementImpl) this._factory.newElement(currentBinding); - AnnotationBinding [] annotationBindings = element.getPackedAnnotationBindings(); // discovery is never in terms of repeating annotation. - for (AnnotationBinding binding : annotationBindings) { - ReferenceBinding annotationType = binding.getAnnotationType(); - if (Annotation.isAnnotationTargetAllowed(scope, annotationType, currentBinding) - ) { // binding should be resolved, but in case it's not, ignore it: it could have been wrapped into a container. - TypeElement anno = (TypeElement)this._factory.newElement(annotationType); - this._annoToElement.put(anno, element); - } - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java deleted file mode 100644 index f6128ff..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/AptProblem.java +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001, 2007 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; - -public class AptProblem extends DefaultProblem { - - // The batch compiler does not depend on org.eclipse.jdt.apt.pluggable.core; this - // is just an arbitrary string to it, namespace notwithstanding. However, the IDE - // cares about the fact that this string is registered as a marker ID by the - // org.eclipse.jdt.apt.pluggable.core plug-in. - private static final String MARKER_ID = "org.eclipse.jdt.apt.pluggable.core.compileProblem"; //$NON-NLS-1$ - - /** May be null, if it was not possible to identify problem context */ - public final ReferenceContext _referenceContext; - - public AptProblem( - ReferenceContext referenceContext, - char[] originatingFileName, - String message, - int id, - String[] stringArguments, - int severity, - int startPosition, - int endPosition, - int line, - int column) - { - super(originatingFileName, - message, - id, - stringArguments, - severity, - startPosition, - endPosition, - line, - column); - this._referenceContext = referenceContext; - } - - @Override - public int getCategoryID() { - return CAT_UNSPECIFIED; - } - - @Override - public String getMarkerType() { - return MARKER_ID; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java deleted file mode 100644 index e16725f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseAnnotationProcessorManager.java +++ /dev/null @@ -1,177 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2018 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager; -import org.eclipse.jdt.internal.compiler.Compiler; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; - -/** - * This class is the central dispatch point for Java 6 annotation processing. - * This is created and configured by the JDT core; specifics depend on how - * compilation is being performed, ie from the command line, via the Tool - * interface, or within the IDE. This class manages the discovery of annotation - * processors and other information spanning multiple rounds of processing; - * context that is valid only within a single round is managed by - * {@link RoundDispatcher}. There may be multiple instances of this class; - * there is in general one of these for every Compiler that has annotation - * processing enabled. Within the IDE there will typically be one for every - * Java project, because each project potentially has a separate processor path. - * - * TODO: do something useful with _supportedOptions and _supportedAnnotationTypes. - */ -public abstract class BaseAnnotationProcessorManager extends AbstractAnnotationProcessorManager - implements IProcessorProvider -{ - - protected PrintWriter _out; - protected PrintWriter _err; - protected BaseProcessingEnvImpl _processingEnv; - public boolean _isFirstRound = true; - - /** - * The list of processors that have been loaded so far. A processor on this - * list has been initialized, but may not yet have been called to process(). - */ - protected List _processors = new ArrayList<>(); - - // Tracing - protected boolean _printProcessorInfo = false; - protected boolean _printRounds = false; - protected int _round; - - /* (non-Javadoc) - * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#configure(org.eclipse.jdt.internal.compiler.batch.Main, java.lang.String[]) - */ - @Override - public void configure(Object batchCompiler, String[] options) { - // Implemented by BatchAnnotationProcessorManager. - throw new UnsupportedOperationException(); - } - - /* (non-Javadoc) - * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#configureFromPlatform(org.eclipse.jdt.internal.compiler.Compiler, java.lang.Object) - */ - @Override - public void configureFromPlatform(Compiler compiler, Object compilationUnitLocator, Object javaProject, boolean isTestCode) { - // Implemented by IdeAnnotationProcessorManager. - throw new UnsupportedOperationException(); - } - - @Override - public List getDiscoveredProcessors() { - return this._processors; - } - - @Override - public ICompilationUnit[] getDeletedUnits() { - return this._processingEnv.getDeletedUnits(); - } - - @Override - public ICompilationUnit[] getNewUnits() { - return this._processingEnv.getNewUnits(); - } - - @Override - public ReferenceBinding[] getNewClassFiles() { - return this._processingEnv.getNewClassFiles(); - } - - @Override - public void reset() { - this._processingEnv.reset(); - } - - /* (non-Javadoc) - * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setErr(java.io.PrintWriter) - */ - @Override - public void setErr(PrintWriter err) { - this._err = err; - } - - /* (non-Javadoc) - * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setOut(java.io.PrintWriter) - */ - @Override - public void setOut(PrintWriter out) { - this._out = out; - } - - /* (non-Javadoc) - * @see org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager#setProcessors(java.lang.Object[]) - */ - @Override - public void setProcessors(Object[] processors) { - // Only meaningful in batch mode. - throw new UnsupportedOperationException(); - } - - /** - * A single "round" of processing, in the sense implied in - * {@link javax.annotation.processing.Processor}. - *

- * The Java 6 Processor spec contains ambiguities about how processors that support "*" are - * handled. Eclipse tries to match Sun's implementation in javac. What that actually does is - * analogous to inspecting the set of annotions found in the root units and adding an - * "imaginary" annotation if the set is empty. Processors are then called in order of discovery; - * for each processor, the intersection between the set of root annotations and the set of - * annotations the processor supports is calculated, and if it is non-empty, the processor is - * called. If the processor returns true then the intersection (including the - * imaginary annotation if one exists) is removed from the set of root annotations and the loop - * continues, until the set is empty. Of course, the imaginary annotation is not actually - * included in the set of annotations passed in to the processor. A processor's process() method - * is not called until its intersection set is non-empty, but thereafter it is called on every - * round. Note that even if a processor is not called in the first round, if it is called in - * subsequent rounds, it will be called in the order in which the processors were discovered, - * rather than being added to the end of the list. - */ - @Override - public void processAnnotations(CompilationUnitDeclaration[] units, ReferenceBinding[] referenceBindings, boolean isLastRound) { - if (units != null) { - for (CompilationUnitDeclaration declaration : units) { - if (declaration != null && declaration.scope != null) { - ModuleBinding m = declaration.scope.module(); - if (m != null) { - this._processingEnv._current_module = m; - break; - } - } - } - } - RoundEnvImpl roundEnv = new RoundEnvImpl(units, referenceBindings, isLastRound, this._processingEnv); - PrintWriter out = this._out; // closable resource not manages in this class - PrintWriter traceProcessorInfo = this._printProcessorInfo ? out : null; - PrintWriter traceRounds = this._printRounds ? out : null; - if (traceRounds != null) { - traceRounds.println("Round " + ++this._round + ':'); //$NON-NLS-1$ - } - RoundDispatcher dispatcher = new RoundDispatcher( - this, roundEnv, roundEnv.getRootAnnotations(), traceProcessorInfo, traceRounds); - dispatcher.round(); - if (this._isFirstRound) { - this._isFirstRound = false; - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java deleted file mode 100644 index fd51160..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseMessagerImpl.java +++ /dev/null @@ -1,269 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2023 BEA Systems, Inc. and others - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - derived base class from BatchMessagerImpl - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.tools.Diagnostic.Kind; - -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.apt.model.AnnotationMemberValue; -import org.eclipse.jdt.internal.compiler.apt.model.AnnotationMirrorImpl; -import org.eclipse.jdt.internal.compiler.apt.model.ExecutableElementImpl; -import org.eclipse.jdt.internal.compiler.apt.model.ModuleElementImpl; -import org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl; -import org.eclipse.jdt.internal.compiler.apt.model.VariableElementImpl; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.ast.ArrayInitializer; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Expression; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; -import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; -import org.eclipse.jdt.internal.compiler.ast.MemberValuePair; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.AptSourceLocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class BaseMessagerImpl { - - static final String[] NO_ARGUMENTS = new String[0]; - - /** - * Create a CategorizedProblem that can be reported to an ICompilerRequestor, etc. - * - * @param e the element against which to report the message. If the element is not - * in the set of elements being compiled in the current round, the reference context - * and filename will be set to null. - * @return a new {@link AptProblem} - */ - public static AptProblem createProblem(Kind kind, CharSequence msg, Element e, - AnnotationMirror a, AnnotationValue v) { - ReferenceContext referenceContext = null; - Annotation[] elementAnnotations = null; - int startPosition = 0; - int endPosition = 0; - if (e != null) { - switch(e.getKind()) { - case MODULE: - ModuleElementImpl moduleElementImpl = (ModuleElementImpl) e; - Binding moduleBinding = moduleElementImpl._binding; - if (moduleBinding instanceof SourceModuleBinding) { - SourceModuleBinding sourceModuleBinding = (SourceModuleBinding) moduleBinding; - CompilationUnitDeclaration unitDeclaration = (CompilationUnitDeclaration) sourceModuleBinding.scope.referenceContext(); - referenceContext = unitDeclaration; - elementAnnotations = unitDeclaration.moduleDeclaration.annotations; - startPosition = unitDeclaration.moduleDeclaration.sourceStart; - endPosition = unitDeclaration.moduleDeclaration.sourceEnd; - } - break; - case ANNOTATION_TYPE : - case INTERFACE : - case CLASS : - case ENUM : - TypeElementImpl typeElementImpl = (TypeElementImpl) e; - Binding typeBinding = typeElementImpl._binding; - if (typeBinding instanceof SourceTypeBinding) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) typeBinding; - TypeDeclaration typeDeclaration = (TypeDeclaration) sourceTypeBinding.scope.referenceContext(); - referenceContext = typeDeclaration; - elementAnnotations = typeDeclaration.annotations; - startPosition = typeDeclaration.sourceStart; - endPosition = typeDeclaration.sourceEnd; - } - break; - case PACKAGE : - // nothing to do: there is no reference context for a package - break; - case CONSTRUCTOR : - case METHOD : - ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) e; - Binding binding = executableElementImpl._binding; - if (binding instanceof MethodBinding) { - MethodBinding methodBinding = (MethodBinding) binding; - AbstractMethodDeclaration sourceMethod = methodBinding.sourceMethod(); - if (sourceMethod != null) { - referenceContext = sourceMethod; - elementAnnotations = sourceMethod.annotations; - startPosition = sourceMethod.sourceStart; - endPosition = sourceMethod.sourceEnd; - } - } - break; - case ENUM_CONSTANT : - break; - case EXCEPTION_PARAMETER : - break; - case FIELD : - case PARAMETER : - VariableElementImpl variableElementImpl = (VariableElementImpl) e; - binding = variableElementImpl._binding; - if (binding instanceof FieldBinding) { - FieldBinding fieldBinding = (FieldBinding) binding; - FieldDeclaration fieldDeclaration = fieldBinding.sourceField(); - if (fieldDeclaration != null) { - ReferenceBinding declaringClass = fieldBinding.declaringClass; - if (declaringClass instanceof SourceTypeBinding) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) declaringClass; - TypeDeclaration typeDeclaration = (TypeDeclaration) sourceTypeBinding.scope.referenceContext(); - referenceContext = typeDeclaration; - } - elementAnnotations = fieldDeclaration.annotations; - startPosition = fieldDeclaration.sourceStart; - endPosition = fieldDeclaration.sourceEnd; - } - } else if (binding instanceof AptSourceLocalVariableBinding){ - AptSourceLocalVariableBinding parameterBinding = (AptSourceLocalVariableBinding) binding; - LocalDeclaration parameterDeclaration = parameterBinding.declaration; - if (parameterDeclaration != null) { - MethodBinding methodBinding = parameterBinding.methodBinding; - if (methodBinding != null) { - referenceContext = methodBinding.sourceMethod(); - } - elementAnnotations = parameterDeclaration.annotations; - startPosition = parameterDeclaration.sourceStart; - endPosition = parameterDeclaration.sourceEnd; - } - } - break; - case INSTANCE_INIT : - case STATIC_INIT : - break; - case LOCAL_VARIABLE : - break; - case TYPE_PARAMETER : - default: - break; - } - } - StringBuilder builder = new StringBuilder(); - if (msg != null) { - builder.append(msg); - } - if (a != null && elementAnnotations != null) { - AnnotationBinding annotationBinding = ((AnnotationMirrorImpl) a)._binding; - Annotation annotation = findAnnotation(elementAnnotations, annotationBinding); - if (annotation != null) { - startPosition = annotation.sourceStart; - endPosition = annotation.sourceEnd; - if (v != null && v instanceof AnnotationMemberValue) { - MethodBinding methodBinding = ((AnnotationMemberValue) v).getMethodBinding(); - MemberValuePair[] memberValuePairs = annotation.memberValuePairs(); - MemberValuePair memberValuePair = null; - for (int i = 0; memberValuePair == null && i < memberValuePairs.length; i++) { - if (methodBinding == memberValuePairs[i].binding) { - memberValuePair = memberValuePairs[i]; - } - } - if (memberValuePair != null) { - startPosition = memberValuePair.sourceStart; - endPosition = memberValuePair.sourceEnd; - } - } - } - } - int lineNumber = 0; - int columnNumber = 1; - char[] fileName = null; - if (referenceContext != null) { - CompilationResult result = referenceContext.compilationResult(); - fileName = result.fileName; - int[] lineEnds = null; - lineNumber = startPosition >= 0 - ? Util.getLineNumber(startPosition, lineEnds = result.getLineSeparatorPositions(), 0, lineEnds.length-1) - : 0; - columnNumber = startPosition >= 0 - ? Util.searchColumnNumber(result.getLineSeparatorPositions(), lineNumber,startPosition) - : 0; - } - int severity; - switch(kind) { - case ERROR : - severity = ProblemSeverities.Error; - break; - case NOTE : - case OTHER: - severity = ProblemSeverities.Info; - break; - default : - severity = ProblemSeverities.Warning; - break; - } - return new AptProblem( - referenceContext, - fileName, - String.valueOf(builder), - 0, - NO_ARGUMENTS, - severity, - startPosition, - endPosition, - lineNumber, - columnNumber); - } - - private static Annotation findAnnotation(Annotation[] elementAnnotations, AnnotationBinding annotationBinding) { - for (int i = 0; i < elementAnnotations.length; i++) { - Annotation annotation = findAnnotation(elementAnnotations[i], annotationBinding); - if (annotation != null) { - return annotation; - } - } - return null; - } - - private static Annotation findAnnotation(Annotation elementAnnotation, AnnotationBinding annotationBinding) { - if (annotationBinding == elementAnnotation.getCompilerAnnotation()) { - return elementAnnotation; - } - - MemberValuePair[] memberValuePairs = elementAnnotation.memberValuePairs(); - for (MemberValuePair mvp : memberValuePairs) { - Expression v = mvp.value; - if (v instanceof Annotation) { - Annotation a = findAnnotation((Annotation) v, annotationBinding); - if (a != null) { - return a; - } - } else if (v instanceof ArrayInitializer) { - Expression[] expressions = ((ArrayInitializer) v).expressions; - for (Expression e : expressions) { - if (e instanceof Annotation) { - Annotation a = findAnnotation((Annotation) e, annotationBinding); - if (a != null) { - return a; - } - } - } - } - } - return null; - } - - public BaseMessagerImpl() { - super(); - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java deleted file mode 100644 index 135fb7a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BaseProcessingEnvImpl.java +++ /dev/null @@ -1,225 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2023 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * IBM Corporation - fix for 342598 - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.annotation.processing.Filer; -import javax.annotation.processing.Messager; -import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; -import javax.tools.JavaFileManager; - -import org.eclipse.jdt.internal.compiler.Compiler; -import org.eclipse.jdt.internal.compiler.apt.model.ElementsImpl; -import org.eclipse.jdt.internal.compiler.apt.model.Factory; -import org.eclipse.jdt.internal.compiler.apt.model.TypesImpl; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; - -/** - * Implementation of ProcessingEnvironment that is common to batch and IDE environments. - */ -public abstract class BaseProcessingEnvImpl implements ProcessingEnvironment { - - /** - * The minimal required Java runtime version (we need to run compiler on) - */ - public static final SourceVersion MINIMAL_REQUIRED_RUNTIME_VERSION = SourceVersion.RELEASE_17; - private static final long VERSION_FOR_MINIMAL_RUNTIME = ClassFileConstants.JDK17; - - // Initialized in subclasses: - protected Filer _filer; - protected Messager _messager; - protected Map _processorOptions; - protected Compiler _compiler; - - // Initialized in this base class: - protected Elements _elementUtils; - protected Types _typeUtils; - private final List _addedUnits; - private final List _addedClassFiles; - private final List _deletedUnits; - private boolean _errorRaised; - private final Factory _factory; - public ModuleBinding _current_module; - - public BaseProcessingEnvImpl() { - this._addedUnits = new ArrayList<>(); - this._addedClassFiles = new ArrayList<>(); - this._deletedUnits = new ArrayList<>(); - this._elementUtils = ElementsImpl.create(this); - this._typeUtils = new TypesImpl(this); - this._factory = new Factory(this); - this._errorRaised = false; - } - - public void addNewUnit(ICompilationUnit unit) { - this._addedUnits.add(unit); - } - - public void addNewClassFile(ReferenceBinding binding) { - this._addedClassFiles.add(binding); - } - - public Compiler getCompiler() { - return this._compiler; - } - - public ICompilationUnit[] getDeletedUnits() { - ICompilationUnit[] result = new ICompilationUnit[this._deletedUnits.size()]; - this._deletedUnits.toArray(result); - return result; - } - - public ICompilationUnit[] getNewUnits() { - ICompilationUnit[] result = new ICompilationUnit[this._addedUnits.size()]; - this._addedUnits.toArray(result); - return result; - } - - @Override - public Elements getElementUtils() { - return this._elementUtils; - } - - @Override - public Filer getFiler() { - return this._filer; - } - - @Override - public Messager getMessager() { - return this._messager; - } - - @Override - public Map getOptions() { - return this._processorOptions; - } - - @Override - public Types getTypeUtils() { - return this._typeUtils; - } - - public LookupEnvironment getLookupEnvironment() { - return this._compiler.lookupEnvironment; - } - - @Override - public SourceVersion getSourceVersion() { - final long sourceLevel = this._compiler.options.sourceLevel; - if (sourceLevel <= ClassFileConstants.JDK1_5) { - return SourceVersion.RELEASE_5; - } - if (sourceLevel == ClassFileConstants.JDK1_6) { - return SourceVersion.RELEASE_6; - } else if (sourceLevel == ClassFileConstants.JDK1_7) { - return SourceVersion.RELEASE_7; - } else if (sourceLevel == ClassFileConstants.JDK1_8) { - return SourceVersion.RELEASE_8; - } else if (sourceLevel == ClassFileConstants.JDK9) { - return SourceVersion.RELEASE_9; - } else if (sourceLevel == ClassFileConstants.JDK10) { - return SourceVersion.RELEASE_10; - } else if (sourceLevel == ClassFileConstants.JDK11) { - return SourceVersion.RELEASE_11; - } else if (sourceLevel == ClassFileConstants.JDK12) { - return SourceVersion.RELEASE_12; - } else if (sourceLevel == ClassFileConstants.JDK13) { - return SourceVersion.RELEASE_13; - } else if (sourceLevel == ClassFileConstants.JDK14) { - return SourceVersion.RELEASE_14; - } else if (sourceLevel == ClassFileConstants.JDK15) { - return SourceVersion.RELEASE_15; - } else if (sourceLevel == ClassFileConstants.JDK16) { - return SourceVersion.RELEASE_16; - } else if (sourceLevel == ClassFileConstants.JDK17) { - return SourceVersion.RELEASE_17; - } - // From here on we can't use constants that may not be yet defined in - // minimal required runtime Java version we have to avoid - // errors like java.lang.NoSuchFieldError: RELEASE_20 - if (sourceLevel > VERSION_FOR_MINIMAL_RUNTIME) { - try { - return SourceVersion.valueOf("RELEASE_" + CompilerOptions.versionFromJdkLevel(sourceLevel)); //$NON-NLS-1$ - } catch (IllegalArgumentException e) { - // handle call on a minimal release we can run on - return MINIMAL_REQUIRED_RUNTIME_VERSION; - } - } else { - // to make compiler happy, should never happen - throw new IllegalStateException("Invalid JDK source level: " + sourceLevel); //$NON-NLS-1$ - } - } - - /** - * Called when AnnotationProcessorManager has retrieved the list of - * newly generated compilation units (ie, once per round) - */ - public void reset() { - this._addedUnits.clear(); - this._addedClassFiles.clear(); - this._deletedUnits.clear(); - } - - /** - * Has an error been raised in any of the rounds of processing in this build? - * @return error flag - */ - public boolean errorRaised() - { - return this._errorRaised; - } - - /** - * Set or clear the errorRaised flag. Typically this will be set by the Messager - * when an error has been raised, and it will never be cleared. - */ - public void setErrorRaised(boolean b) - { - this._errorRaised = true; - } - - public Factory getFactory() - { - return this._factory; - } - - public ReferenceBinding[] getNewClassFiles() { - ReferenceBinding[] result = new ReferenceBinding[this._addedClassFiles.size()]; - this._addedClassFiles.toArray(result); - return result; - } - @Override - public boolean isPreviewEnabled() { - return this._compiler.options.enablePreviewFeatures; - } - - public JavaFileManager getFileManager() { - return null; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java deleted file mode 100644 index e5e904f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchAnnotationProcessorManager.java +++ /dev/null @@ -1,269 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.io.File; -import java.io.IOException; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; - -import javax.annotation.processing.Processor; -import javax.lang.model.SourceVersion; -import javax.tools.JavaFileManager; -import javax.tools.StandardJavaFileManager; -import javax.tools.StandardLocation; - -import org.eclipse.jdt.internal.compiler.batch.Main; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; - -/** - * Java 6 annotation processor manager used when compiling from the command line - * or via the javax.tools.JavaCompiler interface. - */ -public class BatchAnnotationProcessorManager extends BaseAnnotationProcessorManager -{ - - /** - * Processors that have been set by calling CompilationTask.setProcessors(). - */ - private List _setProcessors = null; - private Iterator _setProcessorIter = null; - - /** - * Processors named with the -processor option on the command line. - */ - private List _commandLineProcessors; - private Iterator _commandLineProcessorIter = null; - - private ServiceLoader _serviceLoader = null; - private Iterator _serviceLoaderIter; - - private ClassLoader _procLoader; - - // Set this to true in order to trace processor discovery when -XprintProcessorInfo is specified - private final static boolean VERBOSE_PROCESSOR_DISCOVERY = true; - private boolean _printProcessorDiscovery = false; - - /** - * Zero-arg constructor so this object can be easily created via reflection. - * A BatchAnnotationProcessorManager cannot be used until its - * {@link #configure(Object, String[])} method has been called. - */ - public BatchAnnotationProcessorManager() - { - } - - @Override - public void configure(Object batchCompiler, String[] commandLineArguments) { - if (null != this._processingEnv) { - throw new IllegalStateException( - "Calling configure() more than once on an AnnotationProcessorManager is not supported"); //$NON-NLS-1$ - } - BatchProcessingEnvImpl processingEnv = new BatchProcessingEnvImpl(this, (Main) batchCompiler, commandLineArguments); - this._processingEnv = processingEnv; - @SuppressWarnings("resource") // fileManager is not opened here - JavaFileManager fileManager = processingEnv.getFileManager(); - if (fileManager instanceof StandardJavaFileManager) { - Iterable location = null; - if (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) > 0) { - location = ((StandardJavaFileManager) fileManager).getLocation(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH); - } - if (location != null) { - this._procLoader = fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_MODULE_PATH); - } else { - this._procLoader = fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH); - } - } else { - // Fall back to old code - this._procLoader = fileManager.getClassLoader(StandardLocation.ANNOTATION_PROCESSOR_PATH); - } - parseCommandLine(commandLineArguments); - this._round = 0; - } - - /** - * If a -processor option was specified in command line arguments, - * parse it into a list of qualified classnames. - * @param commandLineArguments contains one string for every space-delimited token on the command line - */ - private void parseCommandLine(String[] commandLineArguments) { - List commandLineProcessors = null; - for (int i = 0; i < commandLineArguments.length; ++i) { - String option = commandLineArguments[i]; - if ("-XprintProcessorInfo".equals(option)) { //$NON-NLS-1$ - this._printProcessorInfo = true; - this._printProcessorDiscovery = VERBOSE_PROCESSOR_DISCOVERY; - } - else if ("-XprintRounds".equals(option)) { //$NON-NLS-1$ - this._printRounds = true; - } - else if ("-processor".equals(option)) { //$NON-NLS-1$ - commandLineProcessors = new ArrayList<>(); - String procs = commandLineArguments[++i]; - commandLineProcessors.addAll(Arrays.asList(procs.split(","))); //$NON-NLS-1$ - break; - } - } - this._commandLineProcessors = commandLineProcessors; - if (null != this._commandLineProcessors) { - this._commandLineProcessorIter = this._commandLineProcessors.iterator(); - } - } - - @Override - public ProcessorInfo discoverNextProcessor() { - if (null != this._setProcessors) { - // If setProcessors() was called, use that list until it's empty and then stop. - if (this._setProcessorIter.hasNext()) { - Processor p = this._setProcessorIter.next(); - p.init(this._processingEnv); - ProcessorInfo pi = new ProcessorInfo(p); - this._processors.add(pi); - if (this._printProcessorDiscovery && null != this._out) { - this._out.println("API specified processor: " + pi); //$NON-NLS-1$ - } - return pi; - } - return null; - } - - if (null != this._commandLineProcessors) { - // If there was a -processor option, iterate over processor names, - // creating and initializing processors, until no more names are found, then stop. - if (this._commandLineProcessorIter.hasNext()) { - String proc = this._commandLineProcessorIter.next(); - try { - Class clazz = this._procLoader.loadClass(proc); - Object o = clazz.getDeclaredConstructor().newInstance(); - Processor p = (Processor) o; - p.init(this._processingEnv); - ProcessorInfo pi = new ProcessorInfo(p); - this._processors.add(pi); - if (this._printProcessorDiscovery && null != this._out) { - this._out.println("Command line specified processor: " + pi); //$NON-NLS-1$ - } - return pi; - } catch (Exception e) { - // TODO: better error handling - throw new AbortCompilation(null, e); - } - } - return null; - } - - // if no processors were explicitly specified with setProcessors() - // or the command line, search the processor path with ServiceLoader. - if (null == this._serviceLoader ) { - this._serviceLoader = ServiceLoader.load(Processor.class, this._procLoader); - this._serviceLoaderIter = this._serviceLoader.iterator(); - } - try { - if (this._serviceLoaderIter.hasNext()) { - Processor p = this._serviceLoaderIter.next(); - p.init(this._processingEnv); - ProcessorInfo pi = new ProcessorInfo(p); - this._processors.add(pi); - if (this._printProcessorDiscovery && null != this._out) { - StringBuilder sb = new StringBuilder(); - sb.append("Discovered processor service "); //$NON-NLS-1$ - sb.append(pi); - sb.append("\n supporting "); //$NON-NLS-1$ - sb.append(pi.getSupportedAnnotationTypesAsString()); - sb.append("\n in "); //$NON-NLS-1$ - sb.append(getProcessorLocation(p)); - this._out.println(sb.toString()); - } - return pi; - } - } catch (ServiceConfigurationError e) { - // TODO: better error handling - throw new AbortCompilation(null, e); - } - return null; - } - - /** - * Used only for debugging purposes. Generates output like "file:jar:D:/temp/jarfiles/myJar.jar!/". - * Surely this code already exists in several hundred other places? - * @return the location whence a processor class was loaded. - */ - private String getProcessorLocation(Processor p) { - // Get the classname in a form that can be passed to ClassLoader.getResource(), - // e.g., "pa/pb/pc/Outer$Inner.class" - boolean isMember = false; - Class outerClass = p.getClass(); - StringBuilder innerName = new StringBuilder(); - while (outerClass.isMemberClass()) { - innerName.insert(0, outerClass.getSimpleName()); - innerName.insert(0, '$'); - isMember = true; - outerClass = outerClass.getEnclosingClass(); - } - String path = outerClass.getName(); - path = path.replace('.', '/'); - if (isMember) { - path = path + innerName; - } - path = path + ".class"; //$NON-NLS-1$ - - // Find the URL for the class resource and strip off the resource name itself - String location = this._procLoader.getResource(path).toString(); - if (location.endsWith(path)) { - location = location.substring(0, location.length() - path.length()); - } - return location; - } - - @Override - public void reportProcessorException(Processor p, Exception e) { - // TODO: if (verbose) report the processor - throw new AbortCompilation(null, e); - } - - @Override - public void setProcessors(Object[] processors) { - if (!this._isFirstRound) { - throw new IllegalStateException("setProcessors() cannot be called after processing has begun"); //$NON-NLS-1$ - } - // Cast all the processors here, rather than failing later. - // But don't call init() until the processor is actually needed. - this._setProcessors = new ArrayList<>(processors.length); - for (Object o : processors) { - Processor p = (Processor)o; - this._setProcessors.add(p); - } - this._setProcessorIter = this._setProcessors.iterator(); - - // processors set this way take precedence over anything on the command line - this._commandLineProcessors = null; - this._commandLineProcessorIter = null; - } - - @Override - protected void cleanUp() { - // the classloader needs to be kept open between rounds, close it at the end: - if (this._procLoader instanceof URLClassLoader) { - try { - ((URLClassLoader) this._procLoader).close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java deleted file mode 100644 index 66c9a55..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchFilerImpl.java +++ /dev/null @@ -1,182 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2018 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * philippe.marschall@netcetera.ch - Fix for 338370 - * IBM Corporation - Fix for validating relative name - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.URI; -import java.util.HashSet; - -import javax.annotation.processing.Filer; -import javax.annotation.processing.FilerException; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import javax.tools.FileObject; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.StandardLocation; -import javax.tools.JavaFileManager.Location; - -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; - -/** - * Implementation of Filer used when compilation is driven by command line - * or by Tool interface. This version does not need to keep track of - * dependencies. - */ -public class BatchFilerImpl implements Filer { - - protected final BaseAnnotationProcessorManager _dispatchManager; - protected final BatchProcessingEnvImpl _env; - protected final JavaFileManager _fileManager; - protected final HashSet _createdFiles; - - public BatchFilerImpl(BaseAnnotationProcessorManager dispatchManager, BatchProcessingEnvImpl env) - { - this._dispatchManager = dispatchManager; - this._fileManager = env._fileManager; - this._env = env; - this._createdFiles = new HashSet<>(); - } - - public void addNewUnit(ICompilationUnit unit) { - this._env.addNewUnit(unit); - } - - public void addNewClassFile(ReferenceBinding binding) { - this._env.addNewClassFile(binding); - } - - /* (non-Javadoc) - * @see javax.annotation.processing.Filer#createClassFile(java.lang.CharSequence, javax.lang.model.element.Element[]) - */ - @Override - public JavaFileObject createClassFile(CharSequence name, - Element... originatingElements) throws IOException { - JavaFileObject jfo = this._fileManager.getJavaFileForOutput( - StandardLocation.CLASS_OUTPUT, name.toString(), JavaFileObject.Kind.CLASS, null); - URI uri = jfo.toUri(); - if (this._createdFiles.contains(uri)) { - throw new FilerException("Class file already created : " + name); //$NON-NLS-1$ - } - - this._createdFiles.add(uri); - return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this); - } - - /* (non-Javadoc) - * @see javax.annotation.processing.Filer#createResource(javax.tools.JavaFileManager.Location, java.lang.CharSequence, java.lang.CharSequence, javax.lang.model.element.Element[]) - */ - @Override - public FileObject createResource(Location location, CharSequence pkg, - CharSequence relativeName, Element... originatingElements) - throws IOException { - validateName(relativeName); - FileObject fo = this._fileManager.getFileForOutput( - location, pkg.toString(), relativeName.toString(), null); - URI uri = fo.toUri(); - if (this._createdFiles.contains(uri)) { - throw new FilerException("Resource already created : " + location + '/' + pkg + '/' + relativeName); //$NON-NLS-1$ - } - - this._createdFiles.add(uri); - return fo; - } - - private static void validateName(CharSequence relativeName) { - int length = relativeName.length(); - if (length == 0) { - throw new IllegalArgumentException("relative path cannot be empty"); //$NON-NLS-1$ - } - String path = relativeName.toString(); - if (path.indexOf('\\') != -1) { - // normalize the path with '/' - path = path.replace('\\', '/'); - } - if (path.charAt(0) == '/') { - throw new IllegalArgumentException("relative path is absolute"); //$NON-NLS-1$ - } - boolean hasDot = false; - for (int i = 0; i < length; i++) { - switch(path.charAt(i)) { - case '/' : - if (hasDot) { - throw new IllegalArgumentException("relative name " + relativeName + " is not relative"); //$NON-NLS-1$ //$NON-NLS-2$ - } - break; - case '.' : - hasDot = true; - break; - default: - hasDot = false; - } - } - if (hasDot) { - throw new IllegalArgumentException("relative name " + relativeName + " is not relative"); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - - /* (non-Javadoc) - * @see javax.annotation.processing.Filer#createSourceFile(java.lang.CharSequence, javax.lang.model.element.Element[]) - */ - @Override - public JavaFileObject createSourceFile(CharSequence name, - Element... originatingElements) throws IOException { - String moduleAndPkgString = name.toString(); - int slash = moduleAndPkgString.indexOf('/'); - String mod = null; - if (slash != -1) { - name = moduleAndPkgString.substring(slash + 1, name.length()); - mod = moduleAndPkgString.substring(0, slash); - } - TypeElement typeElement = this._env._elementUtils.getTypeElement(name); - if (typeElement != null) { - throw new FilerException("Source file already exists : " + moduleAndPkgString); //$NON-NLS-1$ - } - Location location = mod == null ? StandardLocation.SOURCE_OUTPUT : this._fileManager.getLocationForModule(StandardLocation.SOURCE_OUTPUT, mod); - JavaFileObject jfo = this._fileManager.getJavaFileForOutput(location, name.toString(), JavaFileObject.Kind.SOURCE, null); - URI uri = jfo.toUri(); - if (this._createdFiles.contains(uri)) { - throw new FilerException("Source file already created : " + name); //$NON-NLS-1$ - } - - this._createdFiles.add(uri); - // hook the file object's writers to create compilation unit and add to addedUnits() - return new HookedJavaFileObject(jfo, jfo.getName(), name.toString(), this); - } - - /* (non-Javadoc) - * @see javax.annotation.processing.Filer#getResource(javax.tools.JavaFileManager.Location, java.lang.CharSequence, java.lang.CharSequence) - */ - @Override - public FileObject getResource(Location location, CharSequence pkg, - CharSequence relativeName) throws IOException { - validateName(relativeName); - FileObject fo = this._fileManager.getFileForInput( - location, pkg.toString(), relativeName.toString()); - if (fo == null) { - throw new FileNotFoundException("Resource does not exist : " + location + '/' + pkg + '/' + relativeName); //$NON-NLS-1$ - } - URI uri = fo.toUri(); - if (this._createdFiles.contains(uri)) { - throw new FilerException("Resource already created : " + location + '/' + pkg + '/' + relativeName); //$NON-NLS-1$ - } - return fo; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java deleted file mode 100644 index 1f0e9b2..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchMessagerImpl.java +++ /dev/null @@ -1,80 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006-2009 BEA Systems, Inc. and others - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import javax.annotation.processing.Messager; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.tools.Diagnostic.Kind; - -import org.eclipse.jdt.core.compiler.CategorizedProblem; -import org.eclipse.jdt.internal.compiler.batch.Main; - -/** - * An implementation of Messager that reports messages via the Compiler - */ -public class BatchMessagerImpl extends BaseMessagerImpl implements Messager { - - private final Main _compiler; - private final BaseProcessingEnvImpl _processingEnv; - - public BatchMessagerImpl(BaseProcessingEnvImpl processingEnv, Main compiler) { - this._compiler = compiler; - this._processingEnv = processingEnv; - } - - /* (non-Javadoc) - * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence) - */ - @Override - public void printMessage(Kind kind, CharSequence msg) { - printMessage(kind, msg, null, null, null); - } - - /* (non-Javadoc) - * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, javax.lang.model.element.Element) - */ - @Override - public void printMessage(Kind kind, CharSequence msg, Element e) { - printMessage(kind, msg, e, null, null); - } - - /* (non-Javadoc) - * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror) - */ - @Override - public void printMessage(Kind kind, CharSequence msg, Element e, - AnnotationMirror a) { - printMessage(kind, msg, e, a, null); - - } - - /* (non-Javadoc) - * @see javax.annotation.processing.Messager#printMessage(javax.tools.Diagnostic.Kind, java.lang.CharSequence, javax.lang.model.element.Element, javax.lang.model.element.AnnotationMirror, javax.lang.model.element.AnnotationValue) - */ - @Override - public void printMessage(Kind kind, CharSequence msg, Element e, - AnnotationMirror a, AnnotationValue v) { - if (kind == Kind.ERROR) { - this._processingEnv.setErrorRaised(true); - } - CategorizedProblem problem = createProblem(kind, msg, e, a, v); - if (problem != null) { - this._compiler.addExtraProblems(problem); - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java deleted file mode 100644 index 0643446..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/BatchProcessingEnvImpl.java +++ /dev/null @@ -1,148 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2023 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.lang.reflect.Field; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Locale; -import java.util.Map; - -import javax.tools.JavaFileManager; - -import org.eclipse.jdt.internal.compiler.apt.util.EclipseFileManager; -import org.eclipse.jdt.internal.compiler.batch.Main; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; - -/** - * The implementation of ProcessingEnvironment that is used when compilation is - * driven by the command line or by the Tool interface. This environment uses - * the JavaFileManager provided by the compiler. - */ -public class BatchProcessingEnvImpl extends BaseProcessingEnvImpl { - - protected final BaseAnnotationProcessorManager _dispatchManager; - protected final JavaFileManager _fileManager; - protected final Main _compilerOwner; - - public BatchProcessingEnvImpl(BaseAnnotationProcessorManager dispatchManager, Main batchCompiler, - String[] commandLineArguments) - { - super(); - this._compilerOwner = batchCompiler; - this._compiler = batchCompiler.batchCompiler; - this._dispatchManager = dispatchManager; - Class c = null; - try { - c = Class.forName("org.eclipse.jdt.internal.compiler.tool.EclipseCompilerImpl"); //$NON-NLS-1$ - } catch (ClassNotFoundException e) { - // ignore - } - Field field = null; - JavaFileManager javaFileManager = null; - if (c != null) { - try { - field = c.getField("fileManager"); //$NON-NLS-1$ - } catch (SecurityException e) { - // ignore - } catch (IllegalArgumentException e) { - // ignore - } catch (NoSuchFieldException e) { - // ignore - } - } - if (field != null) { - try { - javaFileManager = (JavaFileManager) field.get(batchCompiler); - } catch (IllegalArgumentException e) { - // ignore - } catch (IllegalAccessException e) { - // ignore - } - } - if (javaFileManager != null) { - this._fileManager = javaFileManager; - } else { - String encoding = batchCompiler.options.get(CompilerOptions.OPTION_Encoding); - Charset charset = encoding != null ? Charset.forName(encoding) : null; - JavaFileManager manager = new EclipseFileManager(batchCompiler.compilerLocale, charset); - ArrayList options = new ArrayList<>(); - options.addAll(Arrays.asList(commandLineArguments)); - for (Iterator iterator = options.iterator(); iterator.hasNext(); ) { - manager.handleOption(iterator.next(), iterator); - } - this._fileManager = manager; - } - this._processorOptions = Collections.unmodifiableMap(parseProcessorOptions(commandLineArguments)); - this._filer = new BatchFilerImpl(this._dispatchManager, this); - this._messager = new BatchMessagerImpl(this, this._compilerOwner); - } - - /** - * Parse the -A command line arguments so that they can be delivered to - * processors with {@link javax.annotation.processing.ProcessingEnvironment#getOptions()}. In Sun's Java 6 - * version of javac, unlike in the Java 5 apt tool, only the -A options are - * passed to processors, not the other command line options; that behavior - * is repeated here. - * @param args the equivalent of the args array from the main() method. - * @return a map of key to value, or key to null if there is no value for - * a particular key. The "-A" is stripped from the key, so a command-line - * argument like "-Afoo=bar" will result in an entry with key "foo" and - * value "bar". - */ - private Map parseProcessorOptions(String[] args) { - Map options = new LinkedHashMap<>(); - for (String arg : args) { - if (!arg.startsWith("-A")) { //$NON-NLS-1$ - continue; - } - int equals = arg.indexOf('='); - if (equals == 2) { - // option begins "-A=" - not valid - Exception e = new IllegalArgumentException("-A option must have a key before the equals sign"); //$NON-NLS-1$ - throw new AbortCompilation(null, e); - } - if (equals == arg.length() - 1) { - // option ends with "=" - not valid - options.put(arg.substring(2, equals), null); - } else if (equals == -1) { - // no value - options.put(arg.substring(2), null); - } else { - // value and key - options.put(arg.substring(2, equals), arg.substring(equals + 1)); - } - } - return options; - } - @Override - public JavaFileManager getFileManager() { - return this._fileManager; - } - - @Override - public Locale getLocale() { - return this._compilerOwner.compilerLocale; - } - - public boolean shouldIgnoreOptionalProblems(char[] fileName) { - return Main.shouldIgnoreOptionalProblems(this._compilerOwner.ignoreOptionalProblemsFromFolders, fileName); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java deleted file mode 100644 index 7776c12..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/HookedJavaFileObject.java +++ /dev/null @@ -1,268 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2023 BEA Systems, Inc. and others - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; - -import javax.tools.ForwardingJavaFileObject; -import javax.tools.JavaFileObject; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.batch.CompilationUnit; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; - -/** - * A delegating JavaFileObject that hooks the close() methods of the Writer - * or OutputStream objects that it produces, and notifies the annotation - * dispatch manager when a new compilation unit is produced. - */ -public class HookedJavaFileObject extends - ForwardingJavaFileObject -{ - // A delegating Writer that passes all commands to its contained Writer, - // but hooks close() to notify the annotation dispatch manager of the new unit. - private class ForwardingWriter extends Writer { - private final Writer _w; - ForwardingWriter(Writer w) { - this._w = w; - } - @Override - public Writer append(char c) throws IOException { - return this._w.append(c); - } - @Override - public Writer append(CharSequence csq, int start, int end) - throws IOException { - return this._w.append(csq, start, end); - } - @Override - public Writer append(CharSequence csq) throws IOException { - return this._w.append(csq); - } - // This is the only interesting method - it has to notify the - // dispatch manager of the new file. - @Override - public void close() throws IOException { - this._w.close(); - closed(); - } - @Override - public void flush() throws IOException { - this._w.flush(); - } - @Override - public void write(char[] cbuf) throws IOException { - this._w.write(cbuf); - } - @Override - public void write(int c) throws IOException { - this._w.write(c); - } - @Override - public void write(String str, int off, int len) - throws IOException { - this._w.write(str, off, len); - } - @Override - public void write(String str) throws IOException { - this._w.write(str); - } - @Override - public void write(char[] cbuf, int off, int len) - throws IOException { - this._w.write(cbuf, off, len); - } - @Override - protected Object clone() throws CloneNotSupportedException { - return new ForwardingWriter(this._w); - } - @Override - public int hashCode() { - return this._w.hashCode(); - } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final ForwardingWriter other = (ForwardingWriter) obj; - if (this._w == null) { - if (other._w != null) - return false; - } else if (!this._w.equals(other._w)) - return false; - return true; - } - @Override - public String toString() { - return "ForwardingWriter wrapping " + this._w.toString(); //$NON-NLS-1$ - } - } - - // A delegating Writer that passes all commands to its contained Writer, - // but hooks close() to notify the annotation dispatch manager of the new unit. - private class ForwardingOutputStream extends OutputStream { - private final OutputStream _os; - - ForwardingOutputStream(OutputStream os) { - this._os = os; - } - - @Override - public void close() throws IOException { - this._os.close(); - closed(); - } - @Override - public void flush() throws IOException { - this._os.flush(); - } - @Override - public void write(byte[] b, int off, int len) throws IOException { - this._os.write(b, off, len); - } - @Override - public void write(byte[] b) throws IOException { - this._os.write(b); - } - @Override - public void write(int b) throws IOException { - this._os.write(b); - } - @Override - protected Object clone() throws CloneNotSupportedException { - return new ForwardingOutputStream(this._os); - } - @Override - public int hashCode() { - return this._os.hashCode(); - } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final ForwardingOutputStream other = (ForwardingOutputStream) obj; - if (this._os == null) { - if (other._os != null) - return false; - } else if (!this._os.equals(other._os)) - return false; - return true; - } - @Override - public String toString() { - return "ForwardingOutputStream wrapping " + this._os.toString(); //$NON-NLS-1$ - } - } - - /** - * The Filer implementation that we need to notify when a new file is created. - */ - protected final BatchFilerImpl _filer; - - /** - * The name of the file that is created; this is passed to the CompilationUnit constructor, - * and ultimately to the java.io.File constructor, so it is a normal pathname, just like - * what would be on the compiler command line. - */ - protected final String _fileName; - - - - /** - * A compilation unit is created when the writer or stream is closed. Only do this once. - */ - private boolean _closed = false; - - private final String _typeName; - - public HookedJavaFileObject(JavaFileObject fileObject, String fileName, String typeName, BatchFilerImpl filer) { - super(fileObject); - this._filer = filer; - this._fileName = fileName; - this._typeName = typeName; - } - - @SuppressWarnings("resource") // ForwardingOutputStream forwards close() too - @Override - public OutputStream openOutputStream() throws IOException { - return new ForwardingOutputStream(super.openOutputStream()); - } - - @SuppressWarnings("resource") // ForwardingWriter forwards close() too - @Override - public Writer openWriter() throws IOException { - return new ForwardingWriter(super.openWriter()); - } - - protected void closed() { - if (!this._closed) { - this._closed = true; - //TODO: support encoding - switch(this.getKind()) { - case SOURCE : - CompilationUnit unit = new CompilationUnit(null, this._fileName, null /* encoding */, null, this._filer._env.shouldIgnoreOptionalProblems(this._fileName.toCharArray()), null); - this._filer.addNewUnit(unit); - break; - case CLASS : - IBinaryType binaryType = null; - try { - binaryType = ClassFileReader.read(this._fileName); - } catch (ClassFormatException e) { - /* When the annotation processor produces garbage, javac seems to show some resilience, by hooking the source type, - which since is resolved can answer annotations during discovery - Not sure if this sanctioned by the spec, to be taken - up with Oracle. Here we mimic the bug, see that addNewClassFile is simply collecting ReferenceBinding's, so adding - a SourceTypeBinding works just fine. - */ - ReferenceBinding type = this._filer._env._compiler.lookupEnvironment.getType(CharOperation.splitOn('.', this._typeName.toCharArray())); - if (type != null) - this._filer.addNewClassFile(type); - } catch (IOException e) { - // ignore - } - if (binaryType != null) { - char[] name = binaryType.getName(); - ReferenceBinding type = this._filer._env._compiler.lookupEnvironment.getType(CharOperation.splitOn('/', name)); - if (type != null && type.isValidBinding()) { - if (type.isBinaryBinding()) { - this._filer.addNewClassFile(type); - } else { - BinaryTypeBinding binaryBinding = new BinaryTypeBinding(type.getPackage(), binaryType, this._filer._env._compiler.lookupEnvironment, true); - this._filer.addNewClassFile(binaryBinding); - } - } - } - break; - case HTML: - case OTHER: - break; - } - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java deleted file mode 100644 index ae4e7dc..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/IProcessorProvider.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2007 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.util.List; - -import javax.annotation.processing.Processor; - -/** - * Implementors know how to discover annotation processors, and maintain a list of processors that - * have been discovered and initialized so far. - */ -public interface IProcessorProvider { - - /** - * Return the next processor that can be discovered, according to the order and discovery rules - * of the provider (see, for instance, {@link Processor}. - * @return a ProcessorInfo wrapping an initialized Processor, or null if there are - * no more processors to be discovered. - */ - ProcessorInfo discoverNextProcessor(); - - /** - * @return the list of all processors that have been discovered so far. This list will grow when - * {@link #discoverNextProcessor()} is called. - */ - List getDiscoveredProcessors(); - - /** - * Called when a processor throws an exception. This may abort compilation, throw an - * unchecked exception, etc; the caller should not assume that this method will return. - * - * @param p the processor, if known, or null if not. - */ - void reportProcessorException(Processor p, Exception e); -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java deleted file mode 100644 index 9248929..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/ProcessorInfo.java +++ /dev/null @@ -1,177 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2011 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.util.Iterator; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.annotation.processing.Processor; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.TypeElement; - -/** - * Cached information associated with a {@link Processor} in the context - * of annotation processor dispatch. - *

- * This class supports inclusion in a collection by implementing - * equals() and hashCode(). Its concept of identity is based on - * the class object of the Processor that it wraps; so, for instance, - * it is not possible to have a Set that contains more than one - * instance of a particular Processor class. In fact, it is possible - * to have more than one instance of a Processor if there are multiple - * build threads, but within the context of a particular dispatch - * manager, there will only be one of any given Processor class. - */ -public class ProcessorInfo { - final Processor _processor; - final Set _supportedOptions; - final SourceVersion _supportedSourceVersion; - - private final Pattern _supportedAnnotationTypesPattern; - private final boolean _supportsStar; - private boolean _hasBeenCalled; - - /** - * Create a ProcessorInfo wrapping a particular Processor. The Processor must already have been - * initialized (that is, - * {@link Processor#init(javax.annotation.processing.ProcessingEnvironment)} must already have - * been called). Its getSupportedXXX() methods will be called and the results will be cached. - */ - public ProcessorInfo(Processor p) - { - this._processor = p; - this._hasBeenCalled = false; - this._supportedSourceVersion = p.getSupportedSourceVersion(); - this._supportedOptions = p.getSupportedOptions(); - Set supportedAnnotationTypes = p.getSupportedAnnotationTypes(); - - boolean supportsStar = false; - if (null != supportedAnnotationTypes && !supportedAnnotationTypes.isEmpty()) { - StringBuilder regex = new StringBuilder(); - Iterator iName = supportedAnnotationTypes.iterator(); - while (true) { - String name = iName.next(); - supportsStar |= "*".equals(name); //$NON-NLS-1$ - String escapedName1 = name.replace(".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$ - String escapedName2 = escapedName1.replace("*", ".*"); //$NON-NLS-1$ //$NON-NLS-2$ - regex.append(escapedName2); - if (!iName.hasNext()) { - break; - } - regex.append('|'); - } - this._supportedAnnotationTypesPattern = Pattern.compile(regex.toString()); - } - else { - this._supportedAnnotationTypesPattern = null; - } - this._supportsStar = supportsStar; - } - - /** - * Compute the subset of annotations that are described by annotationTypes, - * and determine whether the processor should be called. A processor will be called if it has - * any annotations to process, or if it supports "*", or if it was called in a previous round. - * If the return value of this method is true once for a given processor, then it will always be true on - * subsequent calls. - * - * @param annotations a set of annotation types - * @param result an empty modifiable set, which upon return will contain a subset of annotations, which may be empty but will not be null. - * @return true if the processor should be called on this round. - */ - public boolean computeSupportedAnnotations(Set annotations, Set result) - { - if (null != annotations && !annotations.isEmpty() && null != this._supportedAnnotationTypesPattern) { - for (TypeElement annotation : annotations) { - Matcher matcher = this._supportedAnnotationTypesPattern.matcher(annotation.getQualifiedName().toString()); - if (matcher.matches()) { - result.add(annotation); - } - } - } - boolean call = this._hasBeenCalled || this._supportsStar || !result.isEmpty(); - this._hasBeenCalled |= call; - return call; - } - - /** - * @return true if the processor included "*" among its list of supported annotations. - */ - public boolean supportsStar() - { - return this._supportsStar; - } - - /** - * Must be called at the beginning of a build to ensure that no information is - * carried over from the previous build. In particular, processors are - * required to be called on every round after the round in which they are - * first called; this method resets the "has been called" flag. - */ - public void reset() - { - this._hasBeenCalled = false; - } - - @Override - public int hashCode() { - return this._processor.getClass().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final ProcessorInfo other = (ProcessorInfo) obj; - if (!this._processor.getClass().equals(other._processor.getClass())) - return false; - return true; - } - - @Override - public String toString() - { - return this._processor.getClass().getName(); - } - - /** - * @return a string representing the set of supported annotation types, in a format - * suitable for debugging. The format is unspecified and subject to change. - */ - public String getSupportedAnnotationTypesAsString() - { - StringBuilder sb = new StringBuilder(); - sb.append('['); - Iterator iAnnots = this._processor.getSupportedAnnotationTypes().iterator(); - boolean hasNext = iAnnots.hasNext(); - while (hasNext) { - sb.append(iAnnots.next()); - hasNext = iAnnots.hasNext(); - if (hasNext) { - sb.append(','); - } - } - sb.append(']'); - return sb.toString(); - } -} - diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java deleted file mode 100644 index 15131a4..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundDispatcher.java +++ /dev/null @@ -1,175 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2015 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.io.PrintWriter; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; - -/** - * Manages context during a single round of annotation processing. - */ -public class RoundDispatcher { - - private final Set _unclaimedAnnotations; - private final RoundEnvironment _roundEnv; - private final IProcessorProvider _provider; - private boolean _searchForStar = false; - private final PrintWriter _traceProcessorInfo; - private final PrintWriter _traceRounds; - - /** - * Processors discovered so far. This list may grow during the - * course of a round, as additional processors are discovered. - */ - private final List _processors; - - /** - * @param rootAnnotations a possibly empty but non-null set of annotations on the - * root compilation units of this round. A local copy of the set will be made, to - * avoid modifying the set passed in. - * @param traceProcessorInfo a PrintWriter that processor trace output will be sent - * to, or null if tracing is not desired. - */ - public RoundDispatcher( - IProcessorProvider provider, - RoundEnvironment env, - Set rootAnnotations, - PrintWriter traceProcessorInfo, - PrintWriter traceRounds) - { - this._provider = provider; - this._processors = provider.getDiscoveredProcessors(); - this._roundEnv = env; - this._unclaimedAnnotations = new HashSet<>(rootAnnotations); - this._traceProcessorInfo = traceProcessorInfo; - this._traceRounds = traceRounds; - } - - /** - * Handle a complete round, dispatching to all appropriate processors. - */ - public void round() - { - if (null != this._traceRounds) { - StringBuilder sbElements = new StringBuilder(); - sbElements.append("\tinput files: {"); //$NON-NLS-1$ - Iterator iElements = this._roundEnv.getRootElements().iterator(); - boolean hasNext = iElements.hasNext(); - while (hasNext) { - sbElements.append(iElements.next()); - hasNext = iElements.hasNext(); - if (hasNext) { - sbElements.append(','); - } - } - sbElements.append('}'); - this._traceRounds.println(sbElements.toString()); - - StringBuilder sbAnnots = new StringBuilder(); - sbAnnots.append("\tannotations: ["); //$NON-NLS-1$ - Iterator iAnnots = this._unclaimedAnnotations.iterator(); - hasNext = iAnnots.hasNext(); - while (hasNext) { - sbAnnots.append(iAnnots.next()); - hasNext = iAnnots.hasNext(); - if (hasNext) { - sbAnnots.append(','); - } - } - sbAnnots.append(']'); - this._traceRounds.println(sbAnnots.toString()); - - this._traceRounds.println("\tlast round: " + this._roundEnv.processingOver()); //$NON-NLS-1$ - } - - // If there are no root annotations, try to find a processor that claims "*" - this._searchForStar = this._unclaimedAnnotations.isEmpty(); - - // Iterate over all the already-found processors, giving each one a chance at the unclaimed - // annotations. If a processor is called at all, it is called on every subsequent round - // including the final round, but it may be called with an empty set of annotations. - for (ProcessorInfo pi : this._processors) { - handleProcessor(pi); - } - - // If there are any unclaimed annotations, or if there were no root annotations and - // we have not yet run into a processor that claimed "*", continue discovery. - while (this._searchForStar || !this._unclaimedAnnotations.isEmpty()) { - ProcessorInfo pi = this._provider.discoverNextProcessor(); - if (null == pi) { - // There are no more processors to be discovered. - break; - } - handleProcessor(pi); - } - - // TODO: If !unclaimedAnnos.isEmpty(), issue a warning. - } - - /** - * Evaluate a single processor. Depending on the unclaimed annotations, - * the annotations this processor supports, and whether it has already been - * called in a previous round, possibly call its process() method. - */ - private void handleProcessor(ProcessorInfo pi) - { - try { - Set annotationsToProcess = new HashSet<>(); - boolean shouldCall = pi.computeSupportedAnnotations( - this._unclaimedAnnotations, annotationsToProcess); - if (shouldCall) { - boolean claimed = pi._processor.process(annotationsToProcess, this._roundEnv); - if (null != this._traceProcessorInfo && !this._roundEnv.processingOver()) { - StringBuilder sb = new StringBuilder(); - sb.append("Processor "); //$NON-NLS-1$ - sb.append(pi._processor.getClass().getName()); - sb.append(" matches ["); //$NON-NLS-1$ - Iterator i = annotationsToProcess.iterator(); - boolean hasNext = i.hasNext(); - while (hasNext) { - sb.append(i.next()); - hasNext = i.hasNext(); - if (hasNext) { - sb.append(' '); - } - } - sb.append("] and returns "); //$NON-NLS-1$ - sb.append(claimed); - this._traceProcessorInfo.println(sb.toString()); - } - if (claimed) { - // The processor claimed its annotations. - this._unclaimedAnnotations.removeAll(annotationsToProcess); - if (pi.supportsStar()) { - this._searchForStar = false; - } - } - } - } catch (Throwable e) { - // If a processor throws an exception (as opposed to reporting an error), - // report it and abort compilation by throwing AbortCompilation. - this._provider.reportProcessorException(pi._processor, new Exception(e)); - } - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java deleted file mode 100644 index 7117c2c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/dispatch/RoundEnvImpl.java +++ /dev/null @@ -1,257 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * IBM Corporation - Fix for bug 328575 - * het@google.com - Bug 415274 - Annotation processing throws a NPE in getElementsAnnotatedWith() - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.dispatch; - -import java.lang.annotation.Annotation; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.ElementFilter; - -import org.eclipse.jdt.internal.compiler.apt.model.Factory; -import org.eclipse.jdt.internal.compiler.apt.model.TypeElementImpl; -import org.eclipse.jdt.internal.compiler.apt.util.ManyToMany; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; - -public class RoundEnvImpl implements RoundEnvironment -{ - private final BaseProcessingEnvImpl _processingEnv; - private final boolean _isLastRound; - private final CompilationUnitDeclaration[] _units; - private final ManyToMany _annoToUnit; - private final ReferenceBinding[] _binaryTypes; - private final Factory _factory; - private Set _rootElements = null; - - public RoundEnvImpl(CompilationUnitDeclaration[] units, ReferenceBinding[] binaryTypeBindings, boolean isLastRound, BaseProcessingEnvImpl env) { - this._processingEnv = env; - this._isLastRound = isLastRound; - this._units = units; - this._factory = this._processingEnv.getFactory(); - - // Discover the annotations that will be passed to Processor.process() - AnnotationDiscoveryVisitor visitor = new AnnotationDiscoveryVisitor(this._processingEnv); - if (this._units != null) { - for (CompilationUnitDeclaration unit : this._units) { - unit.scope.environment.suppressImportErrors = true; - unit.traverse(visitor, unit.scope); - unit.scope.environment.suppressImportErrors = false; - } - } - this._annoToUnit = visitor._annoToElement; - if (binaryTypeBindings != null) collectAnnotations(binaryTypeBindings); - this._binaryTypes = binaryTypeBindings; - } - - private void collectAnnotations(ReferenceBinding[] referenceBindings) { - for (ReferenceBinding referenceBinding : referenceBindings) { - // collect all annotations from the binary types - if (referenceBinding instanceof ParameterizedTypeBinding) { - referenceBinding = ((ParameterizedTypeBinding) referenceBinding).genericType(); - } - AnnotationBinding[] annotationBindings = Factory.getPackedAnnotationBindings(referenceBinding.getAnnotations()); - for (AnnotationBinding annotationBinding : annotationBindings) { - TypeElement anno = (TypeElement)this._factory.newElement(annotationBinding.getAnnotationType()); - Element element = this._factory.newElement(referenceBinding); - this._annoToUnit.put(anno, element); - } - FieldBinding[] fieldBindings = referenceBinding.fields(); - for (FieldBinding fieldBinding : fieldBindings) { - annotationBindings = Factory.getPackedAnnotationBindings(fieldBinding.getAnnotations()); - for (AnnotationBinding annotationBinding : annotationBindings) { - TypeElement anno = (TypeElement)this._factory.newElement(annotationBinding.getAnnotationType()); - Element element = this._factory.newElement(fieldBinding); - this._annoToUnit.put(anno, element); - } - } - MethodBinding[] methodBindings = referenceBinding.methods(); - for (MethodBinding methodBinding : methodBindings) { - annotationBindings = Factory.getPackedAnnotationBindings(methodBinding.getAnnotations()); - for (AnnotationBinding annotationBinding : annotationBindings) { - TypeElement anno = (TypeElement)this._factory.newElement(annotationBinding.getAnnotationType()); - Element element = this._factory.newElement(methodBinding); - this._annoToUnit.put(anno, element); - } - } - ReferenceBinding[] memberTypes = referenceBinding.memberTypes(); - collectAnnotations(memberTypes); - } - } - - /** - * Return the set of annotation types that were discovered on the root elements. - * This does not include inherited annotations, only those directly on the root - * elements. - * @return a set of annotation types, possibly empty. - */ - public Set getRootAnnotations() - { - return Collections.unmodifiableSet(this._annoToUnit.getKeySet()); - } - - @Override - public boolean errorRaised() - { - return this._processingEnv.errorRaised(); - } - - /** - * From the set of root elements and their enclosed elements, return the subset that are annotated - * with {@code a}. If {@code a} is annotated with the {@link java.lang.annotation.Inherited} - * annotation, include those elements that inherit the annotation from their superclasses. - * Note that {@link java.lang.annotation.Inherited} only applies to classes (i.e. TypeElements). - */ - @Override - public Set getElementsAnnotatedWith(TypeElement a) - { - if (a.getKind() != ElementKind.ANNOTATION_TYPE) { - throw new IllegalArgumentException("Argument must represent an annotation type"); //$NON-NLS-1$ - } - Binding annoBinding = ((TypeElementImpl)a)._binding; - if (0 != (annoBinding.getAnnotationTagBits() & TagBits.AnnotationInherited)) { - Set annotatedElements = new HashSet<>(this._annoToUnit.getValues(a)); - // For all other root elements that are TypeElements, and for their recursively enclosed - // types, add each element if it has a superclass are annotated with 'a' - ReferenceBinding annoTypeBinding = (ReferenceBinding) annoBinding; - for (TypeElement element : ElementFilter.typesIn(getRootElements())) { - ReferenceBinding typeBinding = (ReferenceBinding)((TypeElementImpl)element)._binding; - addAnnotatedElements(annoTypeBinding, typeBinding, annotatedElements); - } - return Collections.unmodifiableSet(annotatedElements); - } - return Collections.unmodifiableSet(this._annoToUnit.getValues(a)); - } - - /** - * For every type in types that is a class and that is annotated with anno, either directly or by inheritance, - * add that type to result. Recursively descend on each types's child classes as well. - * @param anno the compiler binding for an annotation type - * @param type a type, not necessarily a class - * @param result must be a modifiable Set; will accumulate annotated classes - */ - private void addAnnotatedElements(ReferenceBinding anno, ReferenceBinding type, Set result) { - if (type.isClass()) { - if (inheritsAnno(type, anno)) { - result.add(this._factory.newElement(type)); - } - } - for (ReferenceBinding element : type.memberTypes()) { - addAnnotatedElements(anno, element, result); - } - } - - /** - * Check whether an element has a superclass that is annotated with an @Inherited annotation. - * @param element must be a class (not an interface, enum, etc.). - * @param anno must be an annotation type, and must be @Inherited - * @return true if element has a superclass that is annotated with anno - */ - private boolean inheritsAnno(ReferenceBinding element, ReferenceBinding anno) { - ReferenceBinding searchedElement = element; - do { - if (searchedElement instanceof ParameterizedTypeBinding) { - searchedElement = ((ParameterizedTypeBinding) searchedElement).genericType(); - } - AnnotationBinding[] annos = Factory.getPackedAnnotationBindings(searchedElement.getAnnotations()); - for (AnnotationBinding annoBinding : annos) { - if (annoBinding.getAnnotationType() == anno) { //$IDENTITY-COMPARISON$ - // element is annotated with anno - return true; - } - } - } while (null != (searchedElement = searchedElement.superclass())); - return false; - } - - @Override - public Set getElementsAnnotatedWith(Class a) - { - String canonicalName = a.getCanonicalName(); - if (canonicalName == null) { - // null for anonymous and local classes or an array of those - throw new IllegalArgumentException("Argument must represent an annotation type"); //$NON-NLS-1$ - } - TypeElement annoType = this._processingEnv.getElementUtils().getTypeElement(canonicalName); - if (annoType == null) { - return Collections.emptySet(); - } - return getElementsAnnotatedWith(annoType); - } - - @Override - public Set getRootElements() - { - if (this._units == null) { - return Collections.emptySet(); - } - if (this._rootElements == null) { - Set elements = new HashSet<>(this._units.length); - for (CompilationUnitDeclaration unit : this._units) { - if (unit.moduleDeclaration != null && unit.moduleDeclaration.binding != null) { - Element m = this._factory.newElement(unit.moduleDeclaration.binding); - elements.add(m); - continue; - } - if (null == unit.scope || null == unit.scope.topLevelTypes) - continue; - for (SourceTypeBinding binding : unit.scope.topLevelTypes) { - Element element = this._factory.newElement(binding); - if (null == element) { - throw new IllegalArgumentException("Top-level type binding could not be converted to element: " + binding); //$NON-NLS-1$ - } - elements.add(element); - } - } - if (this._binaryTypes != null) { - for (ReferenceBinding typeBinding : this._binaryTypes) { - Element element = this._factory.newElement(typeBinding); - if (null == element) { - throw new IllegalArgumentException("Top-level type binding could not be converted to element: " + typeBinding); //$NON-NLS-1$ - } - elements.add(element); - ModuleBinding binding = typeBinding.module(); - if (binding != null) { - Element m = this._factory.newElement(binding); - elements.add(m); - } - } - } - this._rootElements = elements; - } - return this._rootElements; - } - - @Override - public boolean processingOver() - { - return this._isLastRound; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java deleted file mode 100644 index fae18b9..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMemberValue.java +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2017 Vladimir Piskarev and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Vladimir Piskarev - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.model; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; - -public class AnnotationMemberValue extends AnnotationValueImpl { - - private final MethodBinding _methodBinding; - - /** - * @param value - * The JDT representation of a compile-time constant. See - * {@link org.eclipse.jdt.internal.compiler.lookup.ElementValuePair#getValue()} for possible object types: - *

    - *
  • {@link org.eclipse.jdt.internal.compiler.impl.Constant} for member - * of primitive type or String
  • - *
  • {@link org.eclipse.jdt.internal.compiler.lookup.TypeBinding} for a member value of type - * {@link java.lang.Class}
  • - *
  • {@link org.eclipse.jdt.internal.compiler.lookup.FieldBinding} for an enum constant
  • - *
  • {@link org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding} for an annotation instance
  • - *
  • Object[] for a member value of array type, where the - * array entries are one of the above
  • - *
- * @param methodBinding the method binding that defined this member value pair - */ - public AnnotationMemberValue(BaseProcessingEnvImpl env, Object value, MethodBinding methodBinding) { - super(env, value, methodBinding.returnType); - this._methodBinding = methodBinding; - } - - /** - * @return the method binding that defined this member value pair. - */ - public MethodBinding getMethodBinding() { - return this._methodBinding; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java deleted file mode 100644 index 78d075b..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/AnnotationMirrorImpl.java +++ /dev/null @@ -1,561 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * het@google.com - Bug 441790 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.MirroredTypeException; -import javax.lang.model.type.MirroredTypesException; -import javax.lang.model.type.TypeMirror; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -public class AnnotationMirrorImpl implements AnnotationMirror, InvocationHandler { - - public final BaseProcessingEnvImpl _env; - public final AnnotationBinding _binding; - - /* package */ AnnotationMirrorImpl(BaseProcessingEnvImpl env, AnnotationBinding binding) { - this._env = env; - this._binding = binding; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof AnnotationMirrorImpl) { - if (this._binding == null) { - return ((AnnotationMirrorImpl) obj)._binding == null; - } - return equals(this._binding, ((AnnotationMirrorImpl) obj)._binding); - } - return obj == null ? false : obj.equals(this); // obj could be wrapped by a proxy. - } - - private static boolean equals(AnnotationBinding annotationBinding, AnnotationBinding annotationBinding2) { - if (annotationBinding.getAnnotationType() != annotationBinding2.getAnnotationType()) return false; //$IDENTITY-COMPARISON$ - final ElementValuePair[] elementValuePairs = annotationBinding.getElementValuePairs(); - final ElementValuePair[] elementValuePairs2 = annotationBinding2.getElementValuePairs(); - final int length = elementValuePairs.length; - if (length != elementValuePairs2.length) return false; - loop: for (int i = 0; i < length; i++) { - ElementValuePair pair = elementValuePairs[i]; - // loop on the given pair to make sure one will match - for (int j = 0; j < length; j++) { - ElementValuePair pair2 = elementValuePairs2[j]; - if (pair.binding == pair2.binding) { - if (pair.value == null) { - if (pair2.value == null) { - continue loop; - } - return false; - } else { - if (pair2.value == null) return false; - if (pair2.value instanceof Object[] && pair.value instanceof Object[]) { - if (!Arrays.equals((Object[]) pair.value, (Object[]) pair2.value)) { - return false; - } - } else if (!pair2.value.equals(pair.value)){ - return false; - } - } - continue loop; - } - } - return false; - } - return true; - } - - @Override - public DeclaredType getAnnotationType() { - return (DeclaredType) this._env.getFactory().newTypeMirror(this._binding.getAnnotationType()); - } - - /** - * @return all the members of this annotation mirror that have explicit values. - * Default values are not included. - */ - @Override - public Map getElementValues() { - if (this._binding == null) { - return Collections.emptyMap(); - } - ElementValuePair[] pairs = this._binding.getElementValuePairs(); - Map valueMap = - new LinkedHashMap<>(pairs.length); - for (ElementValuePair pair : pairs) { - MethodBinding method = pair.getMethodBinding(); - if (method == null) { - // ideally we should be able to create a fake ExecutableElementImpl - continue; - } - ExecutableElement e = new ExecutableElementImpl(this._env, method); - AnnotationValue v = new AnnotationMemberValue(this._env, pair.getValue(), method); - valueMap.put(e, v); - } - return Collections.unmodifiableMap(valueMap); - } - - /** - * @see javax.lang.model.util.Elements#getElementValuesWithDefaults(AnnotationMirror) - * @return all the members of this annotation mirror that have explicit or default - * values. - */ - public Map getElementValuesWithDefaults() { - if (this._binding == null) { - return Collections.emptyMap(); - } - ElementValuePair[] pairs = this._binding.getElementValuePairs(); - ReferenceBinding annoType = this._binding.getAnnotationType(); - Map valueMap = - new LinkedHashMap<>(); - for (MethodBinding method : annoType.methods()) { - // if binding is in ElementValuePair list, then get value from there - boolean foundExplicitValue = false; - for (int i = 0; i < pairs.length; ++i) { - MethodBinding explicitBinding = pairs[i].getMethodBinding(); - if (method == explicitBinding) { - ExecutableElement e = new ExecutableElementImpl(this._env, explicitBinding); - AnnotationValue v = new AnnotationMemberValue(this._env, pairs[i].getValue(), explicitBinding); - valueMap.put(e, v); - foundExplicitValue = true; - break; - } - } - // else get default value if one exists - if (!foundExplicitValue) { - Object defaultVal = method.getDefaultValue(); - if (null != defaultVal) { - ExecutableElement e = new ExecutableElementImpl(this._env, method); - AnnotationValue v = new AnnotationMemberValue(this._env, defaultVal, method); - valueMap.put(e, v); - } - } - } - return Collections.unmodifiableMap(valueMap); - } - - @Override - public int hashCode() { - if (this._binding == null) return this._env.hashCode(); - return this._binding.hashCode(); - } - - /* - * Used by getAnnotation(), which returns a reflective proxy of the annotation class. When processors then - * invoke methods such as value() on the annotation proxy, this method is called. - *

- * A challenge here is that the processor was not necessarily compiled against the same annotation - * definition that the compiler is looking at right now, not to mention that the annotation itself - * may be defective in source. So the actual type of the value may be quite different than the - * type expected by the caller, which will result in a ClassCastException, which is ugly for the - * processor to try to catch. So we try to catch and correct this type mismatch where possible. - *

- * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) - */ - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable - { - if (this._binding == null) return null; - final String methodName = method.getName(); - if ( args == null || args.length == 0 ) { - if( methodName.equals("hashCode") ) { //$NON-NLS-1$ - return Integer.valueOf(hashCode()); - } - else if( methodName.equals("toString") ) { //$NON-NLS-1$ - return toString(); - } - else if( methodName.equals("annotationType")) { //$NON-NLS-1$ - return proxy.getClass().getInterfaces()[0]; - } - } - else if ( args.length == 1 && methodName.equals("equals") ) { //$NON-NLS-1$ - return Boolean.valueOf(equals(args[0])); - } - - // If it's not one of the above methods, it must be an annotation member, so it cannot take any arguments - if ( args != null && args.length != 0 ) { - throw new NoSuchMethodException("method " + method.getName() + formatArgs(args) + " does not exist on annotation " + toString()); //$NON-NLS-1$ //$NON-NLS-2$ - } - final MethodBinding methodBinding = getMethodBinding(methodName); - if ( methodBinding == null ) { - throw new NoSuchMethodException("method " + method.getName() + "() does not exist on annotation" + toString()); //$NON-NLS-1$ //$NON-NLS-2$ - } - - Object actualValue = null; - boolean foundMethod = false; - ElementValuePair[] pairs = this._binding.getElementValuePairs(); - for (ElementValuePair pair : pairs) { - if (methodName.equals(new String(pair.getName()))) { - actualValue = pair.getValue(); - foundMethod = true; - break; - } - } - if (!foundMethod) { - // couldn't find explicit value; see if there's a default - actualValue = methodBinding.getDefaultValue(); - } - Class expectedType = method.getReturnType(); - TypeBinding actualType = methodBinding.returnType; - return getReflectionValue(actualValue, actualType, expectedType); - } - - @Override - public String toString() { - TypeMirror decl = getAnnotationType(); - StringBuilder sb = new StringBuilder(); - sb.append('@'); - sb.append(decl.toString()); - Map values = getElementValues(); - if (!values.isEmpty()) { - sb.append('('); - boolean first = true; - for (Entry e : values.entrySet()) { - if (!first) { - sb.append(", "); //$NON-NLS-1$ - } - first = false; - sb.append(e.getKey().getSimpleName()); - sb.append(" = "); //$NON-NLS-1$ - sb.append(e.getValue().toString()); - } - sb.append(')'); - } - return sb.toString(); - } - - /** - * Used for constructing exception message text. - * @return a string like "(a, b, c)". - */ - private String formatArgs(final Object[] args) - { - // estimate that each class name (plus the separators) is 10 characters long plus 2 for "()". - final StringBuilder builder = new StringBuilder(args.length * 8 + 2 ); - builder.append('('); - for( int i=0; i 0 ) - builder.append(", "); //$NON-NLS-1$ - builder.append(args[i].getClass().getName()); - } - builder.append(')'); - return builder.toString(); - } - - /** - * Find a particular annotation member by name. - * @return a compiler method binding, or null if no member was found. - */ - private MethodBinding getMethodBinding(String name) { - ReferenceBinding annoType = this._binding.getAnnotationType(); - MethodBinding[] methods = annoType.getMethods(name.toCharArray()); - for (MethodBinding method : methods) { - // annotation members have no parameters - if (method.parameters.length == 0) { - return method; - } - } - return null; - } - - /** - * Convert an annotation member value from JDT into Reflection, and from whatever its actual type - * is into whatever type the reflective invoker of a method is expecting. - *

- * Only certain types are permitted as member values. Specifically, a member must be a constant, - * and must be either a primitive type, String, Class, an enum constant, an annotation, or an - * array of any of those. Multidimensional arrays are not permitted. - * - * @param actualValue the value as represented by {@link ElementValuePair#getValue()} - * @param actualType the return type of the corresponding {@link MethodBinding} - * @param expectedType the type that the reflective method invoker is expecting - * @return an object of the expected type representing the annotation member value, - * or an appropriate dummy value (such as null) if no value is available - */ - private Object getReflectionValue(Object actualValue, TypeBinding actualType, Class expectedType) - { - if (null == expectedType) { - // With no expected type, we can't even guess at a conversion - return null; - } - if (null == actualValue) { - // Return a type-appropriate equivalent of null - return Factory.getMatchingDummyValue(expectedType); - } - if (expectedType.isArray()) { - if (Class.class.equals(expectedType.getComponentType())) { - // package Class[]-valued return as a MirroredTypesException - if (actualType.isArrayType() && ((ArrayBinding)actualType).leafComponentType.erasure().id == TypeIds.T_JavaLangClass) { - - Object[] bindings; - if(actualValue instanceof Object[]) { - bindings = (Object[]) actualValue; - } else if(actualValue instanceof TypeBinding) { - // when a single class element is passed to array: @AnnotationType(Something.class) - bindings = new Object[] {actualValue}; - } else { - bindings = null; - } - - if(bindings != null) { - List mirrors = new ArrayList<>(bindings.length); - for (int i = 0; i < bindings.length; ++i) { - if (bindings[i] instanceof TypeBinding) { - mirrors.add(this._env.getFactory().newTypeMirror((TypeBinding)bindings[i])); - } - } - throw new MirroredTypesException(mirrors); - } - } - // TODO: actual value is not a TypeBinding[]. Should we return a TypeMirror[] around an ErrorType? - return null; - } - // Handle arrays of types other than Class, e.g., int[], MyEnum[], ... - return convertJDTArrayToReflectionArray(actualValue, actualType, expectedType); - } - else if (Class.class.equals(expectedType)) { - // package the Class-valued return as a MirroredTypeException - if (actualValue instanceof TypeBinding) { - TypeMirror mirror = this._env.getFactory().newTypeMirror((TypeBinding)actualValue); - throw new MirroredTypeException(mirror); - } - else { - // TODO: actual value is not a TypeBinding. Should we return a TypeMirror around an ErrorType? - return null; - } - } - else { - // Handle unitary values of type other than Class, e.g., int, MyEnum, ... - return convertJDTValueToReflectionType(actualValue, actualType, expectedType); - } - } - - /** - * Convert an array of JDT types as obtained from ElementValuePair.getValue() - * (e.g., an Object[] containing IntConstant elements) to the type expected by - * a reflective method invocation (e.g., int[]). - *

- * This does not handle arrays of Class, but it does handle primitives, enum constants, - * and types such as String. - * @param jdtValue the actual value returned by ElementValuePair.getValue() or MethodBinding.getDefault() - * @param jdtType the return type of the annotation method binding - * @param expectedType the type that the invoker of the method is expecting; must be an array type - * @return an Object which is, e.g., an int[]; or null, if an array cannot be created. - */ - private Object convertJDTArrayToReflectionArray(Object jdtValue, TypeBinding jdtType, Class expectedType) - { - assert null != expectedType && expectedType.isArray(); - if (!jdtType.isArrayType()) { - // the compiler says that the type binding isn't an array type; this probably means - // that there's some sort of syntax error. - return null; - } - Object[] jdtArray; - // See bug 261969: it's legal to pass a solo element for an array-typed value - if (jdtValue != null && !(jdtValue instanceof Object[])) { - // Create an array of the expected type - jdtArray = (Object[]) Array.newInstance(jdtValue.getClass(), 1); - jdtArray[0] = jdtValue; - } else { - jdtArray = (Object[])jdtValue; - } - TypeBinding jdtLeafType = jdtType.leafComponentType(); - Class expectedLeafType = expectedType.getComponentType(); - final int length = jdtArray.length; - final Object returnArray = Array.newInstance(expectedLeafType, length); - for (int i = 0; i < length; ++i) { - Object jdtElementValue = jdtArray[i]; - if (expectedLeafType.isPrimitive() || String.class.equals(expectedLeafType)) { - if (jdtElementValue instanceof Constant) { - if (boolean.class.equals(expectedLeafType)) { - Array.setBoolean(returnArray, i, ((Constant)jdtElementValue).booleanValue()); - } - else if (byte.class.equals(expectedLeafType)) { - Array.setByte(returnArray, i, ((Constant)jdtElementValue).byteValue()); - } - else if (char.class.equals(expectedLeafType)) { - Array.setChar(returnArray, i, ((Constant)jdtElementValue).charValue()); - } - else if (double.class.equals(expectedLeafType)) { - Array.setDouble(returnArray, i, ((Constant)jdtElementValue).doubleValue()); - } - else if (float.class.equals(expectedLeafType)) { - Array.setFloat(returnArray, i, ((Constant)jdtElementValue).floatValue()); - } - else if (int.class.equals(expectedLeafType)) { - Array.setInt(returnArray, i, ((Constant)jdtElementValue).intValue()); - } - else if (long.class.equals(expectedLeafType)) { - Array.setLong(returnArray, i, ((Constant)jdtElementValue).longValue()); - } - else if (short.class.equals(expectedLeafType)) { - Array.setShort(returnArray, i, ((Constant)jdtElementValue).shortValue()); - } - else if (String.class.equals(expectedLeafType)) { - Array.set(returnArray, i, ((Constant)jdtElementValue).stringValue()); - } - } - else { - // Primitive or string is expected, but our actual value cannot be coerced into one. - // TODO: if the actual value is an array of primitives, should we unpack the first one? - Factory.setArrayMatchingDummyValue(returnArray, i, expectedLeafType); - } - } - else if (expectedLeafType.isEnum()) { - Object returnVal = null; - if (jdtLeafType != null && jdtLeafType.isEnum() && jdtElementValue instanceof FieldBinding) { - FieldBinding binding = (FieldBinding)jdtElementValue; - try { - Field returnedField = null; - returnedField = expectedLeafType.getField( new String(binding.name) ); - if (null != returnedField) { - returnVal = returnedField.get(null); - } - } - catch (NoSuchFieldException nsfe) { - // return null - } - catch (IllegalAccessException iae) { - // return null - } - } - Array.set(returnArray, i, returnVal); - } - else if (expectedLeafType.isAnnotation()) { - // member value is expected to be an annotation type. Wrap it in an Annotation proxy. - Object returnVal = null; - if (jdtLeafType.isAnnotationType() && jdtElementValue instanceof AnnotationBinding) { - AnnotationMirrorImpl annoMirror = - (AnnotationMirrorImpl)this._env.getFactory().newAnnotationMirror((AnnotationBinding)jdtElementValue); - returnVal = Proxy.newProxyInstance(expectedLeafType.getClassLoader(), - new Class[]{ expectedLeafType }, annoMirror ); - } - Array.set(returnArray, i, returnVal); - } - else { - Array.set(returnArray, i, null); - } - } - return returnArray; - } - - /** - * Convert a JDT annotation value as obtained from ElementValuePair.getValue() - * (e.g., IntConstant, FieldBinding, etc.) to the type expected by a reflective - * method invocation (e.g., int, an enum constant, etc.). - * @return a value of type {@code expectedType}, or a dummy value of that type if - * the actual value cannot be converted. - */ - private Object convertJDTValueToReflectionType(Object jdtValue, TypeBinding actualType, Class expectedType) { - if (expectedType.isPrimitive() || String.class.equals(expectedType)) { - if (jdtValue instanceof Constant) { - if (boolean.class.equals(expectedType)) { - return ((Constant)jdtValue).booleanValue(); - } - else if (byte.class.equals(expectedType)) { - return ((Constant)jdtValue).byteValue(); - } - else if (char.class.equals(expectedType)) { - return ((Constant)jdtValue).charValue(); - } - else if (double.class.equals(expectedType)) { - return ((Constant)jdtValue).doubleValue(); - } - else if (float.class.equals(expectedType)) { - return ((Constant)jdtValue).floatValue(); - } - else if (int.class.equals(expectedType)) { - return ((Constant)jdtValue).intValue(); - } - else if (long.class.equals(expectedType)) { - return ((Constant)jdtValue).longValue(); - } - else if (short.class.equals(expectedType)) { - return ((Constant)jdtValue).shortValue(); - } - else if (String.class.equals(expectedType)) { - return ((Constant)jdtValue).stringValue(); - } - } - // Primitive or string is expected, but our actual value cannot be coerced into one. - // TODO: if the actual value is an array of primitives, should we unpack the first one? - return Factory.getMatchingDummyValue(expectedType); - } - else if (expectedType.isEnum()) { - Object returnVal = null; - if (actualType != null && actualType.isEnum() && jdtValue instanceof FieldBinding) { - - FieldBinding binding = (FieldBinding)jdtValue; - try { - Field returnedField = null; - returnedField = expectedType.getField( new String(binding.name) ); - if (null != returnedField) { - returnVal = returnedField.get(null); - } - } - catch (NoSuchFieldException nsfe) { - // return null - } - catch (IllegalAccessException iae) { - // return null - } - } - return null == returnVal ? Factory.getMatchingDummyValue(expectedType) : returnVal; - } - else if (expectedType.isAnnotation()) { - // member value is expected to be an annotation type. Wrap it in an Annotation proxy. - if (actualType.isAnnotationType() && jdtValue instanceof AnnotationBinding) { - AnnotationMirrorImpl annoMirror = - (AnnotationMirrorImpl)this._env.getFactory().newAnnotationMirror((AnnotationBinding)jdtValue); - return Proxy.newProxyInstance(expectedType.getClassLoader(), - new Class[]{ expectedType }, annoMirror ); - } - else { - // No way to cast a non-annotation value to an annotation type; return null to caller - return null; - } - } - else { - return Factory.getMatchingDummyValue(expectedType); - } - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java deleted file mode 100644 index 60d382e..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/AnnotationValueImpl.java +++ /dev/null @@ -1,307 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * het@google.com - Bug 441790 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.AnnotationValueVisitor; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeMirror; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.DoubleConstant; -import org.eclipse.jdt.internal.compiler.impl.FloatConstant; -import org.eclipse.jdt.internal.compiler.impl.LongConstant; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class AnnotationValueImpl implements AnnotationValue, TypeIds { - - /* - * Additions to T_* constants in TypeIds. - */ - private static final int T_AnnotationMirror = -1; - private static final int T_EnumConstant = -2; - private static final int T_ClassObject = -3; - private static final int T_ArrayType = -4; - - private final BaseProcessingEnvImpl _env; - - /** - * The annotation value, as it would be returned by - * {@link #getValue()}. For instance, an Integer (for an int - * constant), a VariableElement (for an enum constant), or - * a List containing multiple such (for an array type). - */ - private final Object _value; - - /** - * The type stored in _value, represented as a T_* value from {@link TypeIds} - * or one of the additional T_* values defined in this class. - */ - private final int _kind; - - /** - * @param value - * The JDT representation of a compile-time constant. See - * {@link org.eclipse.jdt.internal.compiler.lookup.ElementValuePair#getValue()} for possible object types: - *

    - *
  • {@link org.eclipse.jdt.internal.compiler.impl.Constant} for member - * of primitive type or String
  • - *
  • {@link TypeBinding} for a member value of type - * {@link java.lang.Class}
  • - *
  • {@link FieldBinding} for an enum constant
  • - *
  • {@link AnnotationBinding} for an annotation instance
  • - *
  • Object[] for a member value of array type, where the - * array entries are one of the above
  • - *
- * @param type - * The JDT representation of the type of the constant, as determined - * by the return type of the element. This is needed because the type - * of the value may have been widened (e.g., byte to int) by the compiler - * and we need to call the proper visitor. This is used only for base types. - * If it is null or not a BaseTypeBinding, it is ignored and the type is - * determined from the type of the value. - */ - public AnnotationValueImpl(BaseProcessingEnvImpl env, Object value, TypeBinding type) { - this._env = env; - int kind[] = new int[1]; - if (type == null) { - this._value = convertToMirrorType(value, type, kind); - this._kind = kind[0]; - } else if (type.isArrayType()) { - List convertedValues = null; - TypeBinding valueType = ((ArrayBinding)type).elementsType(); - if (value instanceof Object[]) { - Object[] values = (Object[])value; - convertedValues = new ArrayList<>(values.length); - for (Object oneValue : values) { - convertedValues.add(new AnnotationValueImpl(this._env, oneValue, valueType)); - } - } else { - convertedValues = new ArrayList<>(1); - convertedValues.add(new AnnotationValueImpl(this._env, value, valueType)); - } - this._value = Collections.unmodifiableList(convertedValues); - this._kind = T_ArrayType; - } else { - this._value = convertToMirrorType(value, type, kind); - this._kind = kind[0]; - } - } - - /** - * Convert the JDT representation of a single constant into its javax.lang.model - * representation. For instance, convert a StringConstant into a String, or - * a FieldBinding into a VariableElement. This does not handle the case where - * value is an Object[]. - * @param value the JDT object - * @param type the return type of the annotation member. If null or not a - * BaseTypeBinding, this is ignored and the value is inspected to determine type. - * @param kind an int array whose first element will be set to the type of the - * converted object, represented with T_* values from TypeIds or from this class. - * @return converted mirror type - */ - private Object convertToMirrorType(Object value, TypeBinding type, int kind[]) { - if (type == null) { - kind[0] = TypeIds.T_JavaLangString; - return ""; //$NON-NLS-1$ - } else if (type instanceof BaseTypeBinding || type.id == TypeIds.T_JavaLangString) { - if (value == null) { - if (type instanceof BaseTypeBinding - || type.id == TypeIds.T_JavaLangString) { - // return a string with error in it to reflect a value that could not be resolved - kind[0] = TypeIds.T_JavaLangString; - return ""; //$NON-NLS-1$ - } else if (type.isAnnotationType()) { - kind[0] = T_AnnotationMirror; - return this._env.getFactory().newAnnotationMirror(null); - } - } else if (value instanceof Constant) { - if (type instanceof BaseTypeBinding) { - kind[0] = ((BaseTypeBinding)type).id; - } - else if (type.id == TypeIds.T_JavaLangString) { - kind[0] = ((Constant)value).typeID(); - } else { - // error case - kind[0] = TypeIds.T_JavaLangString; - return ""; //$NON-NLS-1$ - } - switch (kind[0]) { - case T_boolean: - return ((Constant)value).booleanValue(); - case T_byte: - return ((Constant)value).byteValue(); - case T_char: - return ((Constant)value).charValue(); - case T_double: - return ((Constant)value).doubleValue(); - case T_float: - return ((Constant)value).floatValue(); - case T_int: - try { - if (value instanceof LongConstant - || value instanceof DoubleConstant - || value instanceof FloatConstant) { - // error case - kind[0] = TypeIds.T_JavaLangString; - return ""; //$NON-NLS-1$ - } - return ((Constant)value).intValue(); - } catch (ShouldNotImplement e) { - kind[0] = TypeIds.T_JavaLangString; - return ""; //$NON-NLS-1$ - } - case T_JavaLangString: - return ((Constant)value).stringValue(); - case T_long: - return ((Constant)value).longValue(); - case T_short: - return ((Constant)value).shortValue(); - } - } - } else if (type.isEnum()) { - if (value instanceof FieldBinding) { - kind[0] = T_EnumConstant; - return this._env.getFactory().newElement((FieldBinding) value); - } else { - kind[0] = TypeIds.T_JavaLangString; - return ""; //$NON-NLS-1$ - } - } else if (type.isAnnotationType()) { - if (value instanceof AnnotationBinding) { - kind[0] = T_AnnotationMirror; - return this._env.getFactory().newAnnotationMirror((AnnotationBinding) value); - } - } else if (value instanceof TypeBinding) { - kind[0] = T_ClassObject; - return this._env.getFactory().newTypeMirror((TypeBinding) value); - } - // error case - kind[0] = TypeIds.T_JavaLangString; - return ""; //$NON-NLS-1$ - } - - @SuppressWarnings("unchecked") // Need to cast Object _value to a List - @Override - public R accept(AnnotationValueVisitor v, P p) { - switch (this._kind) { - case TypeIds.T_boolean: - return v.visitBoolean((Boolean)this._value, p); - case TypeIds.T_byte: - return v.visitByte((Byte)this._value, p); - case TypeIds.T_char: - return v.visitChar((Character)this._value, p); - case TypeIds.T_double: - return v.visitDouble((Double)this._value, p); - case TypeIds.T_float: - return v.visitFloat((Float)this._value, p); - case TypeIds.T_int: - return v.visitInt((Integer)this._value, p); - case TypeIds.T_JavaLangString: - return v.visitString((String)this._value, p); - case TypeIds.T_long: - return v.visitLong((Long)this._value, p); - case TypeIds.T_short: - return v.visitShort((Short)this._value, p); - case T_EnumConstant: - return v.visitEnumConstant((VariableElement)this._value, p); - case T_ClassObject: - return v.visitType((TypeMirror)this._value, p); - case T_AnnotationMirror: - return v.visitAnnotation((AnnotationMirror)this._value, p); - case T_ArrayType: - return v.visitArray((List)this._value, p); - default: - return null; - } - } - - @Override - public Object getValue() { - return this._value; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof AnnotationValueImpl) { - return this._value.equals(((AnnotationValueImpl) obj)._value); - } - return false; - } - - @Override - public int hashCode() { - return this._value.hashCode() + this._kind; - } - - @Override - public String toString() { - if (this._value == null) { - return "null"; //$NON-NLS-1$ - } else if (this._value instanceof String) { - String value = (String) this._value; - StringBuilder sb = new StringBuilder(); - sb.append('"'); - for (int i = 0; i < value.length(); i++) { - Util.appendEscapedChar(sb, value.charAt(i), true); - } - sb.append('"'); - return sb.toString(); - } else if (this._value instanceof Character) { - StringBuilder sb = new StringBuilder(); - sb.append('\''); - Util.appendEscapedChar(sb, ((Character) this._value).charValue(), false); - sb.append('\''); - return sb.toString(); - } else if (this._value instanceof VariableElement) { - VariableElement enumDecl = (VariableElement) this._value; - return enumDecl.asType().toString() + "." + enumDecl.getSimpleName(); //$NON-NLS-1$ - } else if (this._value instanceof Collection) { - // It must be Collection - @SuppressWarnings("unchecked") - Collection values = (Collection) this._value; - StringBuilder sb = new StringBuilder(); - sb.append('{'); - boolean first = true; - for (AnnotationValue annoValue : values) { - if (!first) { - sb.append(", "); //$NON-NLS-1$ - } - first = false; - sb.append(annoValue.toString()); - } - sb.append('}'); - return sb.toString(); - } else if (this._value instanceof TypeMirror) { - return this._value.toString() + ".class"; //$NON-NLS-1$ - } else { - return this._value.toString(); - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java deleted file mode 100644 index 378c716..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ArrayTypeImpl.java +++ /dev/null @@ -1,75 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2014 BEA Systems, Inc. and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * IBM Corporation - fix for 342598 - * IBM Corporation - Java 8 support - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVisitor; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; - -/** - * Implementation of ArrayType, which represents an array of some type. - */ -public class ArrayTypeImpl extends TypeMirrorImpl implements ArrayType { - - ArrayTypeImpl(BaseProcessingEnvImpl env, ArrayBinding binding) { - super(env, binding); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.ArrayType#getComponentType() - */ - @Override - public TypeMirror getComponentType() { - return this._env.getFactory().newTypeMirror(((ArrayBinding)this._binding).elementsType()); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object) - */ - @Override - public R accept(TypeVisitor v, P p) { - return v.visitArray(this, p); - } - - @Override - protected AnnotationBinding[] getAnnotationBindings() { - AnnotationBinding[] oldies = ((ArrayBinding)this._binding).getTypeAnnotations(); - AnnotationBinding[] newbies = Binding.NO_ANNOTATIONS; - // Strip out the annotations on sub arrays - for (int i = 0, length = oldies == null ? 0 : oldies.length; i < length; i++) { - if (oldies[i] == null) { - System.arraycopy(oldies, 0, newbies = new AnnotationBinding[i], 0, i); - return newbies; - } - } - return newbies; - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#getKind() - */ - @Override - public TypeKind getKind() { - return TypeKind.ARRAY; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java deleted file mode 100644 index f1ece38..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/DeclaredTypeImpl.java +++ /dev/null @@ -1,130 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2023 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * IBM Corporation - fix for 342598 - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVisitor; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -/** - * Implementation of DeclaredType, which refers to a particular usage or instance of a type. - * Contrast with {@link javax.lang.model.element.TypeElement}, which is an element that potentially defines a family - * of DeclaredTypes. - */ -public class DeclaredTypeImpl extends TypeMirrorImpl implements DeclaredType { - - private final ElementKind _elementKindHint; - - /* package */ DeclaredTypeImpl(BaseProcessingEnvImpl env, ReferenceBinding binding) { - super(env, binding); - this._elementKindHint = null; - } - - /** - * Create a DeclaredType that knows in advance what kind of element to produce from asElement(). - * This is useful in the case where the type binding is to an unresolved type, but we know - * from context what type it is - e.g., an annotation type. - */ - /* package */ DeclaredTypeImpl(BaseProcessingEnvImpl env, ReferenceBinding binding, ElementKind elementKindHint) { - super(env, binding); - this._elementKindHint = elementKindHint; - } - - @Override - public Element asElement() { - TypeBinding prototype = null; - if (this._binding instanceof TypeBinding) { - prototype = ((TypeBinding) this._binding).prototype(); - } - if (prototype != null) { - return this._env.getFactory().newElement(prototype, this._elementKindHint); - } - // The JDT compiler does not distinguish between type elements and declared types - return this._env.getFactory().newElement(this._binding, this._elementKindHint); - } - - @Override - public TypeMirror getEnclosingType() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - ReferenceBinding enclosingType = binding.enclosingType(); - if (enclosingType != null) { - return this._env.getFactory().newTypeMirror(enclosingType); - } - return this._env.getFactory().getNoType(TypeKind.NONE); - } - - /* - * (non-Javadoc) - * @see javax.lang.model.type.DeclaredType#getTypeArguments() - * @see javax.lang.model.element.TypeElement#getTypeParameters(). - */ - @Override - public List getTypeArguments() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - if (binding.isParameterizedType()) { - ParameterizedTypeBinding ptb = (ParameterizedTypeBinding)this._binding; - TypeBinding[] arguments = ptb.arguments; - int length = arguments == null ? 0 : arguments.length; - if (length == 0) return Collections.emptyList(); - List args = new ArrayList<>(length); - for (TypeBinding arg : arguments) { - args.add(this._env.getFactory().newTypeMirror(arg)); - } - return Collections.unmodifiableList(args); - } - if (binding.isGenericType()) { - TypeVariableBinding[] typeVariables = binding.typeVariables(); - List args = new ArrayList<>(typeVariables.length); - for (TypeBinding arg : typeVariables) { - args.add(this._env.getFactory().newTypeMirror(arg)); - } - return Collections.unmodifiableList(args); - } - return Collections.emptyList(); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object) - */ - @Override - public R accept(TypeVisitor v, P p) { - return v.visitDeclared(this, p); - } - - @Override - public TypeKind getKind() { - return TypeKind.DECLARED; - } - - @Override - public String toString() { - return new String(this._binding.readableName()); - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java deleted file mode 100644 index b258002..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ElementImpl.java +++ /dev/null @@ -1,158 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.lang.annotation.Annotation; -import java.lang.annotation.Inherited; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; -import javax.lang.model.element.PackageElement; -import javax.lang.model.type.TypeMirror; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; - -/** - * Element represents any defined Java language element - a package, - * a method, a class or interface. Contrast with DeclaredType. - */ -public abstract class ElementImpl - implements javax.lang.model.element.Element, IElementInfo -{ - public final BaseProcessingEnvImpl _env; - public final Binding _binding; - - protected ElementImpl(BaseProcessingEnvImpl env, Binding binding) { - this._env = env; - this._binding = binding; - } - - @Override - public TypeMirror asType() { - return this._env.getFactory().newTypeMirror(this._binding); - } - - /** - * @return the set of compiler annotation bindings on this element - */ - protected abstract AnnotationBinding[] getAnnotationBindings(); - - /* Package any repeating annotations into containers, return others as is. - In the compiler bindings repeating annotations are left in as is, hence - this step. The return value would match what one would expect to see in - a class file. - */ - public final AnnotationBinding [] getPackedAnnotationBindings() { - return Factory.getPackedAnnotationBindings(getAnnotationBindings()); - } - - @Override - public A getAnnotation(Class annotationClass) { - A annotation = this._env.getFactory().getAnnotation(getPackedAnnotationBindings(), annotationClass); - if (annotation != null || this.getKind() != ElementKind.CLASS || annotationClass.getAnnotation(Inherited.class) == null) - return annotation; - - ElementImpl superClass = (ElementImpl) this._env.getFactory().newElement(((ReferenceBinding) this._binding).superclass()); - return superClass == null ? null : superClass.getAnnotation(annotationClass); - } - - @Override - public List getAnnotationMirrors() { - return this._env.getFactory().getAnnotationMirrors(getPackedAnnotationBindings()); - } - - @Override - public A[] getAnnotationsByType(Class annotationType) { - A [] annotations = this._env.getFactory().getAnnotationsByType(Factory.getUnpackedAnnotationBindings(getPackedAnnotationBindings()), annotationType); - if (annotations.length != 0 || this.getKind() != ElementKind.CLASS || annotationType.getAnnotation(Inherited.class) == null) - return annotations; - - ElementImpl superClass = (ElementImpl) this._env.getFactory().newElement(((ReferenceBinding) this._binding).superclass()); - return superClass == null ? annotations : superClass.getAnnotationsByType(annotationType); - } - - @Override - public Set getModifiers() { - // Most subclasses implement this; this default is appropriate for - // PackageElement and TypeParameterElement. - return Collections.emptySet(); - } - - @Override - public Name getSimpleName() { - return new NameImpl(this._binding.shortReadableName()); - } - - @Override - public int hashCode() { - return this._binding.hashCode(); - } - - // TODO: equals() implemented as == of JDT bindings. Valid within - // a single Compiler instance; breaks in IDE if processors cache values. - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final ElementImpl other = (ElementImpl) obj; - if (this._binding == null) { - if (other._binding != null) - return false; - } else if (this._binding != other._binding) - return false; - return true; - } - - @Override - public String toString() { - return this._binding.toString(); - } - - @Override - public String getFileName() { - // Subclasses should override and return something of value - return null; - } - - /** - * @return the package containing this element. The package of a PackageElement is itself. - */ - PackageElement getPackage() { - return null; - } - - /** - * Subclassed by VariableElementImpl, TypeElementImpl, and ExecutableElementImpl. - * This base implementation suffices for other types. - * @see javax.lang.model.util.Elements#hides - * @return true if this element hides {@code hidden} - */ - public boolean hides(Element hidden) - { - return false; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java deleted file mode 100644 index 20b5173..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl.java +++ /dev/null @@ -1,741 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2023 BEA Systems, Inc. and others - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * IBM Corporation - Fix for bug 341494 - * IBM Corporation - Fix for bug 328575 - * IBM Corporation - Java 8 support - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.lang.model.SourceVersion; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.ModuleElement; -import javax.lang.model.element.Name; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Javadoc; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; - -/** - * Utilities for working with java8 and earlier language elements. - * There is one of these for every ProcessingEnvironment. - * - * @see ElementsImpl9 - */ -public class ElementsImpl implements Elements { - - // Used for parsing Javadoc comments: matches initial delimiter, followed by whitespace - private static final Pattern INITIAL_DELIMITER = Pattern.compile("^\\s*/\\*+"); //$NON-NLS-1$ - - protected final BaseProcessingEnvImpl _env; - - /* - * The processing env creates and caches an ElementsImpl. Other clients should - * not create their own; they should ask the env for it. - */ - protected ElementsImpl(BaseProcessingEnvImpl env) { - this._env = env; - } - - public static ElementsImpl create(BaseProcessingEnvImpl env) { - return (SourceVersion.latest().compareTo(SourceVersion.RELEASE_8) <= 0)? new ElementsImpl(env): new ElementsImpl9(env); - } - - /** - * Return all the annotation mirrors on this element, including inherited annotations. - * Annotations are inherited only if the annotation type is meta-annotated with @Inherited, - * and the annotation is on a class: e.g., annotations are not inherited for interfaces, methods, - * or fields. - */ - @Override - public List getAllAnnotationMirrors(Element e) { - // if e is a class, walk up its superclass hierarchy looking for @Inherited annotations not already in the list - if (e.getKind() == ElementKind.CLASS && e instanceof TypeElementImpl) { - List annotations = new ArrayList<>(); - // A class can only have one annotation of a particular annotation type. - Set annotationTypes = new HashSet<>(); - ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl)e)._binding; - boolean checkIfInherited = false; - while (null != binding) { - if (binding instanceof ParameterizedTypeBinding) { - binding = ((ParameterizedTypeBinding) binding).genericType(); - } - for (AnnotationBinding annotation : Factory.getPackedAnnotationBindings(binding.getAnnotations())) { - if (annotation == null) continue; - ReferenceBinding annotationType = annotation.getAnnotationType(); - if (checkIfInherited && (annotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) == 0) - continue; - if (!annotationTypes.contains(annotationType)) { - annotationTypes.add(annotationType); - annotations.add(annotation); - } - } - binding = binding.superclass(); - checkIfInherited = true; - } - List list = new ArrayList<>(annotations.size()); - for (AnnotationBinding annotation : annotations) { - list.add(this._env.getFactory().newAnnotationMirror(annotation)); - } - return Collections.unmodifiableList(list); - } - else { - return e.getAnnotationMirrors(); - } - } - - /** - * Compute a list of all the visible entities in this type. Specifically: - *
    - *
  • All nested types declared in this type, including interfaces and enums
  • - *
  • All protected or public nested types declared in this type's superclasses - * and superinterfaces, that are not hidden by a name collision
  • - *
  • All methods declared in this type, including constructors but not - * including static or instance initializers, and including abstract - * methods and unimplemented methods declared in interfaces
  • - *
  • All protected or public methods declared in this type's superclasses, - * that are not overridden by another method, but not including constructors - * or initializers. Includes abstract methods and methods declared in - * superinterfaces but not implemented
  • - *
  • All fields declared in this type, including constants
  • - *
  • All non-private fields declared in this type's superclasses and - * superinterfaces, that are not hidden by a name collision.
  • - *
- */ - @Override - public List getAllMembers(TypeElement type) { - if (null == type || !(type instanceof TypeElementImpl)) { - return Collections.emptyList(); - } - ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl)type)._binding; - // Map of element simple name to binding - Map types = new HashMap<>(); - // Javac implementation does not take field name collisions into account - List fields = new ArrayList<>(); - // For methods, need to compare parameters, not just names - Map> methods = new HashMap<>(); - Set superinterfaces = new LinkedHashSet<>(); - boolean ignoreVisibility = true; - while (null != binding) { - addMembers(binding, ignoreVisibility, types, fields, methods); - Set newfound = new LinkedHashSet<>(); - collectSuperInterfaces(binding, superinterfaces, newfound); - for (ReferenceBinding superinterface : newfound) { - addMembers(superinterface, false, types, fields, methods); - } - superinterfaces.addAll(newfound); - binding = binding.superclass(); - ignoreVisibility = false; - } - List allMembers = new ArrayList<>(); - for (ReferenceBinding nestedType : types.values()) { - allMembers.add(this._env.getFactory().newElement(nestedType)); - } - for (FieldBinding field : fields) { - allMembers.add(this._env.getFactory().newElement(field)); - } - for (Set sameNamedMethods : methods.values()) { - for (MethodBinding method : sameNamedMethods) { - allMembers.add(this._env.getFactory().newElement(method)); - } - } - return allMembers; - } - - /** - * Recursively depth-first walk the tree of superinterfaces of a type, collecting - * all the unique superinterface bindings. (Note that because of generics, a type may - * have multiple unique superinterface bindings corresponding to the same interface - * declaration.) - * @param existing bindings already in this set will not be re-added or recursed into - * @param newfound newly found bindings will be added to this set - */ - private void collectSuperInterfaces(ReferenceBinding type, - Set existing, Set newfound) { - for (ReferenceBinding superinterface : type.superInterfaces()) { - if (!existing.contains(superinterface) && !newfound.contains(superinterface)) { - newfound.add(superinterface); - collectSuperInterfaces(superinterface, existing, newfound); - } - } - } - - /** - * Add the members of a type to the maps of subtypes, fields, and methods. Add only those - * which are non-private and which are not overridden by an already-discovered member. - * For fields, add them all; javac implementation does not take field hiding into account. - * @param binding the type whose members will be added to the lists - * @param directMembers if true, all members will be added regardless of whether they - * are private, overridden, static etc. - * @param types a map of type simple name to type binding - * @param fields a list of field bindings - * @param methods a map of method simple name to set of method bindings with that name - */ - private void addMembers(ReferenceBinding binding, boolean directMembers, Map types, - List fields, Map> methods) - { - for (ReferenceBinding subtype : binding.memberTypes()) { - if (directMembers || !subtype.isPrivate()) { - String name = new String(subtype.sourceName()); - if (null == types.get(name)) { - types.put(name, subtype); - } - } - } - for (FieldBinding field : binding.fields()) { - if (directMembers || !field.isPrivate()) { - fields.add(field); - } - } - for (MethodBinding method : binding.methods()) { - if (!directMembers && method.isStatic()) - continue; - if (!method.isSynthetic() && (directMembers || (!method.isPrivate() && !method.isConstructor()))) { - String methodName = new String(method.selector); - Set sameNamedMethods = methods.get(methodName); - if (null == sameNamedMethods) { - // New method name. Create a set for it and add it to the list. - // We don't expect many methods with same name, so only 4 slots: - sameNamedMethods = new HashSet<>(4); - methods.put(methodName, sameNamedMethods); - sameNamedMethods.add(method); - } - else { - // We already have a method with this name. Is this method overridden? - boolean unique = true; - if (!directMembers) { - for (MethodBinding existing : sameNamedMethods) { - MethodVerifier verifier = this._env.getLookupEnvironment().methodVerifier(); - if (verifier.doesMethodOverride(existing, method)) { - unique = false; - break; - } - } - } - if (unique) { - sameNamedMethods.add(method); - } - } - } - } - } - - /* (non-Javadoc) - * @see javax.lang.model.util.Elements#getBinaryName(javax.lang.model.element.TypeElement) - */ - @Override - public Name getBinaryName(TypeElement type) { - TypeElementImpl typeElementImpl = (TypeElementImpl) type; - ReferenceBinding referenceBinding = (ReferenceBinding) typeElementImpl._binding; - return new NameImpl( - CharOperation.replaceOnCopy(referenceBinding.constantPoolName(), '/', '.')); - } - - /* (non-Javadoc) - * @see javax.lang.model.util.Elements#getConstantExpression(java.lang.Object) - */ - @Override - public String getConstantExpression(Object value) { - if (!(value instanceof Integer) - && !(value instanceof Byte) - && !(value instanceof Float) - && !(value instanceof Double) - && !(value instanceof Long) - && !(value instanceof Short) - && !(value instanceof Character) - && !(value instanceof String) - && !(value instanceof Boolean)) { - throw new IllegalArgumentException("Not a valid wrapper type : " + value.getClass()); //$NON-NLS-1$ - } - if (value instanceof Character) { - StringBuilder builder = new StringBuilder(); - builder.append('\'').append(value).append('\''); - return String.valueOf(builder); - } else if (value instanceof String) { - StringBuilder builder = new StringBuilder(); - builder.append('\"').append(value).append('\"'); - return String.valueOf(builder); - } else if (value instanceof Float) { - StringBuilder builder = new StringBuilder(); - builder.append(value).append('f'); - return String.valueOf(builder); - } else if (value instanceof Long) { - StringBuilder builder = new StringBuilder(); - builder.append(value).append('L'); - return String.valueOf(builder); - } else if (value instanceof Short) { - StringBuilder builder = new StringBuilder(); - builder.append("(short)").append(value); //$NON-NLS-1$ - return String.valueOf(builder); - } else if (value instanceof Byte) { - StringBuilder builder = new StringBuilder(); - builder.append("(byte)0x"); //$NON-NLS-1$ - int intValue = ((Byte) value).byteValue(); - String hexString = Integer.toHexString(intValue & 0xFF); - if (hexString.length() < 2) { - builder.append('0'); - } - builder.append(hexString); - return String.valueOf(builder); - } - return String.valueOf(value); - } - - /* (non-Javadoc) - * @see javax.lang.model.util.Elements#getDocComment(javax.lang.model.element.Element) - */ - @Override - public String getDocComment(Element e) { - char[] unparsed = getUnparsedDocComment(e); - return formatJavadoc(unparsed); - } - - /** - * Return the entire javadoc comment on e, including the comment characters and whitespace - * @param e an Element of any sort, possibly with a javadoc comment. - * @return a String, or null if the comment is not available - */ - private char[] getUnparsedDocComment(Element e) - { - Javadoc javadoc = null; - ReferenceContext referenceContext = null; - switch(e.getKind()) { - case ANNOTATION_TYPE : - case CLASS : - case ENUM : - case INTERFACE : - case RECORD : - TypeElementImpl typeElementImpl = (TypeElementImpl) e; - ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding; - if (referenceBinding instanceof SourceTypeBinding) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) referenceBinding; - referenceContext = sourceTypeBinding.scope.referenceContext; - javadoc = ((TypeDeclaration) referenceContext).javadoc; - } - break; - case PACKAGE : - // might need to handle javadoc of package-info.java file - PackageElementImpl packageElementImpl = (PackageElementImpl) e; - PackageBinding packageBinding = (PackageBinding) packageElementImpl._binding; - char[][] compoundName = CharOperation.arrayConcat(packageBinding.compoundName, TypeConstants.PACKAGE_INFO_NAME); - ReferenceBinding type = this._env.getLookupEnvironment().getType(compoundName); - if (type != null && type.isValidBinding() && (type instanceof SourceTypeBinding)) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) type; - referenceContext = sourceTypeBinding.scope.referenceContext; - javadoc = ((TypeDeclaration) referenceContext).javadoc; - } - break; - case CONSTRUCTOR : - case METHOD : - ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) e; - MethodBinding methodBinding = (MethodBinding) executableElementImpl._binding; - AbstractMethodDeclaration sourceMethod = methodBinding.sourceMethod(); - if (sourceMethod != null) { - javadoc = sourceMethod.javadoc; - referenceContext = sourceMethod; - } - break; - case RECORD_COMPONENT : - case ENUM_CONSTANT : - case FIELD : - VariableElementImpl variableElementImpl = (VariableElementImpl) e; - FieldBinding fieldBinding = (FieldBinding) variableElementImpl._binding; - FieldDeclaration sourceField = fieldBinding.sourceField(); - if (sourceField != null) { - javadoc = sourceField.javadoc; - if (fieldBinding.declaringClass instanceof SourceTypeBinding) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) fieldBinding.declaringClass; - referenceContext = sourceTypeBinding.scope.referenceContext; - } - } - break; - default: - return null; - } - if (javadoc != null && referenceContext != null) { - char[] contents = referenceContext.compilationResult().getCompilationUnit().getContents(); - if (contents != null) { - return CharOperation.subarray(contents, javadoc.sourceStart, javadoc.sourceEnd - 1); - } - } - return null; - } - - /** - * Strip the comment characters from a javadoc comment. Assume the comment is already - * missing its closing delimiter. - * - * Javac's behavior with regard to tab expansion and trimming of whitespace and - * asterisks is bizarre and undocumented. We do our best here to emulate it. - */ - private static String formatJavadoc(char[] unparsed) - { - if (unparsed == null || unparsed.length < 5) { // delimiters take 5 chars - return null; - } - - String[] lines = new String(unparsed).split("\n"); //$NON-NLS-1$ - Matcher delimiterMatcher = INITIAL_DELIMITER.matcher(lines[0]); - if (!delimiterMatcher.find()) { - return null; - } - int iOpener = delimiterMatcher.end(); - lines[0] = lines[0].substring(iOpener); - if (lines.length == 1) { - // single-line comment. Should trim(), but javac doesn't. - // we should however remove the starting whitespaces - StringBuilder sb = new StringBuilder(); - char[] chars = lines[0].toCharArray(); - boolean startingWhitespaces = true; - for (char c : chars) { - if (Character.isWhitespace(c)) - if (startingWhitespaces) { - continue; - } else { - sb.append(c); - } else { - startingWhitespaces = false; - sb.append(c); - } - } - return sb.toString(); - } - - // if the first line ends with spaces after the /** then we want to insert a line separator - int firstLine = lines[0].trim().length() > 0 ? 0 : 1; - - // If the last line is now empty, skip it - int lastLine = lines[lines.length - 1].trim().length() > 0 ? lines.length - 1 : lines.length - 2; - - StringBuilder sb = new StringBuilder(); - if (lines[0].length() != 0 && firstLine == 1) { - // insert a line separator only if the remaining chars on the line are whitespaces - sb.append('\n'); - } - boolean preserveLineSeparator = lines[0].length() == 0; - for (int line = firstLine; line <= lastLine; ++line) { - char[] chars = lines[line].toCharArray(); - int starsIndex = getStars(chars); - int leadingWhitespaces = 0; - boolean recordLeadingWhitespaces = true; - for (int i = 0, max = chars.length; i < max; i++) { - char c = chars[i]; - switch(c) { - case ' ' : - if (starsIndex == -1) { - if (recordLeadingWhitespaces) { - leadingWhitespaces++; - } else { - sb.append(c); - } - } else if (i >= starsIndex) { - sb.append(c); - } - break; - default : - // convert leadingwhitespaces to spaces - recordLeadingWhitespaces = false; - if (leadingWhitespaces != 0) { - int numberOfTabs = leadingWhitespaces / 8; - if (numberOfTabs != 0) { - for (int j = 0, max2 = numberOfTabs; j < max2; j++) { - sb.append(" "); //$NON-NLS-1$ - } - if ((leadingWhitespaces % 8) >= 1) { - sb.append(' '); - } - } else if (line != 0) { - // we don't want to preserve the leading spaces for the first line - for (int j = 0, max2 = leadingWhitespaces; j < max2; j++) { - sb.append(' '); - } - } - leadingWhitespaces = 0; - sb.append(c); - } else if (c == '\t') { - if (i >= starsIndex) { - sb.append(c); - } - } else if (c != '*' || i > starsIndex) { - sb.append(c); - } - } - } - - // append a newline at the end of each line except the last, even if we skipped the last entirely - int end = lines.length - 1; - if (line < end) { - sb.append('\n'); - } else if (preserveLineSeparator && line == end) { - sb.append('\n'); - } - } - return sb.toString(); - } - - /** - * Returns the index of the last leading stars on this line, -1 if none. - * - * @param line the given line - * @return the computed index - */ - private static int getStars(char[] line) { - loop: for (int i = 0, max = line.length; i < max; i++) { - char c = line[i]; - if (!Character.isWhitespace(c)) { - if (c == '*') { - // only whitespaces before the first star - // consume all stars and return the last index - for (int j = i + 1; j < max; j++) { - if (line[j] != '*') { - return j; - } - } - return max - 1; - } - // no need to continue - break loop; - } - } - return -1; - } - /** - * @return all the annotation instance's explicitly set values, plus default values - * for all the annotation members that are not explicitly set but that have - * defaults. By comparison, {@link AnnotationMirror#getElementValues()} only - * returns the explicitly set values. - * @see javax.lang.model.util.Elements#getElementValuesWithDefaults(javax.lang.model.element.AnnotationMirror) - */ - @Override - public Map getElementValuesWithDefaults( - AnnotationMirror a) { - return ((AnnotationMirrorImpl)a).getElementValuesWithDefaults(); - } - - /* (non-Javadoc) - * @see javax.lang.model.util.Elements#getName(java.lang.CharSequence) - */ - @Override - public Name getName(CharSequence cs) { - return new NameImpl(cs); - } - - @Override - public PackageElement getPackageElement(CharSequence name) { - LookupEnvironment le = this._env.getLookupEnvironment(); // FIXME(SHMOD): does this lookup need to be module-aware? - if (name.length() == 0) { - return (PackageElement) this._env.getFactory().newElement(le.defaultPackage); - } - char[] packageName = name.toString().toCharArray(); - PackageBinding packageBinding = le.createPackage(CharOperation.splitOn('.', packageName)); - if (packageBinding == null) { - return null; - } - return (PackageElement) this._env.getFactory().newElement(packageBinding); - } - - @Override - public PackageElement getPackageOf(Element type) { - switch(type.getKind()) { - case ANNOTATION_TYPE : - case CLASS : - case ENUM : - case INTERFACE : - case RECORD : - TypeElementImpl typeElementImpl = (TypeElementImpl) type; - ReferenceBinding referenceBinding = (ReferenceBinding)typeElementImpl._binding; - return (PackageElement) this._env.getFactory().newElement(referenceBinding.fPackage); - case PACKAGE : - return (PackageElement) type; - case CONSTRUCTOR : - case METHOD : - ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) type; - MethodBinding methodBinding = (MethodBinding) executableElementImpl._binding; - return (PackageElement) this._env.getFactory().newElement(methodBinding.declaringClass.fPackage); - case ENUM_CONSTANT : - case FIELD : - case RECORD_COMPONENT : - VariableElementImpl variableElementImpl = (VariableElementImpl) type; - FieldBinding fieldBinding = (FieldBinding) variableElementImpl._binding; - return (PackageElement) this._env.getFactory().newElement(fieldBinding.declaringClass.fPackage); - case PARAMETER : - variableElementImpl = (VariableElementImpl) type; - LocalVariableBinding localVariableBinding = (LocalVariableBinding) variableElementImpl._binding; - return (PackageElement) this._env.getFactory().newElement(localVariableBinding.declaringScope.classScope().referenceContext.binding.fPackage); - case EXCEPTION_PARAMETER : - case INSTANCE_INIT : - case OTHER : - case STATIC_INIT : - case TYPE_PARAMETER : - case LOCAL_VARIABLE : - return null; - default: - break; - } - // unreachable - return null; - } - - /* (non-Javadoc) - * @see javax.lang.model.util.Elements#getTypeElement(java.lang.CharSequence) - */ - @Override - public TypeElement getTypeElement(CharSequence name) { - LookupEnvironment le = this._env.getLookupEnvironment(); - final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray()); - ReferenceBinding binding = le.getType(compoundName); - // If we didn't find the binding, maybe it's a nested type; - // try finding the top-level type and then working downwards. - if (null == binding) { - ReferenceBinding topLevelBinding = null; - int topLevelSegments = compoundName.length; - while (--topLevelSegments > 0) { - char[][] topLevelName = new char[topLevelSegments][]; - for (int i = 0; i < topLevelSegments; ++i) { - topLevelName[i] = compoundName[i]; - } - topLevelBinding = le.getType(topLevelName); - if (null != topLevelBinding) { - break; - } - } - if (null == topLevelBinding) { - return null; - } - binding = topLevelBinding; - for (int i = topLevelSegments; null != binding && i < compoundName.length; ++i) { - binding = binding.getMemberType(compoundName[i]); - } - } - if (null == binding) { - return null; - } - if((binding.tagBits & TagBits.HasMissingType) != 0) { - return null; - } - return new TypeElementImpl(this._env, binding, null); - } - - /* (non-Javadoc) - * Element A hides element B if: A and B are both fields, both nested types, or both methods; and - * the enclosing element of B is a superclass or superinterface of the enclosing element of A. - * See JLS 8.3 (for hiding of fields), 8.4.8.2 (hiding of class methods), and 8.5 (for hiding of member types). - * @see javax.lang.model.util.Elements#hides(javax.lang.model.element.Element, javax.lang.model.element.Element) - */ - @Override - public boolean hides(Element hider, Element hidden) { - if (hidden == null) { - // required by API spec - throw new NullPointerException(); - } - return ((ElementImpl)hider).hides(hidden); - } - - /* (non-Javadoc) - * @see javax.lang.model.util.Elements#isDeprecated(javax.lang.model.element.Element) - */ - @Override - public boolean isDeprecated(Element e) { - if (!(e instanceof ElementImpl)) { - return false; - } - return (((ElementImpl)e)._binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0; - } - - /* (non-Javadoc) - * See JLS 8.4.8.1 for discussion of hiding of methods - * @see javax.lang.model.util.Elements#overrides(javax.lang.model.element.ExecutableElement, javax.lang.model.element.ExecutableElement, javax.lang.model.element.TypeElement) - */ - @Override - public boolean overrides(ExecutableElement overrider, ExecutableElement overridden, - TypeElement type) { - if (overridden == null || type == null) { - throw new NullPointerException(); - } - return ((ExecutableElementImpl)overrider).overrides(overridden, type); - } - - /* (non-Javadoc) - * @see javax.lang.model.util.Elements#printElements(java.io.Writer, javax.lang.model.element.Element[]) - */ - @Override - public void printElements(Writer w, Element... elements) { - String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$ - for (Element element : elements) { - try { - w.write(element.toString()); - w.write(lineSeparator); - } catch (IOException e) { - // ignore - } - } - try { - w.flush(); - } catch (IOException e) { - // ignore - } - } - - @Override - public boolean isFunctionalInterface(TypeElement type) { - if (type != null && type.getKind() == ElementKind.INTERFACE) { - ReferenceBinding binding = (ReferenceBinding)((TypeElementImpl) type)._binding; - if (binding instanceof SourceTypeBinding) { - return binding.isFunctionalInterface(((SourceTypeBinding) binding).scope); - } - } - return false; - } - @Override - public boolean isAutomaticModule(ModuleElement module) { - ModuleBinding binding = ((ModuleElementImpl) module).binding; - return binding != null ? binding.isAutomatic() : false; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl9.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl9.java deleted file mode 100644 index ed97430..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ElementsImpl9.java +++ /dev/null @@ -1,307 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2023 BEA Systems, Inc. and others - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Igor Fedorenko - extracted from ElementsImpl - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.io.File; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import javax.lang.model.AnnotatedConstruct; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.ModuleElement; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.JavaFileObject.Kind; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.BinaryModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceModuleBinding; -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.tool.EclipseFileManager; -import org.eclipse.jdt.internal.compiler.tool.PathFileObject; -import org.eclipse.jdt.internal.compiler.util.HashtableOfModule; - -/** - * Utilities for working with java9 language elements. - * There is one of these for every ProcessingEnvironment. - */ -public class ElementsImpl9 extends ElementsImpl { - - public ElementsImpl9(BaseProcessingEnvImpl env) { - super(env); - } - - @Override - public TypeElement getTypeElement(CharSequence name) { - final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray()); - Set allModuleElements = getAllModuleElements(); - for (ModuleElement moduleElement : allModuleElements) { - TypeElement t = getTypeElement(compoundName, ((ModuleElementImpl) moduleElement).binding); - if (t != null) { - return t; - } - } - return null; - } - - @Override - public TypeElement getTypeElement(ModuleElement module, CharSequence name) { - ModuleBinding mBinding = ((ModuleElementImpl) module).binding; - final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray()); - return getTypeElement(compoundName, mBinding); - } - - private TypeElement getTypeElement(final char[][] compoundName, ModuleBinding mBinding) { - LookupEnvironment le = mBinding == null ? this._env.getLookupEnvironment() : mBinding.environment; - ReferenceBinding binding = mBinding == null ? le.getType(compoundName) : le.getType(compoundName, mBinding); - // If we didn't find the binding, maybe it's a nested type; - // try finding the top-level type and then working downwards. - if (null == binding) { - ReferenceBinding topLevelBinding = null; - int topLevelSegments = compoundName.length; - while (--topLevelSegments > 0) { - char[][] topLevelName = new char[topLevelSegments][]; - for (int i = 0; i < topLevelSegments; ++i) { - topLevelName[i] = compoundName[i]; - } - topLevelBinding = le.getType(topLevelName); - if (null != topLevelBinding) { - break; - } - } - if (null == topLevelBinding) { - return null; - } - binding = topLevelBinding; - for (int i = topLevelSegments; null != binding && i < compoundName.length; ++i) { - binding = binding.getMemberType(compoundName[i]); - } - } - if (null == binding) { - return null; - } - if ((binding.tagBits & TagBits.HasMissingType) != 0) { - return null; - } - return new TypeElementImpl(this._env, binding, null); - } - - - @Override - public Origin getOrigin(Element e) { - return Origin.EXPLICIT; - } - - @Override - public Origin getOrigin(AnnotatedConstruct c, AnnotationMirror a) { - return Origin.EXPLICIT; - } - - @Override - public Origin getOrigin(ModuleElement m, ModuleElement.Directive directive) { - return Origin.EXPLICIT; - } - - @Override - public boolean isBridge(ExecutableElement e) { - MethodBinding methodBinding = (MethodBinding) ((ExecutableElementImpl) e)._binding; - return methodBinding.isBridge(); - } - - @Override - public ModuleElement getModuleOf(Element elem) { - if (elem instanceof ModuleElement) { - return (ModuleElement) elem; - } - Element parent = elem.getEnclosingElement(); - while (parent != null) { - if (parent instanceof ModuleElement) { - return (ModuleElement) parent; - } - parent = parent.getEnclosingElement(); - } - return null; - } - - @Override - public ModuleElement getModuleElement(CharSequence name) { - LookupEnvironment lookup = this._env.getLookupEnvironment(); - ModuleBinding binding = lookup.getModule(name.length() == 0 ? ModuleBinding.UNNAMED : name.toString().toCharArray()); - //TODO: Surely there has to be a better way than calling toString().toCharArray()? - if (binding == null) { - return null; - } - return new ModuleElementImpl(this._env, binding); - } - - @Override - public Set getAllModuleElements() { - LookupEnvironment lookup = this._env.getLookupEnvironment(); - HashtableOfModule knownModules = lookup.knownModules; - ModuleBinding[] modules = knownModules.valueTable; - if (modules == null || modules.length == 0) { - return Collections.emptySet(); - } - Set mods = new HashSet<>(modules.length); - for (ModuleBinding moduleBinding : modules) { - if (moduleBinding == null) - continue; - ModuleElement element = (ModuleElement) this._env.getFactory().newElement(moduleBinding); - mods.add(element); - } - mods.add((ModuleElement) this._env.getFactory().newElement(lookup.UnNamedModule)); - return mods; - } - - @Override - public - PackageElement getPackageElement(ModuleElement module, CharSequence name) { - ModuleBinding mBinding = ((ModuleElementImpl) module).binding; - final char[][] compoundName = CharOperation.splitOn('.', name.toString().toCharArray()); - PackageBinding p = null; - if (mBinding != null) { - p = mBinding.getVisiblePackage(compoundName); - } else { - p = this._env.getLookupEnvironment().createPackage(compoundName); - } - if (p == null || !p.isValidBinding()) - return null; - return (PackageElement) this._env.getFactory().newElement(p); - } - @Override - public boolean isAutomaticModule(ModuleElement module) { - ModuleBinding mBinding = ((ModuleElementImpl) module).binding; - return mBinding.isAutomatic(); - } - @Override - public javax.tools.JavaFileObject getFileObjectOf(Element element) { - switch(element.getKind()) { - case INTERFACE: - case CLASS: - case ENUM: - case RECORD: - case ANNOTATION_TYPE: - TypeElementImpl elementImpl = (TypeElementImpl) element; - ReferenceBinding refBinding = (ReferenceBinding) elementImpl._binding; - if (!refBinding.isBinaryBinding()) { - TypeElementImpl outer = (TypeElementImpl) getOutermostTypeElement(element); - refBinding = (ReferenceBinding) outer._binding; - } - return getFileObjectForType(refBinding); - case MODULE: - ModuleElementImpl moduleEl = (ModuleElementImpl) element; - ModuleBinding mBinding = (ModuleBinding) moduleEl._binding; - if (mBinding instanceof SourceModuleBinding) { - SourceModuleBinding sourceModule = (SourceModuleBinding) mBinding; - return getSourceJavaFileObject(sourceModule.scope.referenceContext()); - } else if (mBinding instanceof BinaryModuleBinding) { - BinaryModuleBinding binaryBinding = (BinaryModuleBinding) mBinding; - if (binaryBinding.path != null) { - return new PathFileObject(Path.of(binaryBinding.path), Kind.CLASS, Charset.defaultCharset()); - } - } - break; - case PACKAGE: - PackageElementImpl packEl = (PackageElementImpl) element; - PackageBinding pBinding = (PackageBinding) packEl._binding; - Binding typeOrPackage = pBinding.getTypeOrPackage(TypeConstants.PACKAGE_INFO_NAME, pBinding.enclosingModule, true); - if (typeOrPackage != null) { - return getFileObjectForType((TypeBinding) typeOrPackage); - } - break; - case PARAMETER: - case LOCAL_VARIABLE: - case FIELD: - case RECORD_COMPONENT: - case ENUM_CONSTANT: - case METHOD: - case CONSTRUCTOR: - if (element.getEnclosingElement() != null) { - return getFileObjectOf(element.getEnclosingElement()); - } - break; - default: - break; - } - return null; - } - private JavaFileObject getFileObjectForType(TypeBinding binding) { - if (binding instanceof SourceTypeBinding) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) binding; - ReferenceContext referenceContext = sourceTypeBinding.scope.referenceContext(); - return getSourceJavaFileObject(referenceContext); - } else if(binding instanceof BinaryTypeBinding) { - BinaryTypeBinding binaryBinding = (BinaryTypeBinding) binding; - if (binaryBinding.path != null) { - Path of = Path.of(binaryBinding.path); - if (Files.exists(of)) { - return new PathFileObject(of, Kind.CLASS, Charset.defaultCharset()); - } - } - } - return null; - } - - @SuppressWarnings("resource") // fileManager is not created, must not be closed - private JavaFileObject getSourceJavaFileObject(ReferenceContext referenceContext) { - JavaFileManager fileManager = this._env.getFileManager(); - if (fileManager instanceof EclipseFileManager) { - EclipseFileManager eFileManager = (EclipseFileManager) fileManager; - CompilationResult compilationResult = referenceContext.compilationResult(); - String fileName = new String(compilationResult.fileName); - File f = new File(fileName); - if (f.exists()) { - Iterator objects = eFileManager.getJavaFileObjects(f).iterator(); - if (objects.hasNext()) { - return objects.next(); - } - } - } else { - throw new UnsupportedOperationException(); - } - return null; - } - @Override - public boolean isCanonicalConstructor(ExecutableElement e) { - MethodBinding methodBinding = (MethodBinding) ((ExecutableElementImpl) e)._binding; - return methodBinding.isCanonicalConstructor(); - } - @Override - public boolean isCompactConstructor(ExecutableElement e) { - MethodBinding methodBinding = (MethodBinding) ((ExecutableElementImpl) e)._binding; - return methodBinding.isCompactConstructor(); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java deleted file mode 100644 index a9667e1..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeElement.java +++ /dev/null @@ -1,164 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; -import javax.lang.model.element.NestingKind; -import javax.lang.model.element.TypeParameterElement; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; - -/** - * Element corresponding to the Error type mirror - */ -public class ErrorTypeElement extends TypeElementImpl { - - ErrorTypeElement(BaseProcessingEnvImpl env, ReferenceBinding binding) { - super(env, binding, null); - } - /* (non-Javadoc) - * @see javax.lang.model.element.TypeElement#getInterfaces() - */ - @Override - public List getInterfaces() { - return Collections.emptyList(); - } - - /* (non-Javadoc) - * @see javax.lang.model.element.TypeElement#getNestingKind() - */ - @Override - public NestingKind getNestingKind() { - return NestingKind.TOP_LEVEL; - } - - /* (non-Javadoc) - * @see javax.lang.model.element.TypeElement#getQualifiedName() - */ - @Override - public Name getQualifiedName() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - char[] qName; - if (binding.isMemberType()) { - qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.'); - CharOperation.replace(qName, '$', '.'); - } else { - qName = CharOperation.concatWith(binding.compoundName, '.'); - } - return new NameImpl(qName); - } - - /* (non-Javadoc) - * @see javax.lang.model.element.TypeElement#getSuperclass() - */ - @Override - public TypeMirror getSuperclass() { - return this._env.getFactory().getNoType(TypeKind.NONE); - } - - /* (non-Javadoc) - * @see javax.lang.model.element.TypeElement#getTypeParameters() - */ - @Override - public List getTypeParameters() { - return Collections.emptyList(); - } - - /* (non-Javadoc) - * @see javax.lang.model.element.Element#asType() - */ - @Override - public TypeMirror asType() { - return this._env.getFactory().getErrorType((ReferenceBinding) this._binding); - } - - /* (non-Javadoc) - * @see javax.lang.model.element.Element#getAnnotation(java.lang.Class) - */ - @Override - public
A getAnnotation(Class annotationType) { - return null; - } - - /* (non-Javadoc) - * @see javax.lang.model.element.Element#getAnnotationMirrors() - */ - @Override - public List getAnnotationMirrors() { - return Collections.emptyList(); - } - - @SuppressWarnings("unchecked") - @Override - public A[] getAnnotationsByType(Class annotationType) { - return (A[]) Array.newInstance(annotationType, 0); - } - - - /* (non-Javadoc) - * @see javax.lang.model.element.Element#getEnclosedElements() - */ - @Override - public List getEnclosedElements() { - return Collections.emptyList(); - } - - /* (non-Javadoc) - * @see javax.lang.model.element.Element#getEnclosingElement() - */ - @Override - public Element getEnclosingElement() { - return this._env.getFactory().newPackageElement(this._env.getLookupEnvironment().defaultPackage); - } - - /* (non-Javadoc) - * @see javax.lang.model.element.Element#getKind() - */ - @Override - public ElementKind getKind() { - return ElementKind.CLASS; - } - - /* (non-Javadoc) - * @see javax.lang.model.element.Element#getModifiers() - */ - @Override - public Set getModifiers() { - return Collections.emptySet(); - } - - /* (non-Javadoc) - * @see javax.lang.model.element.Element#getSimpleName() - */ - @Override - public Name getSimpleName() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - return new NameImpl(binding.sourceName()); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java deleted file mode 100644 index cb4ab93..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ErrorTypeImpl.java +++ /dev/null @@ -1,122 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.type.ErrorType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVisitor; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -/** - * Implementation of the {@link ErrorType} interface. - */ -public class ErrorTypeImpl extends DeclaredTypeImpl implements ErrorType { - - /* package */ ErrorTypeImpl(BaseProcessingEnvImpl env, ReferenceBinding binding) { - super(env, binding); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.DeclaredType#asElement() - */ - @Override - public Element asElement() { - return this._env.getFactory().newElement(this._binding); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.DeclaredType#getEnclosingType() - */ - @Override - public TypeMirror getEnclosingType() { - return NoTypeImpl.NO_TYPE_NONE; - } - - @Override - public List getTypeArguments() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - if (binding.isParameterizedType()) { - ParameterizedTypeBinding ptb = (ParameterizedTypeBinding)this._binding; - TypeBinding[] arguments = ptb.arguments; - int length = arguments == null ? 0 : arguments.length; - if (length == 0) return Collections.emptyList(); - List args = new ArrayList<>(length); - for (TypeBinding arg : arguments) { - args.add(this._env.getFactory().newTypeMirror(arg)); - } - return Collections.unmodifiableList(args); - } - if (binding.isGenericType()) { - TypeVariableBinding[] typeVariables = binding.typeVariables(); - List args = new ArrayList<>(typeVariables.length); - for (TypeBinding arg : typeVariables) { - args.add(this._env.getFactory().newTypeMirror(arg)); - } - return Collections.unmodifiableList(args); - } - return Collections.emptyList(); - } - - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object) - */ - @Override - public R accept(TypeVisitor v, P p) { - return v.visitError(this, p); - } - - @Override - public List getAnnotationMirrors() { - return Factory.EMPTY_ANNOTATION_MIRRORS; - } - - @Override - public A getAnnotation(Class annotationType) { - return null; - } - - @SuppressWarnings("unchecked") - @Override - public A[] getAnnotationsByType(Class annotationType) { - return (A[]) Array.newInstance(annotationType, 0); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#getKind() - */ - @Override - public TypeKind getKind() { - return TypeKind.ERROR; - } - - @Override - public String toString() { - return new String(this._binding.readableName()); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java deleted file mode 100644 index b1d6c01..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ExecutableElementImpl.java +++ /dev/null @@ -1,333 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2015 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Jesper Steen Moller - Bug 412150 [1.8] [compiler] Enable reflected parameter names during annotation processing - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ElementVisitor; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.TypeParameterElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeMirror; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; -import org.eclipse.jdt.internal.compiler.ast.Argument; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationHolder; -import org.eclipse.jdt.internal.compiler.lookup.AptBinaryLocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -public class ExecutableElementImpl extends ElementImpl implements - ExecutableElement { - - private Name _name = null; - - /* package */ ExecutableElementImpl(BaseProcessingEnvImpl env, MethodBinding binding) { - super(env, binding); - } - - @Override - public R accept(ElementVisitor v, P p) - { - return v.visitExecutable(this, p); - } - - @Override - protected AnnotationBinding[] getAnnotationBindings() - { - return ((MethodBinding)this._binding).getAnnotations(); - } - - @Override - public AnnotationValue getDefaultValue() { - MethodBinding binding = (MethodBinding)this._binding; - Object defaultValue = binding.getDefaultValue(); - if (defaultValue != null) return new AnnotationMemberValue(this._env, defaultValue, binding); - return null; - } - - @Override - public List getEnclosedElements() { - return Collections.emptyList(); - } - - @Override - public Element getEnclosingElement() { - MethodBinding binding = (MethodBinding)this._binding; - if (null == binding.declaringClass) { - return null; - } - return this._env.getFactory().newElement(binding.declaringClass); - } - - @Override - public String getFileName() { - ReferenceBinding dc = ((MethodBinding)this._binding).declaringClass; - char[] name = dc.getFileName(); - if (name == null) - return null; - return new String(name); - } - - @Override - public ElementKind getKind() { - MethodBinding binding = (MethodBinding)this._binding; - if (binding.isConstructor()) { - return ElementKind.CONSTRUCTOR; - } - else if (CharOperation.equals(binding.selector, TypeConstants.CLINIT)) { - return ElementKind.STATIC_INIT; - } - else if (CharOperation.equals(binding.selector, TypeConstants.INIT)) { - return ElementKind.INSTANCE_INIT; - } - else { - return ElementKind.METHOD; - } - } - - @Override - public Set getModifiers() { - MethodBinding binding = (MethodBinding)this._binding; - return Factory.getModifiers(binding.modifiers, getKind()); - } - - @Override - PackageElement getPackage() - { - MethodBinding binding = (MethodBinding)this._binding; - if (null == binding.declaringClass) { - return null; - } - return this._env.getFactory().newPackageElement(binding.declaringClass.fPackage); - } - - @Override - public List getParameters() { - MethodBinding binding = (MethodBinding)this._binding; - int length = binding.parameters == null ? 0 : binding.parameters.length; - if (0 != length) { - AbstractMethodDeclaration methodDeclaration = binding.sourceMethod(); - List params = new ArrayList<>(length); - if (methodDeclaration != null) { - for (Argument argument : methodDeclaration.arguments) { - VariableElement param = new VariableElementImpl(this._env, argument.binding); - params.add(param); - } - } else { - // binary method - AnnotationBinding[][] parameterAnnotationBindings = null; - AnnotationHolder annotationHolder = binding.declaringClass.retrieveAnnotationHolder(binding, false); - if (annotationHolder != null) { - parameterAnnotationBindings = annotationHolder.getParameterAnnotations(); - } - // we need to filter the synthetic arguments - int i = 0; - for (TypeBinding typeBinding : binding.parameters) { - char name[] = binding.parameterNames.length > i ? binding.parameterNames[i] : null; - if (name == null) { - StringBuilder builder = new StringBuilder("arg");//$NON-NLS-1$ - builder.append(i); - name = String.valueOf(builder).toCharArray(); - } - VariableElement param = new VariableElementImpl(this._env, - new AptBinaryLocalVariableBinding( - name, - typeBinding, - 0, - parameterAnnotationBindings != null ? parameterAnnotationBindings[i] : null, - binding)); - params.add(param); - i++; - } - } - return Collections.unmodifiableList(params); - } - return Collections.emptyList(); - } - - @Override - public TypeMirror getReturnType() { - MethodBinding binding = (MethodBinding)this._binding; - if (binding.returnType == null) { - return null; - } - else return this._env.getFactory().newTypeMirror(binding.returnType); - } - - @Override - public Name getSimpleName() { - MethodBinding binding = (MethodBinding)this._binding; - if (this._name == null) { - this._name = new NameImpl(binding.selector); - } - return this._name; - } - - @Override - public List getThrownTypes() { - MethodBinding binding = (MethodBinding)this._binding; - if (binding.thrownExceptions.length == 0) { - return Collections.emptyList(); - } - List list = new ArrayList<>(binding.thrownExceptions.length); - for (ReferenceBinding exception : binding.thrownExceptions) { - list.add(this._env.getFactory().newTypeMirror(exception)); - } - return list; - } - - @Override - public List getTypeParameters() { - MethodBinding binding = (MethodBinding)this._binding; - TypeVariableBinding[] variables = binding.typeVariables(); - if (variables.length == 0) { - return Collections.emptyList(); - } - List params = new ArrayList<>(variables.length); - for (TypeVariableBinding variable : variables) { - params.add(this._env.getFactory().newTypeParameterElement(variable, this)); - } - return Collections.unmodifiableList(params); - } - - @Override - public boolean hides(Element hidden) - { - if (!(hidden instanceof ExecutableElementImpl)) { - return false; - } - MethodBinding hiderBinding = (MethodBinding)this._binding; - MethodBinding hiddenBinding = (MethodBinding)((ExecutableElementImpl)hidden)._binding; - if (hiderBinding == hiddenBinding) { - return false; - } - if (hiddenBinding.isPrivate()) { - return false; - } - // See JLS 8.4.8: hiding only applies to static methods - if (!hiderBinding.isStatic() || !hiddenBinding.isStatic()) { - return false; - } - // check names - if (!CharOperation.equals(hiddenBinding.selector, hiderBinding.selector)) { - return false; - } - // check parameters - if (!this._env.getLookupEnvironment().methodVerifier().isMethodSubsignature(hiderBinding, hiddenBinding)) { - return false; - } - return null != hiderBinding.declaringClass.findSuperTypeOriginatingFrom(hiddenBinding.declaringClass); - } - - @Override - public boolean isVarArgs() { - return ((MethodBinding) this._binding).isVarargs(); - } - - /** - * Return true if this method overrides {@code overridden} in the context of {@code type}. For - * instance, consider - *
-	 *   interface A { void f(); }
-	 *   class B { void f() {} }
-	 *   class C extends B implements I { }
-	 * 
- * In the context of B, B.f() does not override A.f(); they are unrelated. But in the context of - * C, B.f() does override A.f(). That is, the copy of B.f() that C inherits overrides A.f(). - * This is equivalent to considering two questions: first, does C inherit B.f(); if so, does - * the inherited C.f() override A.f(). If B.f() were private, for instance, then in the context - * of C it would still not override A.f(). - * - *

see jls3 8.4.8 Inheritance, Overriding, and Hiding - *

see jls3 9.4.1 Inheritance and Overriding - * @see javax.lang.model.util.Elements#overrides(ExecutableElement, ExecutableElement, TypeElement) - */ - public boolean overrides(ExecutableElement overridden, TypeElement type) - { - MethodBinding overriddenBinding = (MethodBinding)((ExecutableElementImpl) overridden)._binding; - ReferenceBinding overriderContext = (ReferenceBinding)((TypeElementImpl)type)._binding; - if ((MethodBinding)this._binding == overriddenBinding - || overriddenBinding.isStatic() - || overriddenBinding.isPrivate() - || ((MethodBinding)this._binding).isStatic()) { - return false; - } - char[] selector = ((MethodBinding)this._binding).selector; - if (!CharOperation.equals(selector, overriddenBinding.selector)) - return false; - - // Construct a binding to the equivalent of this (the overrider) as it would be inherited by 'type'. - // Can only do this if 'type' is descended from the overrider. - // Second clause of the AND is required to match a peculiar javac behavior. - if (null == overriderContext.findSuperTypeOriginatingFrom(((MethodBinding)this._binding).declaringClass) && - null == ((MethodBinding)this._binding).declaringClass.findSuperTypeOriginatingFrom(overriderContext)) { - return false; - } - MethodBinding overriderBinding = new MethodBinding((MethodBinding)this._binding, overriderContext); - if (overriderBinding.isPrivate()) { - // a private method can never override another method. The other method would either be - // private itself, in which case it would not be visible; or this would be a restriction - // of access, which is a compile-time error. - return false; - } - - TypeBinding match = overriderBinding.declaringClass.findSuperTypeOriginatingFrom(overriddenBinding.declaringClass); - if (!(match instanceof ReferenceBinding)) return false; - - org.eclipse.jdt.internal.compiler.lookup.MethodBinding[] superMethods = ((ReferenceBinding)match).getMethods(selector); - LookupEnvironment lookupEnvironment = this._env.getLookupEnvironment(); - if (lookupEnvironment == null) return false; - MethodVerifier methodVerifier = lookupEnvironment.methodVerifier(); - for (int i = 0, length = superMethods.length; i < length; i++) { - if (superMethods[i].original() == overriddenBinding) { - return methodVerifier.doesMethodOverride(overriderBinding, superMethods[i]); - } - } - return false; - } - - @Override - public TypeMirror getReceiverType() { - return this._env.getFactory().getReceiverType((MethodBinding) this._binding); - } - - @Override - public boolean isDefault() { - if (this._binding != null) { - return ((MethodBinding)this._binding).isDefaultMethod(); - } - return false; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java deleted file mode 100644 index 4beec43..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ExecutableTypeImpl.java +++ /dev/null @@ -1,139 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.lang.model.type.ExecutableType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVariable; -import javax.lang.model.type.TypeVisitor; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -/** - * Implementation of the ExecutableType - */ -public class ExecutableTypeImpl extends TypeMirrorImpl implements ExecutableType { - - ExecutableTypeImpl(BaseProcessingEnvImpl env, MethodBinding binding) { - super(env, binding); - } - /* (non-Javadoc) - * @see javax.lang.model.type.ExecutableType#getParameterTypes() - */ - @Override - public List getParameterTypes() { - MethodBinding binding = (MethodBinding) this._binding; - TypeBinding[] parameters = binding.parameters; - int length = parameters.length; - boolean isEnumConstructor = binding.isConstructor() - && binding.declaringClass.isEnum() - && binding.declaringClass.isBinaryBinding() - && ((binding.modifiers & ExtraCompilerModifiers.AccGenericSignature) == 0); - if (isEnumConstructor) { - ArrayList list = new ArrayList<>(); - for (int i = 0; i < length; i++) { - list.add(this._env.getFactory().newTypeMirror(parameters[i])); - } - return Collections.unmodifiableList(list); - } - if (length != 0) { - ArrayList list = new ArrayList<>(); - for (TypeBinding typeBinding : parameters) { - list.add(this._env.getFactory().newTypeMirror(typeBinding)); - } - return Collections.unmodifiableList(list); - } - return Collections.emptyList(); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.ExecutableType#getReturnType() - */ - @Override - public TypeMirror getReturnType() { - return this._env.getFactory().newTypeMirror(((MethodBinding) this._binding).returnType); - } - - @Override - protected AnnotationBinding[] getAnnotationBindings() { - return ((MethodBinding) this._binding).returnType.getTypeAnnotations(); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.ExecutableType#getThrownTypes() - */ - @Override - public List getThrownTypes() { - ArrayList list = new ArrayList<>(); - ReferenceBinding[] thrownExceptions = ((MethodBinding) this._binding).thrownExceptions; - if (thrownExceptions.length != 0) { - for (ReferenceBinding referenceBinding : thrownExceptions) { - list.add(this._env.getFactory().newTypeMirror(referenceBinding)); - } - } - return Collections.unmodifiableList(list); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.ExecutableType#getTypeVariables() - */ - @Override - public List getTypeVariables() { - ArrayList list = new ArrayList<>(); - TypeVariableBinding[] typeVariables = ((MethodBinding) this._binding).typeVariables(); - if (typeVariables.length != 0) { - for (TypeVariableBinding typeVariableBinding : typeVariables) { - list.add((TypeVariable) this._env.getFactory().newTypeMirror(typeVariableBinding)); - } - } - return Collections.unmodifiableList(list); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object) - */ - @Override - public R accept(TypeVisitor v, P p) { - return v.visitExecutable(this, p); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#getKind() - */ - @Override - public TypeKind getKind() { - return TypeKind.EXECUTABLE; - } - - @Override - public TypeMirror getReceiverType() { - return this._env.getFactory().getReceiverType((MethodBinding) this._binding); - } - @Override - public String toString() { - return new String(((MethodBinding) this._binding).returnType.readableName()); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/Factory.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/Factory.java deleted file mode 100644 index b42b2d9..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/Factory.java +++ /dev/null @@ -1,921 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2023 BEA Systems, Inc. and others - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * IBM Corporation - fix for 342598 - * IBM Corporation - Java 8 support - * het@google.com - Bug 427943 - The method org.eclipse.jdt.internal.compiler.apt.model.Factory.getPrimitiveType does not throw IllegalArgumentException - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeParameterElement; -import javax.lang.model.type.ErrorType; -import javax.lang.model.type.NoType; -import javax.lang.model.type.NullType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -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.lookup.VariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; - -/** - * Creates javax.lang.model wrappers around JDT internal compiler bindings. - */ -public class Factory { - - // using auto-boxing to take advantage of caching, if any. - // the dummy value picked here falls within the caching range. - public static final Byte DUMMY_BYTE = 0; - public static final Character DUMMY_CHAR = '0'; - public static final Double DUMMY_DOUBLE = 0d; - public static final Float DUMMY_FLOAT = 0f; - public static final Integer DUMMY_INTEGER = 0; - public static final Long DUMMY_LONG = 0l; - public static final Short DUMMY_SHORT = 0; - - private final BaseProcessingEnvImpl _env; - public static List EMPTY_ANNOTATION_MIRRORS = Collections.emptyList(); - - /** - * This object should only be constructed by the BaseProcessingEnvImpl. - */ - public Factory(BaseProcessingEnvImpl env) { - this._env = env; - } - - /** - * Convert an array of compiler annotation bindings into a list of AnnotationMirror - * @return a non-null, possibly empty, unmodifiable list. - */ - public List getAnnotationMirrors(AnnotationBinding[] annotations) { - if (null == annotations || 0 == annotations.length) { - return Collections.emptyList(); - } - List list = new ArrayList<>(annotations.length); - for (AnnotationBinding annotation : annotations) { - if (annotation == null) continue; - list.add(newAnnotationMirror(annotation)); - } - return Collections.unmodifiableList(list); - } - - @SuppressWarnings("unchecked") // for the cast to A - public A[] getAnnotationsByType(AnnotationBinding[] annoInstances, Class annotationClass) { - A[] result = getAnnotations(annoInstances, annotationClass, false); - return result == null ? (A[]) Array.newInstance(annotationClass, 0) : result; - } - - - public A getAnnotation(AnnotationBinding[] annoInstances, Class annotationClass) { - A[] result = getAnnotations(annoInstances, annotationClass, true); - return result == null ? null : result[0]; - } - - @SuppressWarnings("unchecked") // for cast of newProxyInstance() to A - private A[] getAnnotations(AnnotationBinding[] annoInstances, Class annotationClass, boolean justTheFirst) { - if(annoInstances == null || annoInstances.length == 0 || annotationClass == null ) - return null; - - String annoTypeName = annotationClass.getName(); - if(annoTypeName == null ) return null; - - List list = new ArrayList<>(annoInstances.length); - for(AnnotationBinding annoInstance : annoInstances) { - if (annoInstance == null) - continue; - - AnnotationMirrorImpl annoMirror = createAnnotationMirror(annoTypeName, annoInstance); - if (annoMirror != null) { - list.add((A)Proxy.newProxyInstance(annotationClass.getClassLoader(), new Class[]{ annotationClass }, annoMirror)); - if (justTheFirst) break; - } - } - A [] result = (A[]) Array.newInstance(annotationClass, list.size()); - return list.size() > 0 ? (A[]) list.toArray(result) : null; - } - - private AnnotationMirrorImpl createAnnotationMirror(String annoTypeName, AnnotationBinding annoInstance) { - ReferenceBinding binding = annoInstance.getAnnotationType(); - if (binding != null && binding.isAnnotationType() ) { - char[] qName; - if (binding.isMemberType()) { - annoTypeName = annoTypeName.replace('$', '.'); - qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.'); - CharOperation.replace(qName, '$', '.'); - } else { - qName = CharOperation.concatWith(binding.compoundName, '.'); - } - if(annoTypeName.equals(new String(qName)) ){ - return (AnnotationMirrorImpl)this._env.getFactory().newAnnotationMirror(annoInstance); - } - } - return null; - } - - private static void appendModifier(Set result, int modifiers, int modifierConstant, Modifier modifier) { - if ((modifiers & modifierConstant) != 0) { - result.add(modifier); - } - } - - private static void decodeModifiers(Set result, int modifiers, int[] checkBits) { - if (checkBits == null) return; - for (int i = 0, max = checkBits.length; i < max; i++) { - switch(checkBits[i]) { - case ClassFileConstants.AccPublic : - appendModifier(result, modifiers, checkBits[i], Modifier.PUBLIC); - break; - case ClassFileConstants.AccProtected: - appendModifier(result, modifiers, checkBits[i], Modifier.PROTECTED); - break; - case ClassFileConstants.AccPrivate : - appendModifier(result, modifiers, checkBits[i], Modifier.PRIVATE); - break; - case ClassFileConstants.AccAbstract : - appendModifier(result, modifiers, checkBits[i], Modifier.ABSTRACT); - break; - case ExtraCompilerModifiers.AccDefaultMethod : - try { - appendModifier(result, modifiers, checkBits[i], Modifier.valueOf("DEFAULT")); //$NON-NLS-1$ - } catch(IllegalArgumentException iae) { - // Don't have JDK 1.8, just ignore and proceed. - } - break; - case ClassFileConstants.AccStatic : - appendModifier(result, modifiers, checkBits[i], Modifier.STATIC); - break; - case ClassFileConstants.AccFinal : - appendModifier(result, modifiers, checkBits[i], Modifier.FINAL); - break; - case ClassFileConstants.AccSynchronized : - appendModifier(result, modifiers, checkBits[i], Modifier.SYNCHRONIZED); - break; - case ClassFileConstants.AccNative : - appendModifier(result, modifiers, checkBits[i], Modifier.NATIVE); - break; - case ClassFileConstants.AccStrictfp : - appendModifier(result, modifiers, checkBits[i], Modifier.STRICTFP); - break; - case ClassFileConstants.AccTransient : - appendModifier(result, modifiers, checkBits[i], Modifier.TRANSIENT); - break; - case ClassFileConstants.AccVolatile : - appendModifier(result, modifiers, checkBits[i], Modifier.VOLATILE); - break; - case ExtraCompilerModifiers.AccNonSealed : - try { - appendModifier(result, modifiers, checkBits[i], Modifier.valueOf("NON_SEALED")); //$NON-NLS-1$ - } catch(IllegalArgumentException iae) { - // Don't have JDK 15, just ignore and proceed. - } - break; - case ExtraCompilerModifiers.AccSealed : - try { - appendModifier(result, modifiers, checkBits[i], Modifier.valueOf("SEALED")); //$NON-NLS-1$ - } catch(IllegalArgumentException iae) { - // Don't have JDK 15, just ignore and proceed. - } - break; - } - } - } - - public static Object getMatchingDummyValue(final Class expectedType){ - if( expectedType.isPrimitive() ){ - if(expectedType == boolean.class) - return Boolean.FALSE; - else if( expectedType == byte.class ) - return DUMMY_BYTE; - else if( expectedType == char.class ) - return DUMMY_CHAR; - else if( expectedType == double.class) - return DUMMY_DOUBLE; - else if( expectedType == float.class ) - return DUMMY_FLOAT; - else if( expectedType == int.class ) - return DUMMY_INTEGER; - else if( expectedType == long.class ) - return DUMMY_LONG; - else if(expectedType == short.class) - return DUMMY_SHORT; - else // expectedType == void.class. can this happen? - return DUMMY_INTEGER; // anything would work - } - else - return null; - } - - public TypeMirror getReceiverType(MethodBinding binding) { - if (binding != null) { - if (binding.receiver != null) { - return this._env.getFactory().newTypeMirror(binding.receiver); - } - if (binding.declaringClass != null) { - if (!binding.isStatic() && (!binding.isConstructor() || binding.declaringClass.isMemberType())) { - return this._env.getFactory().newTypeMirror(binding.declaringClass); - } - } - } - return NoTypeImpl.NO_TYPE_NONE; - } - - public static Set getModifiers(int modifiers, ElementKind kind) { - return getModifiers(modifiers, kind, false); - } - /** - * Convert from the JDT's ClassFileConstants flags to the Modifier enum. - */ - public static Set getModifiers(int modifiers, ElementKind kind, boolean isFromBinary) - { - EnumSet result = EnumSet.noneOf(Modifier.class); - switch(kind) { - case CONSTRUCTOR : - case METHOD : - // modifiers for methods - decodeModifiers(result, modifiers, new int[] { - ClassFileConstants.AccPublic, - ClassFileConstants.AccProtected, - ClassFileConstants.AccPrivate, - ClassFileConstants.AccAbstract, - ClassFileConstants.AccStatic, - ClassFileConstants.AccFinal, - ClassFileConstants.AccSynchronized, - ClassFileConstants.AccNative, - ClassFileConstants.AccStrictfp, - ExtraCompilerModifiers.AccDefaultMethod - }); - break; - case FIELD : - case ENUM_CONSTANT : - // for fields - decodeModifiers(result, modifiers, new int[] { - ClassFileConstants.AccPublic, - ClassFileConstants.AccProtected, - ClassFileConstants.AccPrivate, - ClassFileConstants.AccStatic, - ClassFileConstants.AccFinal, - ClassFileConstants.AccTransient, - ClassFileConstants.AccVolatile - }); - break; - case ENUM : - if (isFromBinary) { - decodeModifiers(result, modifiers, new int[] { - ClassFileConstants.AccPublic, - ClassFileConstants.AccProtected, - ClassFileConstants.AccFinal, - ClassFileConstants.AccPrivate, - ClassFileConstants.AccAbstract, - ClassFileConstants.AccStatic, - ClassFileConstants.AccStrictfp, - ExtraCompilerModifiers.AccSealed, - }); - } else { - // enum from source cannot be explicitly abstract - decodeModifiers(result, modifiers, new int[] { - ClassFileConstants.AccPublic, - ClassFileConstants.AccProtected, - ClassFileConstants.AccFinal, - ClassFileConstants.AccPrivate, - ClassFileConstants.AccStatic, - ClassFileConstants.AccStrictfp, - ExtraCompilerModifiers.AccSealed, - }); - } - break; - case ANNOTATION_TYPE : - case INTERFACE : - case CLASS : - case RECORD : - // for type - decodeModifiers(result, modifiers, new int[] { - ClassFileConstants.AccPublic, - ClassFileConstants.AccProtected, - ClassFileConstants.AccAbstract, - ClassFileConstants.AccFinal, - ClassFileConstants.AccPrivate, - ClassFileConstants.AccStatic, - ClassFileConstants.AccStrictfp, - ExtraCompilerModifiers.AccSealed, - ExtraCompilerModifiers.AccNonSealed - }); - break; - case MODULE : - decodeModifiers(result, modifiers, new int[] { - ClassFileConstants.ACC_OPEN, - ClassFileConstants.ACC_TRANSITIVE - }); - break; - default: - break; - } - return Collections.unmodifiableSet(result); - } - - public AnnotationMirror newAnnotationMirror(AnnotationBinding binding) - { - return new AnnotationMirrorImpl(this._env, binding); - } - - /** - * Create a new element that knows what kind it is even if the binding is unresolved. - */ - public Element newElement(Binding binding, ElementKind kindHint) { - if (binding == null) - return null; - switch (binding.kind()) { - case Binding.FIELD: - case Binding.LOCAL: - case Binding.RECORD_COMPONENT: - case Binding.VARIABLE: - return new VariableElementImpl(this._env, (VariableBinding) binding); - case Binding.TYPE: - case Binding.GENERIC_TYPE: - ReferenceBinding referenceBinding = (ReferenceBinding)binding; - if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0) { - return new ErrorTypeElement(this._env, referenceBinding); - } - if (CharOperation.equals(referenceBinding.sourceName, TypeConstants.PACKAGE_INFO_NAME)) { - return newPackageElement(referenceBinding.fPackage); - } - return new TypeElementImpl(this._env, referenceBinding, kindHint); - case Binding.METHOD: - return new ExecutableElementImpl(this._env, (MethodBinding)binding); - case Binding.RAW_TYPE: - case Binding.PARAMETERIZED_TYPE: - return new TypeElementImpl(this._env, ((ParameterizedTypeBinding)binding).genericType(), kindHint); - case Binding.PACKAGE: - return newPackageElement((PackageBinding)binding); - case Binding.TYPE_PARAMETER: - return new TypeParameterElementImpl(this._env, (TypeVariableBinding)binding); - // TODO: fill in the rest of these - case Binding.MODULE: - return new ModuleElementImpl(this._env, (ModuleBinding) binding); - case Binding.IMPORT: - case Binding.ARRAY_TYPE: - case Binding.BASE_TYPE: - case Binding.WILDCARD_TYPE: - case Binding.INTERSECTION_TYPE: - throw new UnsupportedOperationException("NYI: binding type " + binding.kind()); //$NON-NLS-1$ - } - return null; - } - - public Element newElement(Binding binding) { - return newElement(binding, null); - } - - /** - * Convenience method - equivalent to {@code (PackageElement)Factory.newElement(binding)} - */ - public PackageElement newPackageElement(PackageBinding binding) - { - if (binding != null && binding.enclosingModule != null) { - binding = binding.getIncarnation(binding.enclosingModule); - } - if (binding == null) { - return null; - } - return new PackageElementImpl(this._env, binding); - } - - public NullType getNullType() { - return NoTypeImpl.NULL_TYPE; - } - - public NoType getNoType(TypeKind kind) - { - switch (kind) { - case NONE: - return NoTypeImpl.NO_TYPE_NONE; - case VOID: - return NoTypeImpl.NO_TYPE_VOID; - case PACKAGE: - return NoTypeImpl.NO_TYPE_PACKAGE; - case MODULE: - return new NoTypeImpl(kind); - default: - throw new IllegalArgumentException(); - } - } - - /** - * Get a type mirror object representing the specified primitive type kind. - * @throws IllegalArgumentException if a non-primitive TypeKind is requested - */ - public PrimitiveTypeImpl getPrimitiveType(TypeKind kind) - { - switch (kind) { - case BOOLEAN: - return PrimitiveTypeImpl.BOOLEAN; - case BYTE: - return PrimitiveTypeImpl.BYTE; - case CHAR: - return PrimitiveTypeImpl.CHAR; - case DOUBLE: - return PrimitiveTypeImpl.DOUBLE; - case FLOAT: - return PrimitiveTypeImpl.FLOAT; - case INT: - return PrimitiveTypeImpl.INT; - case LONG: - return PrimitiveTypeImpl.LONG; - case SHORT: - return PrimitiveTypeImpl.SHORT; - default: - throw new IllegalArgumentException(); - } - } - - public PrimitiveTypeImpl getPrimitiveType(BaseTypeBinding binding) { - AnnotationBinding[] annotations = binding.getTypeAnnotations(); - if (annotations == null || annotations.length == 0) { - return getPrimitiveType(PrimitiveTypeImpl.getKind(binding)); - } - return new PrimitiveTypeImpl(this._env, binding); - } - - /** - * Given a binding of uncertain type, try to create the right sort of TypeMirror for it. - */ - public TypeMirror newTypeMirror(Binding binding) { - switch (binding.kind()) { - case Binding.FIELD: - case Binding.LOCAL: - case Binding.RECORD_COMPONENT: - case Binding.VARIABLE: - // For variables, return the type of the variable - return newTypeMirror(((VariableBinding)binding).type); - - case Binding.PACKAGE: - return getNoType(TypeKind.PACKAGE); - - case Binding.IMPORT: - throw new UnsupportedOperationException("NYI: import type " + binding.kind()); //$NON-NLS-1$ - - case Binding.METHOD: - return new ExecutableTypeImpl(this._env, (MethodBinding) binding); - - case Binding.TYPE: - case Binding.RAW_TYPE: - case Binding.GENERIC_TYPE: - case Binding.PARAMETERIZED_TYPE: - ReferenceBinding referenceBinding = (ReferenceBinding) binding; - if ((referenceBinding.tagBits & TagBits.HasMissingType) != 0) { - return getErrorType(referenceBinding); - } - return new DeclaredTypeImpl(this._env, (ReferenceBinding)binding); - - case Binding.ARRAY_TYPE: - return new ArrayTypeImpl(this._env, (ArrayBinding)binding); - - case Binding.BASE_TYPE: - BaseTypeBinding btb = (BaseTypeBinding)binding; - switch (btb.id) { - case TypeIds.T_void: - return getNoType(TypeKind.VOID); - case TypeIds.T_null: - return getNullType(); - default: - return getPrimitiveType(btb); - } - - case Binding.WILDCARD_TYPE: - case Binding.INTERSECTION_TYPE: // TODO compatible, but shouldn't it really be an intersection type? - return new WildcardTypeImpl(this._env, (WildcardBinding) binding); - - case Binding.TYPE_PARAMETER: - return new TypeVariableImpl(this._env, (TypeVariableBinding) binding); - case Binding.MODULE: - return getNoType(TypeKind.MODULE); - } - return null; - } - - /** - * @param declaringElement the class, method, etc. that is parameterized by this parameter. - */ - public TypeParameterElement newTypeParameterElement(TypeVariableBinding variable, Element declaringElement) - { - return new TypeParameterElementImpl(this._env, variable, declaringElement); - } - - public ErrorType getErrorType(ReferenceBinding binding) { - return new ErrorTypeImpl(this._env, binding); - } - - /** - * This method is derived from code in org.eclipse.jdt.apt.core. - * - * This method is designed to be invoked by the invocation handler and anywhere that requires - * a AnnotationValue (AnnotationMirror member values and default values from annotation member). - * - * Regardless of the path, there are common primitive type conversion that needs to take place. - * The type conversions respect the type widening and narrowing rules from JLS 5.1.2 and 5.1.2. - * - * The only question remains is what is the type of the return value when the type conversion fails? - * When avoidReflectException is set to true - * Return false if the expected type is boolean - * Return numeric 0 for all numeric primitive types and '0' for char - * - * Otherwise: - * Return the value unchanged. - * - * In the invocation handler case: - * The value returned by {@link java.lang.reflect.InvocationHandler#invoke} - * will be converted into the expected type by the {@link java.lang.reflect.Proxy}. - * If the value and the expected type does not agree, and the value is not null, - * a ClassCastException will be thrown. A NullPointerException will result if the - * expected type is a primitive type and the value is null. - * This behavior causes annotation processors a lot of pain and the decision is - * to not throw such unchecked exception. In the case where a ClassCastException or - * NullPointerException will be thrown return some dummy value. Otherwise, return - * the original value. - * Chosen dummy values: - * Return false if the expected type is boolean - * Return numeric 0 for all numeric primitive types and '0' for char - * - * This behavior is triggered by setting avoidReflectException to true - * - * Note: the new behavior deviates from what's documented in - * {@link java.lang.reflect.InvocationHandler#invoke} and also deviates from - * Sun's implementation. - * - * @param value the current value from the annotation instance. - * @param expectedType the expected type of the value. - */ - public static Object performNecessaryPrimitiveTypeConversion( - final Class expectedType, - final Object value, - final boolean avoidReflectException) - { - assert expectedType.isPrimitive() : "expectedType is not a primitive type: " + expectedType.getName(); //$NON-NLS-1$ - if( value == null) - return avoidReflectException ? getMatchingDummyValue(expectedType) : null; - // apply widening conversion based on JLS 5.1.2 and 5.1.3 - final String typeName = expectedType.getName(); - final char expectedTypeChar = typeName.charAt(0); - final int nameLen = typeName.length(); - // widening byte -> short, int, long, float or double - // narrowing byte -> char - if( value instanceof Byte ) - { - final byte b = ((Byte)value).byteValue(); - switch( expectedTypeChar ) - { - case 'b': - if(nameLen == 4) // byte - return value; // exact match. - else - return avoidReflectException ? Boolean.FALSE : value; - case 'c': - return Character.valueOf((char) b); // narrowing. - case 'd': - return Double.valueOf(b); // widening. - case 'f': - return Float.valueOf(b); // widening. - case 'i': - return Integer.valueOf(b); // widening. - case 'l': - return Long.valueOf(b); // widening. - case 's': - return Short.valueOf(b); // widening. - default: - throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ - } - } - // widening short -> int, long, float, or double - // narrowing short -> byte or char - else if( value instanceof Short ) - { - final short s = ((Short)value).shortValue(); - switch( expectedTypeChar ) - { - case 'b': - if(nameLen == 4) // byte - return Byte.valueOf((byte) s); // narrowing. - else - return avoidReflectException ? Boolean.FALSE : value; // completely wrong. - case 'c': - return Character.valueOf((char) s); // narrowing. - case 'd': - return Double.valueOf(s); // widening. - case 'f': - return Float.valueOf(s); // widening. - case 'i': - return Integer.valueOf(s); // widening. - case 'l': - return Long.valueOf(s); // widening. - case 's': - return value; // exact match - default: - throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ - } - } - // widening char -> int, long, float, or double - // narrowing char -> byte or short - else if( value instanceof Character ) - { - final char c = ((Character)value).charValue(); - switch( expectedTypeChar ) - { - case 'b': - if(nameLen == 4) // byte - return Byte.valueOf((byte) c); // narrowing. - else - return avoidReflectException ? Boolean.FALSE : value; // completely wrong. - case 'c': - return value; // exact match - case 'd': - return Double.valueOf(c); // widening. - case 'f': - return Float.valueOf(c); // widening. - case 'i': - return Integer.valueOf(c); // widening. - case 'l': - return Long.valueOf(c); // widening. - case 's': - return Short.valueOf((short) c); // narrowing. - default: - throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ - } - } - - // widening int -> long, float, or double - // narrowing int -> byte, short, or char - else if( value instanceof Integer ) - { - final int i = ((Integer)value).intValue(); - switch( expectedTypeChar ) - { - case 'b': - if(nameLen == 4) // byte - return Byte.valueOf((byte) i); // narrowing. - else - return avoidReflectException ? Boolean.FALSE : value; // completely wrong. - case 'c': - return Character.valueOf((char) i); // narrowing - case 'd': - return Double.valueOf(i); // widening. - case 'f': - return Float.valueOf(i); // widening. - case 'i': - return value; // exact match - case 'l': - return Long.valueOf(i); // widening. - case 's': - return Short.valueOf((short) i); // narrowing. - default: - throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ - } - } - // widening long -> float or double - else if( value instanceof Long ) - { - final long l = ((Long)value).longValue(); - switch( expectedTypeChar ) - { - case 'b': // both byte and boolean - case 'c': - case 'i': - case 's': - // completely wrong. - return avoidReflectException ? getMatchingDummyValue(expectedType) : value; - case 'd': - return Double.valueOf(l); // widening. - case 'f': - return Float.valueOf(l); // widening. - case 'l': - return value; // exact match. - - default: - throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ - } - } - - // widening float -> double - else if( value instanceof Float ) - { - final float f = ((Float)value).floatValue(); - switch( expectedTypeChar ) - { - case 'b': // both byte and boolean - case 'c': - case 'i': - case 's': - case 'l': - // completely wrong. - return avoidReflectException ? getMatchingDummyValue(expectedType) : value; - case 'd': - return Double.valueOf(f); // widening. - case 'f': - return value; // exact match. - default: - throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ - } - } - else if( value instanceof Double ){ - if(expectedTypeChar == 'd' ) - return value; // exact match - else{ - return avoidReflectException ? getMatchingDummyValue(expectedType) : value; // completely wrong. - } - } - else if( value instanceof Boolean ){ - if( expectedTypeChar == 'b' && nameLen == 7) // "boolean".length() == 7 - return value; - else - return avoidReflectException ? getMatchingDummyValue(expectedType) : value; // completely wrong. - } - else // can't convert - return avoidReflectException ? getMatchingDummyValue(expectedType) : value; - } - - /** - * Set an element of an array to the appropriate dummy value type - */ - public static void setArrayMatchingDummyValue(Object array, int i, Class expectedLeafType) - { - if (boolean.class.equals(expectedLeafType)) { - Array.setBoolean(array, i, false); - } - else if (byte.class.equals(expectedLeafType)) { - Array.setByte(array, i, DUMMY_BYTE); - } - else if (char.class.equals(expectedLeafType)) { - Array.setChar(array, i, DUMMY_CHAR); - } - else if (double.class.equals(expectedLeafType)) { - Array.setDouble(array, i, DUMMY_DOUBLE); - } - else if (float.class.equals(expectedLeafType)) { - Array.setFloat(array, i, DUMMY_FLOAT); - } - else if (int.class.equals(expectedLeafType)) { - Array.setInt(array, i, DUMMY_INTEGER); - } - else if (long.class.equals(expectedLeafType)) { - Array.setLong(array, i, DUMMY_LONG); - } - else if (short.class.equals(expectedLeafType)) { - Array.setShort(array, i, DUMMY_SHORT); - } - else { - Array.set(array, i, null); - } - } - - /* Wrap repeating annotations into their container, return an array of bindings. - Incoming array is not modified. The resulting array may be null but will not contain null - entries. - */ - public static AnnotationBinding [] getPackedAnnotationBindings(AnnotationBinding [] annotations) { - - int length = annotations == null ? 0 : annotations.length; - if (length == 0) - return annotations; - - AnnotationBinding[] repackagedBindings = annotations; // only replicate if repackaging. - for (int i = 0; i < length; i++) { - AnnotationBinding annotation = repackagedBindings[i]; - if (annotation == null) continue; - ReferenceBinding annotationType = annotation.getAnnotationType(); - if (!annotationType.isRepeatableAnnotationType()) - continue; - ReferenceBinding containerType = annotationType.containerAnnotationType(); - if (containerType == null) - continue; // FUBAR. - MethodBinding [] values = containerType.getMethods(TypeConstants.VALUE); - if (values == null || values.length != 1) - continue; // FUBAR. - MethodBinding value = values[0]; - if (value.returnType == null || value.returnType.dimensions() != 1 || TypeBinding.notEquals(value.returnType.leafComponentType(), annotationType)) - continue; // FUBAR - - // We have a kosher repeatable annotation with a kosher containing type. See if actually repeats. - List containees = null; - for (int j = i + 1; j < length; j++) { - AnnotationBinding otherAnnotation = repackagedBindings[j]; - if (otherAnnotation == null) continue; - if (otherAnnotation.getAnnotationType() == annotationType) { //$IDENTITY-COMPARISON$ - if (repackagedBindings == annotations) - System.arraycopy(repackagedBindings, 0, repackagedBindings = new AnnotationBinding[length], 0, length); - repackagedBindings[j] = null; // so it is not double packed. - if (containees == null) { - containees = new ArrayList<>(); - containees.add(annotation); - } - containees.add(otherAnnotation); - } - } - if (containees != null) { - ElementValuePair [] elementValuePairs = new ElementValuePair [] { new ElementValuePair(TypeConstants.VALUE, containees.toArray(), value) }; - repackagedBindings[i] = new AnnotationBinding(containerType, elementValuePairs); - } - } - - int finalTally = 0; - for (int i = 0; i < length; i++) { - if (repackagedBindings[i] != null) - finalTally++; - } - - if (repackagedBindings == annotations && finalTally == length) { - return annotations; - } - - annotations = new AnnotationBinding [finalTally]; - for (int i = 0, j = 0; i < length; i++) { - if (repackagedBindings[i] != null) - annotations[j++] = repackagedBindings[i]; - } - return annotations; - } - - /* Unwrap container annotations into the repeated annotations, return an array of bindings that includes the container and the containees. - */ - public static AnnotationBinding [] getUnpackedAnnotationBindings(AnnotationBinding [] annotations) { - - int length = annotations == null ? 0 : annotations.length; - if (length == 0) - return annotations; - - List unpackedAnnotations = new ArrayList<>(); - for (int i = 0; i < length; i++) { - AnnotationBinding annotation = annotations[i]; - if (annotation == null) continue; - unpackedAnnotations.add(annotation); - ReferenceBinding annotationType = annotation.getAnnotationType(); - - MethodBinding [] values = annotationType.getMethods(TypeConstants.VALUE); - if (values == null || values.length != 1) - continue; - MethodBinding value = values[0]; - - if (value.returnType.dimensions() != 1) - continue; - - TypeBinding containeeType = value.returnType.leafComponentType(); - if (containeeType == null || !containeeType.isAnnotationType() || !containeeType.isRepeatableAnnotationType()) - continue; - - if (containeeType.containerAnnotationType() != annotationType) //$IDENTITY-COMPARISON$ - continue; - - // We have a kosher container: unwrap the contained annotations. - ElementValuePair [] elementValuePairs = annotation.getElementValuePairs(); - for (ElementValuePair elementValuePair : elementValuePairs) { - if (CharOperation.equals(elementValuePair.getName(), TypeConstants.VALUE)) { - Object [] containees = (Object []) elementValuePair.getValue(); - for (Object object : containees) { - unpackedAnnotations.add((AnnotationBinding) object); - } - break; - } - } - } - return unpackedAnnotations.toArray(new AnnotationBinding [unpackedAnnotations.size()]); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java deleted file mode 100644 index dc0327a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/IElementInfo.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -/** - * Additional information available for Elements that are implemented - * within the Eclipse APT framework. - * @see javax.lang.model.element.Element - * @since 3.3 - */ -public interface IElementInfo { - /** - * Get the project-relative path to the source file that contains this element. - * If the element is a PackageElement, the "source file" is package-info.java. - * If the element is not recognized or does not exist in the project for some - * reason, returns null. - * @return the project-relative path, or null. - */ - public String getFileName(); -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java deleted file mode 100644 index da73d91..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/ModuleElementImpl.java +++ /dev/null @@ -1,369 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ElementVisitor; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.ModuleElement; -import javax.lang.model.element.Name; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -public class ModuleElementImpl extends ElementImpl implements ModuleElement { - - ModuleBinding binding; - private List directives; - private static List EMPTY_DIRECTIVES = Collections.emptyList(); - - /** - * In general, clients should call - * {@link Factory#newElement(org.eclipse.jdt.internal.compiler.lookup.Binding)} - * to create new instances. - */ - ModuleElementImpl(BaseProcessingEnvImpl env, ModuleBinding binding) { - super(env, binding); - this.binding = binding; - } - - @Override - public ElementKind getKind() { - return ElementKind.MODULE; - } - - @Override - public Set getModifiers() { - int modifiers = this.binding.modifiers; - return Factory.getModifiers(modifiers, getKind(), false); - } - - @Override - public Name getQualifiedName() { - return new NameImpl(this.binding.moduleName); - } - - @Override - public Name getSimpleName() { - char[] simpleName = this.binding.moduleName; - for(int i = simpleName.length-1;i>=0;i--) { - if(simpleName[i] == '.') { - simpleName = Arrays.copyOfRange(simpleName, i+1, simpleName.length); - break; - } - } - return new NameImpl(simpleName); - } - - @Override - public List getEnclosedElements() { - ModuleBinding module = this.binding; - Set unique = new HashSet<>(); - for (PlainPackageBinding p : module.declaredPackages.values()) { - if (!p.hasCompilationUnit(true)) - continue; - unique.add(p); - } - if (module.isUnnamed()) { - PlainPackageBinding def = module.environment.defaultPackage; - // FIXME: Does it have any impact for unnamed modules - default package combo? - if (def != null && def.hasCompilationUnit(true)) { - unique.add(def); - } - } else { - for (PlainPackageBinding pBinding : this.binding.getExports()) { - unique.add(pBinding); - } - for (PlainPackageBinding pBinding : this.binding.getOpens()) { - unique.add(pBinding); - } - } - List enclosed = new ArrayList<>(unique.size()); - for (PlainPackageBinding p : unique) { - PackageElement pElement = (PackageElement) this._env.getFactory().newElement(p); - enclosed.add(pElement); - } - return Collections.unmodifiableList(enclosed); - } - - @Override - public boolean isOpen() { - return (this.binding.modifiers & ClassFileConstants.ACC_OPEN) != 0; - } - - @Override - public boolean isUnnamed() { - return this.binding.moduleName.length == 0; - } - - @Override - public Element getEnclosingElement() { - // As of today, modules have no enclosing element - return null; - } - - @Override - public List getDirectives() { - if (isUnnamed()) { - return EMPTY_DIRECTIVES; - } - if (this.directives == null) - this.directives = new ArrayList<>(); - - PlainPackageBinding[] packs = this.binding.getExports(); - for (PlainPackageBinding exp : packs) { - this.directives.add(new ExportsDirectiveImpl(exp)); - } - Set transitive = new HashSet<>(); - for (ModuleBinding mBinding : this.binding.getRequiresTransitive()) { - transitive.add(mBinding); - } - ModuleBinding[] required = this.binding.getRequires(); - for (ModuleBinding mBinding : required) { - if (transitive.contains(mBinding)) { - this.directives.add(new RequiresDirectiveImpl(mBinding, true)); - } else { - this.directives.add(new RequiresDirectiveImpl(mBinding, false)); - } - } - - TypeBinding[] tBindings = this.binding.getUses(); - for (TypeBinding tBinding : tBindings) { - this.directives.add(new UsesDirectiveImpl(tBinding)); - } - tBindings = this.binding.getServices(); - for (TypeBinding tBinding : tBindings) { - this.directives.add(new ProvidesDirectiveImpl(tBinding)); - } - packs = this.binding.getOpens(); - for (PlainPackageBinding exp : packs) { - this.directives.add(new OpensDirectiveImpl(exp)); - } - return this.directives; - } - - @Override - public R accept(ElementVisitor visitor, P param) { - return visitor.visitModule(this, param); - } - @Override - protected AnnotationBinding[] getAnnotationBindings() { - return ((ModuleBinding) this._binding).getAnnotations(); - } - - abstract class PackageDirectiveImpl { - final PackageBinding binding1; - List targets; - - PackageDirectiveImpl(PackageBinding pBinding) { - this.binding1 = pBinding; - } - - public PackageElement getPackage() { - return ModuleElementImpl.this._env.getFactory().newPackageElement(this.binding1); - } - - public List getTargetModules(String[] restrictions) { - if(this.targets != null) { - return this.targets; - } - if (restrictions.length == 0) { - return (this.targets = null); - } - List targets1 = new ArrayList<>(restrictions.length); - for (String string : restrictions) { - ModuleBinding target = ModuleElementImpl.this.binding.environment.getModule(string.toCharArray()); - if (target != null) { - ModuleElement element = ((ModuleElement) ModuleElementImpl.this._env.getFactory().newElement(target)); - targets1.add(element); - } - } - return (this.targets = Collections.unmodifiableList(targets1)); - } - } - - class ExportsDirectiveImpl extends PackageDirectiveImpl implements ModuleElement.ExportsDirective { - - ExportsDirectiveImpl(PackageBinding pBinding) { - super(pBinding); - } - - @Override - public R accept(DirectiveVisitor visitor, P param) { - return visitor.visitExports(this, param); - } - - @Override - public javax.lang.model.element.ModuleElement.DirectiveKind getKind() { - return DirectiveKind.EXPORTS; - } - - @Override - public PackageElement getPackage() { - return ModuleElementImpl.this._env.getFactory().newPackageElement(this.binding1); - } - @Override - public List getTargetModules() { - if(this.targets != null) { - return this.targets; - } - return getTargetModules(ModuleElementImpl.this.binding.getExportRestrictions(this.binding1)); - } - - } - - class RequiresDirectiveImpl implements ModuleElement.RequiresDirective { - ModuleBinding dependency; - boolean transitive; - - RequiresDirectiveImpl(ModuleBinding dependency, boolean transitive) { - this.dependency = dependency; - this.transitive = transitive; - } - - @Override - public R accept(DirectiveVisitor visitor, P param) { - return visitor.visitRequires(this, param); - } - - @Override - public javax.lang.model.element.ModuleElement.DirectiveKind getKind() { - return DirectiveKind.REQUIRES; - } - - @Override - public ModuleElement getDependency() { - return (ModuleElement) ModuleElementImpl.this._env.getFactory().newElement(this.dependency, ElementKind.MODULE); - } - - @Override - public boolean isStatic() { - // TODO: Yet to see this in ModuleBinding. Check again. - return false; - } - - @Override - public boolean isTransitive() { - return this.transitive; - } - } - - class OpensDirectiveImpl extends PackageDirectiveImpl implements ModuleElement.OpensDirective { - - OpensDirectiveImpl(PackageBinding pBinding) { - super(pBinding); - } - - @Override - public R accept(DirectiveVisitor visitor, P param) { - return visitor.visitOpens(this, param); - } - - @Override - public javax.lang.model.element.ModuleElement.DirectiveKind getKind() { - return DirectiveKind.OPENS; - } - @Override - public List getTargetModules() { - if(this.targets != null) { - return this.targets; - } - return getTargetModules(ModuleElementImpl.this.binding.getOpenRestrictions(this.binding1)); - } - } - - class UsesDirectiveImpl implements ModuleElement.UsesDirective { - final TypeBinding binding1; - - UsesDirectiveImpl(TypeBinding binding) { - this.binding1 = binding; - } - - @Override - public R accept(DirectiveVisitor visitor, P param) { - return visitor.visitUses(this, param); - } - - @Override - public DirectiveKind getKind() { - return DirectiveKind.USES; - } - - @Override - public TypeElement getService() { - return (TypeElement) ModuleElementImpl.this._env.getFactory().newElement(this.binding1); - } - - } - - class ProvidesDirectiveImpl implements ModuleElement.ProvidesDirective { - - TypeBinding service; - public List implementations; - - ProvidesDirectiveImpl(TypeBinding service) { - this.service = service; - } - - @Override - public R accept(DirectiveVisitor visitor, P param) { - return visitor.visitProvides(this, param); - } - - @Override - public DirectiveKind getKind() { - return DirectiveKind.PROVIDES; - } - - @Override - public List getImplementations() { - if (this.implementations != null) - return this.implementations; - - TypeBinding[] implementations2 = ModuleElementImpl.this.binding.getImplementations(this.service); - if (implementations2.length == 0) { - return (this.implementations = Collections.emptyList()); - } - - List list = new ArrayList<>(implementations2.length); - Factory factory = ModuleElementImpl.this._env.getFactory(); - for (TypeBinding type: implementations2) { - TypeElement element = (TypeElement) factory.newElement(type); - list.add(element); - } - return Collections.unmodifiableList(list); - } - - @Override - public TypeElement getService() { - return (TypeElement) ModuleElementImpl.this._env.getFactory().newElement(this.service); - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java deleted file mode 100644 index 0839a4c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/NameImpl.java +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2007 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import javax.lang.model.element.Name; - -/** - * A String-based implementation of the type used to return strings in javax.lang.model. - */ -public class NameImpl implements Name { - - private final String _name; - - /** nullary constructor is prohibited */ - @SuppressWarnings("unused") - private NameImpl() - { - this._name = null; - } - - public NameImpl(CharSequence cs) - { - this._name = cs.toString(); - } - - public NameImpl(char[] chars) - { - this._name = String.valueOf(chars); - } - - /* (non-Javadoc) - * @see javax.lang.model.element.Name#contentEquals(java.lang.CharSequence) - */ - @Override - public boolean contentEquals(CharSequence cs) { - return this._name.equals(cs.toString()); - } - - /* (non-Javadoc) - * @see java.lang.CharSequence#charAt(int) - */ - @Override - public char charAt(int index) { - return this._name.charAt(index); - } - - /* (non-Javadoc) - * @see java.lang.CharSequence#length() - */ - @Override - public int length() { - return this._name.length(); - } - - /* (non-Javadoc) - * @see java.lang.CharSequence#subSequence(int, int) - */ - @Override - public CharSequence subSequence(int start, int end) { - return this._name.subSequence(start, end); - } - - @Override - public String toString() { - return this._name; - } - - @Override - public int hashCode() { - return this._name.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final NameImpl other = (NameImpl) obj; - return this._name.equals(other._name); - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java deleted file mode 100644 index 22294ba..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/NoTypeImpl.java +++ /dev/null @@ -1,116 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2015 BEA Systems, Inc. and others - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * IBM Corporation - Java 8 support - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.util.List; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.type.NoType; -import javax.lang.model.type.NullType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeVisitor; - -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -/** - * An implementation of NoType, which is used to represent certain pseudo-types. - * @see NoType - */ -public class NoTypeImpl extends TypeMirrorImpl implements NoType, NullType -{ - private final TypeKind _kind; - - public static final NoType NO_TYPE_NONE = new NoTypeImpl(TypeKind.NONE); - public static final NoType NO_TYPE_VOID = new NoTypeImpl(TypeKind.VOID, TypeBinding.VOID); - public static final NoType NO_TYPE_PACKAGE = new NoTypeImpl(TypeKind.PACKAGE); - public static final NullType NULL_TYPE = new NoTypeImpl(TypeKind.NULL, TypeBinding.NULL); - public static final Binding NO_TYPE_BINDING = new Binding() { - @Override - public int kind() { - throw new IllegalStateException(); - } - - @Override - public char[] readableName() { - throw new IllegalStateException(); - } - }; - - public NoTypeImpl(TypeKind kind) { - super(null, NO_TYPE_BINDING); - this._kind = kind; - } - public NoTypeImpl(TypeKind kind, Binding binding) { - super(null, binding); - this._kind = kind; - } - - @Override - public R accept(TypeVisitor v, P p) - { - switch(this.getKind()) - { - case NULL : - return v.visitNull(this, p); - default: - return v.visitNoType(this, p); - } - } - - @Override - public TypeKind getKind() - { - return this._kind; - } - - @Override - public String toString() - { - switch (this._kind) { - default: - case NONE: - return "none"; //$NON-NLS-1$ - case NULL: - return "null"; //$NON-NLS-1$ - case VOID: - return "void"; //$NON-NLS-1$ - case PACKAGE: - return "package"; //$NON-NLS-1$ - case MODULE: - return "module"; //$NON-NLS-1$ - } - } - - @Override - public List getAnnotationMirrors() { - return Factory.EMPTY_ANNOTATION_MIRRORS; - } - - @Override - public A getAnnotation(Class annotationType) { - return null; - } - - @Override - @SuppressWarnings("unchecked") - public A[] getAnnotationsByType(Class annotationType) { - return (A[]) Array.newInstance(annotationType, 0); - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java deleted file mode 100644 index 47f5985..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/PackageElementImpl.java +++ /dev/null @@ -1,156 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2017 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ElementVisitor; -import javax.lang.model.element.Name; -import javax.lang.model.element.PackageElement; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.batch.FileSystem; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.env.INameEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; - -/** - * Implementation of PackageElement, which represents a package - */ -public class PackageElementImpl extends ElementImpl implements PackageElement { - - PackageElementImpl(BaseProcessingEnvImpl env, PackageBinding binding) { - super(env, binding); - } - - @Override - public R accept(ElementVisitor v, P p) - { - return v.visitPackage(this, p); - } - - @Override - protected AnnotationBinding[] getAnnotationBindings() - { - PackageBinding packageBinding = (PackageBinding) this._binding; - char[][] compoundName = CharOperation.arrayConcat(packageBinding.compoundName, TypeConstants.PACKAGE_INFO_NAME); - ReferenceBinding type = packageBinding.environment.getType(compoundName); - AnnotationBinding[] annotations = null; - if (type != null && type.isValidBinding()) { - annotations = type.getAnnotations(); - } - return annotations; - } - - @Override - public List getEnclosedElements() { - PackageBinding binding = (PackageBinding)this._binding; - LookupEnvironment environment = binding.environment; - char[][][] typeNames = null; - INameEnvironment nameEnvironment = binding.environment.nameEnvironment; - if (nameEnvironment instanceof FileSystem) { - typeNames = ((FileSystem) nameEnvironment).findTypeNames(binding.compoundName); - } - HashSet set = new HashSet<>(); - Set types = new HashSet<>(); - if (typeNames != null) { - for (char[][] typeName : typeNames) { - if (typeName == null) continue; - ReferenceBinding type = environment.getType(typeName); - if (type == null || type.isMemberType()) continue; - if (type.isValidBinding()) { - Element newElement = this._env.getFactory().newElement(type); - if (newElement.getKind() != ElementKind.PACKAGE) { - set.add(newElement); - types.add(type); - } - } - } - } - if (binding.knownTypes != null) { - ReferenceBinding[] knownTypes = binding.knownTypes.valueTable; - for (ReferenceBinding referenceBinding : knownTypes) { - if (referenceBinding != null && referenceBinding.isValidBinding() && referenceBinding.enclosingType() == null) { - if (!types.contains(referenceBinding)) { - Element newElement = this._env.getFactory().newElement(referenceBinding); - if (newElement.getKind() != ElementKind.PACKAGE) - set.add(newElement); - } - } - } - } - ArrayList list = new ArrayList<>(set.size()); - list.addAll(set); - return Collections.unmodifiableList(list); - } - - @Override - public Element getEnclosingElement() { - if (super._env.getCompiler().options.sourceLevel < ClassFileConstants.JDK9) { - return null; - } - PackageBinding pBinding = (PackageBinding) this._binding; - ModuleBinding module = pBinding.enclosingModule; - if (module == null) - return null; - return new ModuleElementImpl(this._env, module); - } - - @Override - public ElementKind getKind() { - return ElementKind.PACKAGE; - } - - @Override - PackageElement getPackage() - { - return this; - } - - @Override - public Name getSimpleName() { - char[][] compoundName = ((PackageBinding)this._binding).compoundName; - int length = compoundName.length; - if (length == 0) { - return new NameImpl(CharOperation.NO_CHAR); - } - return new NameImpl(compoundName[length - 1]); - } - - @Override - public Name getQualifiedName() { - return new NameImpl(CharOperation.concatWith(((PackageBinding)this._binding).compoundName, '.')); - } - - @Override - public boolean isUnnamed() { - PackageBinding binding = (PackageBinding)this._binding; - return binding.compoundName == CharOperation.NO_CHAR_CHAR; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java deleted file mode 100644 index 4de9896..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/PrimitiveTypeImpl.java +++ /dev/null @@ -1,90 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2014 BEA Systems, Inc. and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * IBM Corporation - Java 8 support - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import javax.lang.model.type.PrimitiveType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeVisitor; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -/** - * - * @since 3.3 - */ -public class PrimitiveTypeImpl extends TypeMirrorImpl implements PrimitiveType { - - public final static PrimitiveTypeImpl BOOLEAN = new PrimitiveTypeImpl(TypeBinding.BOOLEAN); - public final static PrimitiveTypeImpl BYTE = new PrimitiveTypeImpl(TypeBinding.BYTE); - public final static PrimitiveTypeImpl CHAR = new PrimitiveTypeImpl(TypeBinding.CHAR); - public final static PrimitiveTypeImpl DOUBLE = new PrimitiveTypeImpl(TypeBinding.DOUBLE); - public final static PrimitiveTypeImpl FLOAT = new PrimitiveTypeImpl(TypeBinding.FLOAT); - public final static PrimitiveTypeImpl INT = new PrimitiveTypeImpl(TypeBinding.INT); - public final static PrimitiveTypeImpl LONG = new PrimitiveTypeImpl(TypeBinding.LONG); - public final static PrimitiveTypeImpl SHORT = new PrimitiveTypeImpl(TypeBinding.SHORT); - - /** - * Clients should call {@link Factory#getPrimitiveType(TypeKind)}, - * rather than creating new objects. - */ - private PrimitiveTypeImpl(BaseTypeBinding binding) { - // Primitive types do not need an environment! - super(null, binding); - } - - PrimitiveTypeImpl(BaseProcessingEnvImpl env, BaseTypeBinding binding) { - // From Java 8, base type bindings can hold annotations and hence need the environment. - super(env, binding); - } - - @Override - public R accept(TypeVisitor v, P p) - { - return v.visitPrimitive(this, p); - } - - @Override - public TypeKind getKind() { - return getKind((BaseTypeBinding)this._binding); - } - - public static TypeKind getKind(BaseTypeBinding binding) { - switch (binding.id) { - case TypeIds.T_boolean: - return TypeKind.BOOLEAN; - case TypeIds.T_byte: - return TypeKind.BYTE; - case TypeIds.T_char: - return TypeKind.CHAR; - case TypeIds.T_double: - return TypeKind.DOUBLE; - case TypeIds.T_float: - return TypeKind.FLOAT; - case TypeIds.T_int: - return TypeKind.INT; - case TypeIds.T_long: - return TypeKind.LONG; - case TypeIds.T_short: - return TypeKind.SHORT; - default: - throw new IllegalArgumentException("BaseTypeBinding of unexpected id " + binding.id); //$NON-NLS-1$ - } - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/RecordComponentElementImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/RecordComponentElementImpl.java deleted file mode 100644 index a86c4df..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/RecordComponentElementImpl.java +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020, 2021 IBM Corporation. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ElementVisitor; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.RecordComponentElement; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; - -public class RecordComponentElementImpl extends VariableElementImpl implements RecordComponentElement { - - protected RecordComponentElementImpl(BaseProcessingEnvImpl env, RecordComponentBinding binding) { - super(env, binding); - } - - @Override - public ElementKind getKind() { - return ElementKind.RECORD_COMPONENT; - } - - @Override - public ExecutableElement getAccessor() { - RecordComponentBinding comp = (RecordComponentBinding) this._binding; - ReferenceBinding binding = comp.declaringRecord; - MethodBinding accessor = binding.getRecordComponentAccessor(comp.name); - if (accessor != null) { - return new ExecutableElementImpl(this._env, accessor); - } - return null; - } - - @Override - public R accept(ElementVisitor visitor, P param) { - return visitor.visitRecordComponent(this, param); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java deleted file mode 100644 index 4212db5..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeElementImpl.java +++ /dev/null @@ -1,395 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Set; - -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ElementVisitor; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; -import javax.lang.model.element.NestingKind; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.RecordComponentElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.TypeParameterElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -public class TypeElementImpl extends ElementImpl implements TypeElement { - - /** - * Compares Element instances possibly returned by - * {@link TypeElement#getEnclosedElements()} based on their source location, if available. - */ - private static final class SourceLocationComparator implements Comparator { - private final IdentityHashMap sourceStartCache = new IdentityHashMap<>(); - - @Override - public int compare(Element o1, Element o2) { - ElementImpl e1 = (ElementImpl) o1; - ElementImpl e2 = (ElementImpl) o2; - - return getSourceStart(e1) - getSourceStart(e2); - } - - private int getSourceStart(ElementImpl e) { - Integer value = this.sourceStartCache.get(e); - - if (value == null) { - value = determineSourceStart(e); - this.sourceStartCache.put(e, value); - } - - return value; - } - - private int determineSourceStart(ElementImpl e) { - switch(e.getKind()) { - case ANNOTATION_TYPE : - case INTERFACE : - case CLASS : - case ENUM : - case RECORD : - TypeElementImpl typeElementImpl = (TypeElementImpl) e; - Binding typeBinding = typeElementImpl._binding; - if (typeBinding instanceof SourceTypeBinding) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) typeBinding; - TypeDeclaration typeDeclaration = (TypeDeclaration) sourceTypeBinding.scope.referenceContext(); - return typeDeclaration.sourceStart; - } - break; - case CONSTRUCTOR : - case METHOD : - ExecutableElementImpl executableElementImpl = (ExecutableElementImpl) e; - Binding binding = executableElementImpl._binding; - if (binding instanceof MethodBinding) { - MethodBinding methodBinding = (MethodBinding) binding; - return methodBinding.sourceStart(); - } - break; - case ENUM_CONSTANT : - case FIELD : - case RECORD_COMPONENT : - VariableElementImpl variableElementImpl = (VariableElementImpl) e; - binding = variableElementImpl._binding; - if (binding instanceof FieldBinding) { - FieldBinding fieldBinding = (FieldBinding) binding; - FieldDeclaration fieldDeclaration = fieldBinding.sourceField(); - if (fieldDeclaration != null) { - return fieldDeclaration.sourceStart; - } - } - break; - default: - break; - } - - return -1; - } - } - - private final ElementKind _kindHint; - - /** - * In general, clients should call {@link Factory#newElement(org.eclipse.jdt.internal.compiler.lookup.Binding)} - * to create new instances. - */ - TypeElementImpl(BaseProcessingEnvImpl env, ReferenceBinding binding, ElementKind kindHint) { - super(env, binding); - this._kindHint = kindHint; - } - - @Override - public R accept(ElementVisitor v, P p) - { - return v.visitType(this, p); - } - - @Override - protected AnnotationBinding[] getAnnotationBindings() - { - return ((ReferenceBinding)this._binding).getAnnotations(); - } - - @Override - public List getEnclosedElements() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - List enclosed = new ArrayList<>(binding.fieldCount() + binding.methods().length + binding.memberTypes().length); - for (MethodBinding method : binding.methods()) { - ExecutableElement executable = new ExecutableElementImpl(this._env, method); - enclosed.add(executable); - } - for (FieldBinding field : binding.fields()) { - // TODO no field should be excluded according to the JLS - if (!field.isSynthetic()) { - VariableElement variable = new VariableElementImpl(this._env, field); - enclosed.add(variable); - } - } - if (binding.isRecord()) { - RecordComponentBinding[] components = binding.components(); - for (RecordComponentBinding comp : components) { - RecordComponentElement rec = new RecordComponentElementImpl(this._env, comp); - enclosed.add(rec); - } - } - for (ReferenceBinding memberType : binding.memberTypes()) { - TypeElement type = new TypeElementImpl(this._env, memberType, null); - enclosed.add(type); - } - Collections.sort(enclosed, new SourceLocationComparator()); - return Collections.unmodifiableList(enclosed); - } - - @Override - public List getRecordComponents() { - if (this._binding instanceof ReferenceBinding) { - ReferenceBinding binding = (ReferenceBinding) this._binding; - List enclosed = new ArrayList<>(); - for (RecordComponentBinding comp : binding.components()) { - RecordComponentElement variable = new RecordComponentElementImpl(this._env, comp); - enclosed.add(variable); - } - Collections.sort(enclosed, new SourceLocationComparator()); - return Collections.unmodifiableList(enclosed); - } - return Collections.emptyList(); - } - - @Override - public List getPermittedSubclasses() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - if (binding.isSealed()) { - List permitted = new ArrayList<>(); - for (ReferenceBinding type : binding.permittedTypes()) { - TypeMirror typeMirror = this._env.getFactory().newTypeMirror(type); - permitted.add(typeMirror); - } - return Collections.unmodifiableList(permitted); - } - return Collections.emptyList(); - } - @Override - public Element getEnclosingElement() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - ReferenceBinding enclosingType = binding.enclosingType(); - if (null == enclosingType) { - // this is a top level type; get its package - return this._env.getFactory().newPackageElement(binding.fPackage); - } - else { - return this._env.getFactory().newElement(binding.enclosingType()); - } - } - - @Override - public String getFileName() { - char[] name = ((ReferenceBinding)this._binding).getFileName(); - if (name == null) - return null; - return new String(name); - } - - @Override - public List getInterfaces() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - if (null == binding.superInterfaces() || binding.superInterfaces().length == 0) { - return Collections.emptyList(); - } - List interfaces = new ArrayList<>(binding.superInterfaces().length); - for (ReferenceBinding interfaceBinding : binding.superInterfaces()) { - TypeMirror interfaceType = this._env.getFactory().newTypeMirror(interfaceBinding); - if (interfaceType.getKind() == TypeKind.ERROR) { - if (this._env.getSourceVersion().compareTo(SourceVersion.RELEASE_6) > 0) { - // for jdk 7 and above, add error types - interfaces.add(interfaceType); - } - } else { - interfaces.add(interfaceType); - } - } - return Collections.unmodifiableList(interfaces); - } - - @Override - public ElementKind getKind() { - if (null != this._kindHint) { - return this._kindHint; - } - ReferenceBinding refBinding = (ReferenceBinding)this._binding; - // The order of these comparisons is important: e.g., enum is subset of class - if (refBinding.isEnum()) { - return ElementKind.ENUM; - } - else if (refBinding.isRecord()) { - return ElementKind.RECORD; - } - else if (refBinding.isAnnotationType()) { - return ElementKind.ANNOTATION_TYPE; - } - else if (refBinding.isInterface()) { - return ElementKind.INTERFACE; - } - else if (refBinding.isClass()) { - return ElementKind.CLASS; - } - else { - throw new IllegalArgumentException("TypeElement " + new String(refBinding.shortReadableName()) + //$NON-NLS-1$ - " has unexpected attributes " + refBinding.modifiers); //$NON-NLS-1$ - } - } - - @Override - public Set getModifiers() - { - ReferenceBinding refBinding = (ReferenceBinding)this._binding; - int modifiers = refBinding.modifiers; - if (refBinding.isInterface() && refBinding.isNestedType()) { - modifiers |= ClassFileConstants.AccStatic; - } - - return Factory.getModifiers(modifiers, getKind(), refBinding.isBinaryBinding()); - } - - @Override - public NestingKind getNestingKind() { - ReferenceBinding refBinding = (ReferenceBinding)this._binding; - if (refBinding.isAnonymousType()) { - return NestingKind.ANONYMOUS; - } else if (refBinding.isLocalType()) { - return NestingKind.LOCAL; - } else if (refBinding.isMemberType()) { - return NestingKind.MEMBER; - } - return NestingKind.TOP_LEVEL; - } - - @Override - PackageElement getPackage() - { - ReferenceBinding binding = (ReferenceBinding)this._binding; - return this._env.getFactory().newPackageElement(binding.fPackage); - } - - @Override - public Name getQualifiedName() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - char[] qName; - if (binding.isMemberType()) { - qName = CharOperation.concatWith(binding.enclosingType().compoundName, binding.sourceName, '.'); - CharOperation.replace(qName, '$', '.'); - } else { - qName = CharOperation.concatWith(binding.compoundName, '.'); - } - return new NameImpl(qName); - } - - /* - * (non-Javadoc) - * @see org.eclipse.jdt.internal.compiler.apt.model.ElementImpl#getSimpleName() - * @return last segment of name, e.g. for pa.pb.X.Y return Y. - */ - @Override - public Name getSimpleName() - { - ReferenceBinding binding = (ReferenceBinding)this._binding; - return new NameImpl(binding.sourceName()); - } - - @Override - public TypeMirror getSuperclass() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - ReferenceBinding superBinding = binding.superclass(); - if (null == superBinding || binding.isInterface()) { - return this._env.getFactory().getNoType(TypeKind.NONE); - } - // superclass of a type must be a DeclaredType - return this._env.getFactory().newTypeMirror(superBinding); - } - - @Override - public List getTypeParameters() { - ReferenceBinding binding = (ReferenceBinding)this._binding; - TypeVariableBinding[] variables = binding.typeVariables(); - if (variables.length == 0) { - return Collections.emptyList(); - } - List params = new ArrayList<>(variables.length); - for (TypeVariableBinding variable : variables) { - params.add(this._env.getFactory().newTypeParameterElement(variable, this)); - } - return Collections.unmodifiableList(params); - } - - @Override - public boolean hides(Element hidden) - { - if (!(hidden instanceof TypeElementImpl)) { - return false; - } - ReferenceBinding hiddenBinding = (ReferenceBinding)((TypeElementImpl)hidden)._binding; - if (hiddenBinding.isPrivate()) { - return false; - } - ReferenceBinding hiderBinding = (ReferenceBinding)this._binding; - if (TypeBinding.equalsEquals(hiddenBinding, hiderBinding)) { - return false; - } - if (!hiddenBinding.isMemberType() || !hiderBinding.isMemberType()) { - return false; - } - if (!CharOperation.equals(hiddenBinding.sourceName, hiderBinding.sourceName)) { - return false; - } - return null != hiderBinding.enclosingType().findSuperTypeOriginatingFrom(hiddenBinding.enclosingType()); - } - - @Override - public String toString() { - ReferenceBinding binding = (ReferenceBinding) this._binding; - char[] concatWith = CharOperation.concatWith(binding.compoundName, '.'); - if (binding.isNestedType()) { - CharOperation.replace(concatWith, '$', '.'); - return new String(concatWith); - } - return new String(concatWith); - - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java deleted file mode 100644 index 9dffc2d..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeMirrorImpl.java +++ /dev/null @@ -1,151 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2014 BEA Systems, Inc. and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * IBM Corporation - Java 8 support - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.util.List; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVisitor; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -/** - * Implementation of a TypeMirror. TypeMirror represents a type, including - * types that have no declaration, such as primitives (int, boolean) and - * types that are specializations of declarations {@code (List)}. - */ -public class TypeMirrorImpl implements TypeMirror { - - // Caution: _env will be NULL for unannotated primitive types (PrimitiveTypeImpl). - protected final BaseProcessingEnvImpl _env; - protected final Binding _binding; - - /* package */ TypeMirrorImpl(BaseProcessingEnvImpl env, Binding binding) { - this._env = env; - this._binding = binding; - } - - /* package */ Binding binding() { - return this._binding; - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object) - */ - @Override - public R accept(TypeVisitor v, P p) { - return v.visit(this, p); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#getKind() - */ - @Override - public TypeKind getKind() { - switch (this._binding.kind()) { - // case Binding.TYPE: - // case Binding.RAW_TYPE: - // case Binding.GENERIC_TYPE: - // case Binding.PARAMETERIZED_TYPE: - // handled by DeclaredTypeImpl, etc. - // case Binding.BASE_TYPE: handled by PrimitiveTypeImpl - // case Binding.METHOD: handled by ExecutableTypeImpl - // case Binding.PACKAGE: handled by NoTypeImpl - // case Binding.WILDCARD_TYPE: handled by WildcardTypeImpl - // case Binding.ARRAY_TYPE: handled by ArrayTypeImpl - // case Binding.TYPE_PARAMETER: handled by TypeVariableImpl - // TODO: fill in the rest of these - case Binding.FIELD: - case Binding.LOCAL: - case Binding.RECORD_COMPONENT: - case Binding.VARIABLE: - case Binding.IMPORT: - throw new IllegalArgumentException("Invalid binding kind: " + this._binding.kind()); //$NON-NLS-1$ - } - return null; - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return new String(this._binding.readableName()); - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((this._binding == null) ? 0 : this._binding.hashCode()); - return result; - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (!(obj instanceof TypeMirrorImpl)) - return false; - final TypeMirrorImpl other = (TypeMirrorImpl) obj; - return this._binding == other._binding; - } - - /* Package any repeating annotations into containers, return others as is. - In the compiler bindings repeating annotations are left in as is, hence - this step. The return value would match what one would expect to see in - a class file. - */ - public final AnnotationBinding [] getPackedAnnotationBindings() { - return Factory.getPackedAnnotationBindings(getAnnotationBindings()); - } - - protected AnnotationBinding[] getAnnotationBindings() { - return ((TypeBinding)this._binding).getTypeAnnotations(); - } - - @Override - public List getAnnotationMirrors() { - return this._env == null ? Factory.EMPTY_ANNOTATION_MIRRORS : - this._env.getFactory().getAnnotationMirrors(getPackedAnnotationBindings()); - } - - @Override - public A getAnnotation(Class annotationType) { - return this._env == null ? null : this._env.getFactory().getAnnotation(getPackedAnnotationBindings(), annotationType); - } - - @SuppressWarnings("unchecked") - @Override - public A[] getAnnotationsByType(Class annotationType) { - if (this._env == null) - return (A[]) Array.newInstance(annotationType, 0); - return this._env.getFactory().getAnnotationsByType(Factory.getUnpackedAnnotationBindings(getPackedAnnotationBindings()), annotationType); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java deleted file mode 100644 index a6502f3..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeParameterElementImpl.java +++ /dev/null @@ -1,220 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2023 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * IBM Corporation - fix for 342470 - * IBM Corporation - fix for 342598 - * IBM Corporation - Java 8 support - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ElementVisitor; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeParameterElement; -import javax.lang.model.type.TypeMirror; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -public class TypeParameterElementImpl extends ElementImpl implements TypeParameterElement -{ - private final Element _declaringElement; - - // Cache the bounds, because they're expensive to compute - private List _bounds = null; - - /* package */ TypeParameterElementImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding, Element declaringElement) { - super(env, binding); - this._declaringElement = declaringElement; - } - - /* package */ TypeParameterElementImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding) { - super(env, binding); - this._declaringElement = this._env.getFactory().newElement(binding.declaringElement); - } - - @Override - public List getBounds() - { - if (null == this._bounds) { - this._bounds = calculateBounds(); - } - return this._bounds; - } - - // This code is drawn from org.eclipse.jdt.core.dom.TypeBinding.getTypeBounds() - private List calculateBounds() { - TypeVariableBinding typeVariableBinding = (TypeVariableBinding)this._binding; - ReferenceBinding varSuperclass = typeVariableBinding.superclass(); - TypeBinding firstClassOrArrayBound = typeVariableBinding.firstBound; - int boundsLength = 0; - boolean isFirstBoundATypeVariable = false; - if (firstClassOrArrayBound != null) { - if (firstClassOrArrayBound.isTypeVariable()) { - isFirstBoundATypeVariable = true; - } - if (TypeBinding.equalsEquals(firstClassOrArrayBound, varSuperclass)) { - boundsLength++; - if (firstClassOrArrayBound.isTypeVariable()) { - isFirstBoundATypeVariable = true; - } - } else if (firstClassOrArrayBound.isArrayType()) { // capture of ? extends/super arrayType - boundsLength++; - } else { - firstClassOrArrayBound = null; - } - } - ReferenceBinding[] superinterfaces = typeVariableBinding.superInterfaces(); - int superinterfacesLength = 0; - if (superinterfaces != null) { - superinterfacesLength = superinterfaces.length; - boundsLength += superinterfacesLength; - } - List typeBounds = new ArrayList<>(boundsLength); - if (boundsLength != 0) { - if (firstClassOrArrayBound != null) { - TypeMirror typeBinding = this._env.getFactory().newTypeMirror(firstClassOrArrayBound); - if (typeBinding == null) { - return Collections.emptyList(); - } - typeBounds.add(typeBinding); - } - // we need to filter out remaining bounds if the first bound is a type variable - if (superinterfaces != null && !isFirstBoundATypeVariable) { - for (int i = 0; i < superinterfacesLength; i++) { - TypeMirror typeBinding = this._env.getFactory().newTypeMirror(superinterfaces[i]); - if (typeBinding == null) { - return Collections.emptyList(); - } - typeBounds.add(typeBinding); - } - } - } else { - // at least we must add java.lang.Object - typeBounds.add(this._env.getFactory().newTypeMirror(this._env.getLookupEnvironment().getType(TypeConstants.JAVA_LANG_OBJECT))); - } - return Collections.unmodifiableList(typeBounds); - } - - @Override - public Element getGenericElement() - { - return this._declaringElement; - } - - @Override - public R accept(ElementVisitor v, P p) - { - return v.visitTypeParameter(this, p); - } - - /* - * (non-Javadoc) - * Java supports annotations on type parameters from JLS8 - * @see javax.lang.model.element.Element#getAnnotationMirrors() - */ - @Override - protected AnnotationBinding[] getAnnotationBindings() - { - return ((TypeVariableBinding)this._binding).getTypeAnnotations(); - } - - private boolean shouldEmulateJavacBug() { - if (this._env.getLookupEnvironment().globalOptions.emulateJavacBug8031744) { - AnnotationBinding [] annotations = getAnnotationBindings(); - for (int i = 0, length = annotations.length; i < length; i++) { - ReferenceBinding firstAnnotationType = annotations[i].getAnnotationType(); - for (int j = i+1; j < length; j++) { - ReferenceBinding secondAnnotationType = annotations[j].getAnnotationType(); - if (firstAnnotationType == secondAnnotationType) //$IDENTITY-COMPARISON$ - return true; - } - } - } - return false; - } - - @Override - public List getAnnotationMirrors() { - if (shouldEmulateJavacBug()) - return Collections.emptyList(); - return super.getAnnotationMirrors(); - } - - @Override - @SuppressWarnings("unchecked") // for the cast to A - public A[] getAnnotationsByType(Class annotationType) { - if (shouldEmulateJavacBug()) - return (A[]) Array.newInstance(annotationType, 0); - return super.getAnnotationsByType(annotationType); - } - - @Override - public A getAnnotation(Class annotationType) { - if (shouldEmulateJavacBug()) - return null; - return super.getAnnotation(annotationType); - } - - /* - * (non-Javadoc) - * Always return an empty list; type parameters do not enclose other elements. - * @see javax.lang.model.element.Element#getEnclosedElements() - */ - @Override - public List getEnclosedElements() - { - return Collections.emptyList(); - } - - /* - * (non-Javadoc) - * Always return null. - * @see javax.lang.model.element.Element#getEnclosingElement() - */ - @Override - public Element getEnclosingElement() - { - return getGenericElement(); - } - - @Override - public ElementKind getKind() - { - return ElementKind.TYPE_PARAMETER; - } - - @Override - PackageElement getPackage() - { - // TODO what is the package of a type parameter? - return null; - } - - @Override - public String toString() { - return new String(this._binding.readableName()); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java deleted file mode 100644 index 46a6d7e..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypeVariableImpl.java +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import javax.lang.model.element.Element; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVariable; -import javax.lang.model.type.TypeVisitor; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -/** - * Implementation of TypeVariable - */ -public class TypeVariableImpl extends TypeMirrorImpl implements TypeVariable { - - TypeVariableImpl(BaseProcessingEnvImpl env, TypeVariableBinding binding) { - super(env, binding); - } - /* (non-Javadoc) - * @see javax.lang.model.type.TypeVariable#asElement() - */ - @Override - public Element asElement() { - return this._env.getFactory().newElement(this._binding); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeVariable#getLowerBound() - */ - @Override - public TypeMirror getLowerBound() { - // TODO might be more complex than this - return this._env.getFactory().getNullType(); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeVariable#getUpperBound() - */ - @Override - public TypeMirror getUpperBound() { - TypeVariableBinding typeVariableBinding = (TypeVariableBinding) this._binding; - TypeBinding firstBound = typeVariableBinding.firstBound; - ReferenceBinding[] superInterfaces = typeVariableBinding.superInterfaces; - if (firstBound == null || superInterfaces.length == 0) { - // no explicit bound - return this._env.getFactory().newTypeMirror(typeVariableBinding.upperBound()); - } - if (superInterfaces.length == 1 && TypeBinding.equalsEquals(superInterfaces[0], firstBound)) { - // only one bound that is an interface - return this._env.getFactory().newTypeMirror(typeVariableBinding.upperBound()); - } - return this._env.getFactory().newTypeMirror(this._binding); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#accept(javax.lang.model.type.TypeVisitor, java.lang.Object) - */ - @Override - public R accept(TypeVisitor v, P p) { - return v.visitTypeVariable(this, p); - } - - @Override - public TypeKind getKind() { - return TypeKind.TYPEVAR; - } - - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java deleted file mode 100644 index 40c26f8..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java +++ /dev/null @@ -1,584 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007 - 2023 BEA Systems, Inc. and others - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Walter Harley - initial API and implementation - * IBM Corporation - fix for 342598, 382590 - * Jean-Marie Henaff (Google) - Bug 481555 - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.ExecutableType; -import javax.lang.model.type.NoType; -import javax.lang.model.type.NullType; -import javax.lang.model.type.PrimitiveType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.WildcardType; -import javax.lang.model.util.Types; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.ast.Wildcard; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; - -/** - * Utilities for working with types (as opposed to elements). - * There is one of these for every ProcessingEnvironment. - */ -public class TypesImpl implements Types { - - private final BaseProcessingEnvImpl _env; - - /* - * The processing env creates and caches a TypesImpl. Other clients should - * not create their own; they should ask the env for it. - */ - public TypesImpl(BaseProcessingEnvImpl env) { - this._env = env; - } - - /* (non-Javadoc) - * @see javax.lang.model.util.Types#asElement(javax.lang.model.type.TypeMirror) - */ - @Override - public Element asElement(TypeMirror t) { - switch(t.getKind()) { - case DECLARED : - case TYPEVAR : - return this._env.getFactory().newElement(((TypeMirrorImpl)t).binding()); - default: - break; - } - return null; - } - - @Override - public TypeMirror asMemberOf(DeclaredType containing, Element element) { - // throw new UnsupportedOperationException("NYI: TypesImpl.asMemberOf(" - // + containing + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$ - // //$NON-NLS-3$ - ElementImpl elementImpl = (ElementImpl) element; - DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing; - ReferenceBinding referenceBinding = (ReferenceBinding) declaredTypeImpl._binding; - TypeMirror typeMirror; - - switch (element.getKind()) { - case CONSTRUCTOR: - case METHOD: - typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() { - @Override - public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) { - MethodBinding methodBinding = ((MethodBinding) memberBinding); - for (MethodBinding method : typeBinding.methods()) { - if (CharOperation.equals(method.selector, methodBinding.selector) - && (method.original() == methodBinding - || method.areParameterErasuresEqual(methodBinding))) { - return TypesImpl.this._env.getFactory().newTypeMirror(method); - } - } - return null; - } - }); - - if (typeMirror != null) { - return typeMirror; - } - break; - case TYPE_PARAMETER: - typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() { - @Override - public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) { - if (typeBinding instanceof ParameterizedTypeBinding) { - TypeVariableBinding variableBinding = ((TypeVariableBinding) memberBinding); - ReferenceBinding binding = ((ParameterizedTypeBinding) typeBinding).genericType(); - if (variableBinding.declaringElement == binding) { // check in advance avoid looking into type parameters unnecessarily. - TypeVariableBinding[] typeVariables = binding.typeVariables(); - TypeBinding[] typeArguments = ((ParameterizedTypeBinding) typeBinding).typeArguments(); - if (typeVariables.length == typeArguments.length) { - for(int i = 0; i < typeVariables.length; i++) { - if (typeVariables[i] == memberBinding) { - return TypesImpl.this._env.getFactory().newTypeMirror(typeArguments[i]); - } - } - } - } - } - return null; - } - }); - - if (typeMirror != null) { - return typeMirror; - } - break; - case FIELD: - case ENUM_CONSTANT: - case RECORD_COMPONENT: - typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() { - @Override - public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) { - VariableBinding variableBinding = (VariableBinding) memberBinding; - for (FieldBinding field : typeBinding.fields()) { - if (CharOperation.equals(field.name, variableBinding.name)) { - return TypesImpl.this._env.getFactory().newTypeMirror(field); - } - } - return null; - } - }); - - if (typeMirror != null) { - return typeMirror; - } - break; - case ENUM: - case ANNOTATION_TYPE: - case INTERFACE: - case CLASS: - case RECORD: - typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() { - @Override - public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) { - ReferenceBinding elementBinding = (ReferenceBinding) memberBinding; - // If referenceBinding is a ParameterizedTypeBinding, this - // will return only ParameterizedTypeBindings - // for member types, even if the member happens to be a - // static nested class. That's probably a bug; - // static nested classes are not parameterized by their - // outer class. - for (ReferenceBinding memberReferenceBinding : typeBinding.memberTypes()) { - if (CharOperation.equals(elementBinding.compoundName, memberReferenceBinding.compoundName)) { - return TypesImpl.this._env.getFactory().newTypeMirror(memberReferenceBinding); - } - } - return null; - } - }); - - if (typeMirror != null) { - return typeMirror; - } - break; - default: - throw new IllegalArgumentException("element " + element + //$NON-NLS-1$ - " has unrecognized element kind " + element.getKind()); //$NON-NLS-1$ - } - throw new IllegalArgumentException("element " + element + //$NON-NLS-1$ - " is not a member of the containing type " + containing + //$NON-NLS-1$ - " nor any of its superclasses"); //$NON-NLS-1$ - } - - private static interface MemberInTypeFinder { - TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding); - } - - private TypeMirror findMemberInHierarchy(ReferenceBinding typeBinding, Binding memberBinding, - MemberInTypeFinder finder) { - TypeMirror result = null; - - if (typeBinding == null) { - return null; - } - - result = finder.find(typeBinding, memberBinding); - if (result != null) { - return result; - } - - result = findMemberInHierarchy(typeBinding.superclass(), memberBinding, finder); - if (result != null) { - return result; - } - - for (ReferenceBinding superInterface : typeBinding.superInterfaces()) { - result = findMemberInHierarchy(superInterface, memberBinding, finder); - if (result != null) { - return result; - } - } - - return null; - } - private void validateRealType(TypeMirror t) { - switch (t.getKind()) { - case EXECUTABLE: - case PACKAGE: - case MODULE: - throw new IllegalArgumentException( - "Executable, package and module are illegal argument for Types.contains(..)"); //$NON-NLS-1$ - default: - break; - } - } - private void validateRealTypes(TypeMirror t1, TypeMirror t2) { - validateRealType(t1); - validateRealType(t2); - } - - @Override - public TypeElement boxedClass(PrimitiveType p) { - PrimitiveTypeImpl primitiveTypeImpl = (PrimitiveTypeImpl) p; - BaseTypeBinding baseTypeBinding = (BaseTypeBinding)primitiveTypeImpl._binding; - TypeBinding boxed = this._env.getLookupEnvironment().computeBoxingType(baseTypeBinding); - return (TypeElement) this._env.getFactory().newElement(boxed); - } - - @Override - public TypeMirror capture(TypeMirror t) { - validateRealType(t); - TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t; - if (typeMirrorImpl._binding instanceof ParameterizedTypeBinding) { - throw new UnsupportedOperationException("NYI: TypesImpl.capture(...)"); //$NON-NLS-1$ - } - return t; - } - - @Override - public boolean contains(TypeMirror t1, TypeMirror t2) { - validateRealTypes(t1, t2); - throw new UnsupportedOperationException("NYI: TypesImpl.contains(" + t1 + ", " + t2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - - @Override - public List directSupertypes(TypeMirror t) { - validateRealType(t); - TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t; - Binding binding = typeMirrorImpl._binding; - if (binding instanceof ReferenceBinding) { - ReferenceBinding referenceBinding = (ReferenceBinding) binding; - ArrayList list = new ArrayList<>(); - ReferenceBinding superclass = referenceBinding.superclass(); - if (superclass != null) { - list.add(this._env.getFactory().newTypeMirror(superclass)); - } - for (ReferenceBinding interfaceBinding : referenceBinding.superInterfaces()) { - list.add(this._env.getFactory().newTypeMirror(interfaceBinding)); - } - return Collections.unmodifiableList(list); - } - return Collections.emptyList(); - } - - @Override - public TypeMirror erasure(TypeMirror t) { - validateRealType(t); - TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t; - Binding binding = typeMirrorImpl._binding; - if (binding instanceof ReferenceBinding) { - TypeBinding type = ((ReferenceBinding) binding).erasure(); - if (type.isGenericType()) { - type = this._env.getLookupEnvironment().convertToRawType(type, false); - } - return this._env.getFactory().newTypeMirror(type); - } - if (binding instanceof ArrayBinding) { - TypeBinding typeBinding = (TypeBinding) binding; - TypeBinding leafType = typeBinding.leafComponentType().erasure(); - if (leafType.isGenericType()) { - leafType = this._env.getLookupEnvironment().convertToRawType(leafType, false); - } - return this._env.getFactory().newTypeMirror( - this._env.getLookupEnvironment().createArrayType(leafType, - typeBinding.dimensions())); - } - return t; - } - - @Override - public ArrayType getArrayType(TypeMirror componentType) { - TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) componentType; - TypeBinding typeBinding = (TypeBinding) typeMirrorImpl._binding; - return (ArrayType) this._env.getFactory().newTypeMirror( - this._env.getLookupEnvironment().createArrayType( - typeBinding.leafComponentType(), - typeBinding.dimensions() + 1)); - } - - /* - * (non-Javadoc) - * Create a type instance by parameterizing a type element. If the element is a member type, - * its container won't be parameterized (if it needs to be, you would need to use the form of - * getDeclaredType that takes a container TypeMirror). If typeArgs is empty, and typeElem - * is not generic, then you should use TypeElem.asType(). If typeArgs is empty and typeElem - * is generic, this method will create the raw type. - */ - @Override - public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) { - int typeArgsLength = typeArgs.length; - TypeElementImpl typeElementImpl = (TypeElementImpl) typeElem; - ReferenceBinding elementBinding = (ReferenceBinding) typeElementImpl._binding; - TypeVariableBinding[] typeVariables = elementBinding.typeVariables(); - int typeVariablesLength = typeVariables.length; - if (typeArgsLength == 0) { - if (elementBinding.isGenericType()) { - // per javadoc, - return (DeclaredType) this._env.getFactory().newTypeMirror(this._env.getLookupEnvironment().createRawType(elementBinding, null)); - } - return (DeclaredType)typeElem.asType(); - } else if (typeArgsLength != typeVariablesLength) { - throw new IllegalArgumentException("Number of typeArguments doesn't match the number of formal parameters of typeElem"); //$NON-NLS-1$ - } - TypeBinding[] typeArguments = new TypeBinding[typeArgsLength]; - for (int i = 0; i < typeArgsLength; i++) { - TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) typeArgs[i]; - Binding binding = typeMirrorImpl._binding; - if (!(binding instanceof TypeBinding)) { - throw new IllegalArgumentException("Invalid type argument: " + typeMirrorImpl); //$NON-NLS-1$ - } - typeArguments[i] = (TypeBinding) binding; - } - - ReferenceBinding enclosing = elementBinding.enclosingType(); - if (enclosing != null) { - enclosing = this._env.getLookupEnvironment().createRawType(enclosing, null); - } - - return (DeclaredType) this._env.getFactory().newTypeMirror( - this._env.getLookupEnvironment().createParameterizedType(elementBinding, typeArguments, enclosing)); - } - - /* (non-Javadoc) - * Create a specific type from a member element. The containing type can be parameterized, - * e.g. Outer.Inner, but it cannot be generic, i.e., Outer.Inner. It only makes - * sense to use this method when the member element is parameterized by its container; so, - * for example, it makes sense for an inner class but not for a static member class. - * Otherwise you should just use getDeclaredType(TypeElement, TypeMirror ...), if you need - * to specify type arguments, or TypeElement.asType() directly, if not. - */ - @Override - public DeclaredType getDeclaredType(DeclaredType containing, TypeElement typeElem, - TypeMirror... typeArgs) { - int typeArgsLength = typeArgs.length; - TypeElementImpl typeElementImpl = (TypeElementImpl) typeElem; - ReferenceBinding elementBinding = (ReferenceBinding) typeElementImpl._binding; - TypeVariableBinding[] typeVariables = elementBinding.typeVariables(); - int typeVariablesLength = typeVariables.length; - DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing; - ReferenceBinding enclosingType = (ReferenceBinding) declaredTypeImpl._binding; - if (typeArgsLength == 0) { - if (elementBinding.isGenericType()) { - // e.g., Outer.Inner but T is not specified - // Per javadoc on interface, must return the raw type Outer.Inner - return (DeclaredType) this._env.getFactory().newTypeMirror( - this._env.getLookupEnvironment().createRawType(elementBinding, enclosingType)); - } else { - // e.g., Outer.Inner - ParameterizedTypeBinding ptb = this._env.getLookupEnvironment().createParameterizedType(elementBinding, null, enclosingType); - return (DeclaredType) this._env.getFactory().newTypeMirror(ptb); - } - } else if (typeArgsLength != typeVariablesLength) { - throw new IllegalArgumentException("Number of typeArguments doesn't match the number of formal parameters of typeElem"); //$NON-NLS-1$ - } - TypeBinding[] typeArguments = new TypeBinding[typeArgsLength]; - for (int i = 0; i < typeArgsLength; i++) { - TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) typeArgs[i]; - Binding binding = typeMirrorImpl._binding; - if (!(binding instanceof TypeBinding)) { - throw new IllegalArgumentException("Invalid type for a type arguments : " + typeMirrorImpl); //$NON-NLS-1$ - } - typeArguments[i] = (TypeBinding) binding; - } - return (DeclaredType) this._env.getFactory().newTypeMirror( - this._env.getLookupEnvironment().createParameterizedType(elementBinding, typeArguments, enclosingType)); - } - - @Override - public NoType getNoType(TypeKind kind) { - return this._env.getFactory().getNoType(kind); - } - - @Override - public NullType getNullType() { - return this._env.getFactory().getNullType(); - } - - @Override - public PrimitiveType getPrimitiveType(TypeKind kind) { - return this._env.getFactory().getPrimitiveType(kind); - } - - @Override - public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) { - if (extendsBound != null && superBound != null) { - throw new IllegalArgumentException("Extends and super bounds cannot be set at the same time"); //$NON-NLS-1$ - } - if (extendsBound != null) { - TypeMirrorImpl extendsBoundMirrorType = (TypeMirrorImpl) extendsBound; - TypeBinding typeBinding = (TypeBinding) extendsBoundMirrorType._binding; - return (WildcardType) this._env.getFactory().newTypeMirror( - this._env.getLookupEnvironment().createWildcard( - null, - 0, - typeBinding, - null, - Wildcard.EXTENDS)); - } - if (superBound != null) { - TypeMirrorImpl superBoundMirrorType = (TypeMirrorImpl) superBound; - TypeBinding typeBinding = (TypeBinding) superBoundMirrorType._binding; - return new WildcardTypeImpl(this._env, this._env.getLookupEnvironment().createWildcard( - null, - 0, - typeBinding, - null, - Wildcard.SUPER)); - } - return new WildcardTypeImpl(this._env, this._env.getLookupEnvironment().createWildcard( - null, - 0, - null, - null, - Wildcard.UNBOUND)); - } - - /* (non-Javadoc) - * @return true if a value of type t1 can be assigned to a variable of type t2, i.e., t2 = t1. - */ - @Override - public boolean isAssignable(TypeMirror t1, TypeMirror t2) { - validateRealTypes(t1, t2); - if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) { - return false; - } - Binding b1 = ((TypeMirrorImpl)t1).binding(); - Binding b2 = ((TypeMirrorImpl)t2).binding(); - if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) { - // package, method, import, etc. - throw new IllegalArgumentException(); - } - if (((TypeBinding)b1).isCompatibleWith((TypeBinding)b2)) { - return true; - } - - TypeBinding convertedType = this._env.getLookupEnvironment().computeBoxingType((TypeBinding)b1); - return null != convertedType && convertedType.isCompatibleWith((TypeBinding)b2); - } - - @Override - public boolean isSameType(TypeMirror t1, TypeMirror t2) { - if (t1 instanceof NoTypeImpl) { - if (t2 instanceof NoTypeImpl) { - return ((NoTypeImpl) t1).getKind() == ((NoTypeImpl) t2).getKind(); - } - return false; - } else if (t2 instanceof NoTypeImpl) { - return false; - } - if (t1.getKind() == TypeKind.WILDCARD || t2.getKind() == TypeKind.WILDCARD) { - // Wildcard types are never equal, according to the spec of this method - return false; - } - if (t1 == t2) { - return true; - } - if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) { - return false; - } - Binding b1 = ((TypeMirrorImpl)t1).binding(); - Binding b2 = ((TypeMirrorImpl)t2).binding(); - - if (b1 == b2) { - return true; - } - if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) { - return false; - } - TypeBinding type1 = ((TypeBinding) b1); - TypeBinding type2 = ((TypeBinding) b2); - if (TypeBinding.equalsEquals(type1, type2)) - return true; - return CharOperation.equals(type1.computeUniqueKey(), type2.computeUniqueKey()); - } - - @Override - public boolean isSubsignature(ExecutableType m1, ExecutableType m2) { - MethodBinding methodBinding1 = (MethodBinding) ((ExecutableTypeImpl) m1)._binding; - MethodBinding methodBinding2 = (MethodBinding) ((ExecutableTypeImpl) m2)._binding; - if (!CharOperation.equals(methodBinding1.selector, methodBinding2.selector)) - return false; - return methodBinding1.areParameterErasuresEqual(methodBinding2) && methodBinding1.areTypeVariableErasuresEqual(methodBinding2); - } - - /* (non-Javadoc) - * @return true if t1 is a subtype of t2, or if t1 == t2. - */ - @Override - public boolean isSubtype(TypeMirror t1, TypeMirror t2) { - validateRealTypes(t1, t2); - if (t1 instanceof NoTypeImpl) { - if (t2 instanceof NoTypeImpl) { - return ((NoTypeImpl) t1).getKind() == ((NoTypeImpl) t2).getKind(); - } - return false; - } else if (t2 instanceof NoTypeImpl) { - return false; - } - if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) { - throw new IllegalArgumentException(); - } - if (t1 == t2) { - return true; - } - Binding b1 = ((TypeMirrorImpl)t1).binding(); - Binding b2 = ((TypeMirrorImpl)t2).binding(); - if (b1 == b2) { - return true; - } - if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) { - // package, method, import, etc. - throw new IllegalArgumentException(); - } - if (b1.kind() == Binding.BASE_TYPE || b2.kind() == Binding.BASE_TYPE) { - if (b1.kind() != b2.kind()) { - return false; - } - else { - // for primitives, compatibility implies subtype - return ((TypeBinding)b1).isCompatibleWith((TypeBinding)b2); - } - } - return ((TypeBinding)b1).isCompatibleWith((TypeBinding)b2); - } - - @Override - public PrimitiveType unboxedType(TypeMirror t) { - if (!(((TypeMirrorImpl)t)._binding instanceof ReferenceBinding)) { - // Not an unboxable type - could be primitive, array, not a type at all, etc. - throw new IllegalArgumentException("Given type mirror cannot be unboxed"); //$NON-NLS-1$ - } - ReferenceBinding boxed = (ReferenceBinding)((TypeMirrorImpl)t)._binding; - TypeBinding unboxed = this._env.getLookupEnvironment().computeBoxingType(boxed); - if (unboxed.kind() != Binding.BASE_TYPE) { - // No boxing conversion was found - throw new IllegalArgumentException(); - } - return (PrimitiveType) this._env.getFactory().newTypeMirror(unboxed); - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java deleted file mode 100644 index 826b204..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/VariableElementImpl.java +++ /dev/null @@ -1,201 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 2015 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ElementVisitor; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.VariableElement; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.AptBinaryLocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.AptSourceLocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; - -/** - * Implementation of VariableElement, which represents a a field, enum constant, - * method or constructor parameter, local variable, or exception parameter. - */ -public class VariableElementImpl extends ElementImpl implements VariableElement { - - /** - * @param binding might be a FieldBinding (for a field) or a LocalVariableBinding (for a method param) - */ - VariableElementImpl(BaseProcessingEnvImpl env, VariableBinding binding) { - super(env, binding); - } - - @Override - public R accept(ElementVisitor v, P p) - { - return v.visitVariable(this, p); - } - - @Override - protected AnnotationBinding[] getAnnotationBindings() - { - return ((VariableBinding)this._binding).getAnnotations(); - } - - @Override - public Object getConstantValue() { - VariableBinding variableBinding = (VariableBinding) this._binding; - Constant constant = variableBinding.constant(); - if (constant == null || constant == Constant.NotAConstant) return null; - TypeBinding type = variableBinding.type; - switch (type.id) { - case TypeIds.T_boolean: - return constant.booleanValue(); - case TypeIds.T_byte: - return constant.byteValue(); - case TypeIds.T_char: - return constant.charValue(); - case TypeIds.T_double: - return constant.doubleValue(); - case TypeIds.T_float: - return constant.floatValue(); - case TypeIds.T_int: - return constant.intValue(); - case TypeIds.T_JavaLangString: - return constant.stringValue(); - case TypeIds.T_long: - return constant.longValue(); - case TypeIds.T_short: - return constant.shortValue(); - } - return null; - } - - @Override - public List getEnclosedElements() { - return Collections.emptyList(); - } - - @Override - public Element getEnclosingElement() { - if (this._binding instanceof FieldBinding) { - return this._env.getFactory().newElement(((FieldBinding)this._binding).declaringClass); - } - else if (this._binding instanceof AptSourceLocalVariableBinding){ - return this._env.getFactory().newElement(((AptSourceLocalVariableBinding) this._binding).methodBinding); - } else if (this._binding instanceof AptBinaryLocalVariableBinding) { - return this._env.getFactory().newElement(((AptBinaryLocalVariableBinding) this._binding).methodBinding); - } else if (this._binding instanceof RecordComponentBinding) { - return this._env.getFactory().newElement(((RecordComponentBinding)this._binding).declaringRecord); - } - return null; - } - - @Override - public ElementKind getKind() { - if (this._binding instanceof FieldBinding) { - if ((((FieldBinding) this._binding).modifiers & ClassFileConstants.AccEnum) != 0) { - return ElementKind.ENUM_CONSTANT; - } - else { - return ElementKind.FIELD; - } - } - else { - return ElementKind.PARAMETER; - } - } - - @Override - public Set getModifiers() - { - if (this._binding instanceof VariableBinding) { - return Factory.getModifiers(((VariableBinding)this._binding).modifiers, getKind()); - } - return Collections.emptySet(); - } - - @Override - PackageElement getPackage() - { - if (this._binding instanceof FieldBinding) { - PackageBinding pkgBinding = ((FieldBinding)this._binding).declaringClass.fPackage; - return this._env.getFactory().newPackageElement(pkgBinding); - } - else { - // TODO: what is the package of a method parameter? - throw new UnsupportedOperationException("NYI: VariableElmentImpl.getPackage() for method parameter"); //$NON-NLS-1$ - } - } - - @Override - public Name getSimpleName() { - return new NameImpl(((VariableBinding)this._binding).name); - } - - @Override - public boolean hides(Element hiddenElement) - { - if (this._binding instanceof FieldBinding) { - if (!(((ElementImpl)hiddenElement)._binding instanceof FieldBinding)) { - return false; - } - FieldBinding hidden = (FieldBinding)((ElementImpl)hiddenElement)._binding; - if (hidden.isPrivate()) { - return false; - } - FieldBinding hider = (FieldBinding)this._binding; - if (hidden == hider) { - return false; - } - if (!CharOperation.equals(hider.name, hidden.name)) { - return false; - } - return null != hider.declaringClass.findSuperTypeOriginatingFrom(hidden.declaringClass); - } - // TODO: should we implement hides() for method parameters? - return false; - } - - @Override - public String toString() { - return new String(((VariableBinding) this._binding).name); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - final VariableElementImpl other = (VariableElementImpl) obj; - return Objects.equals(this._binding, other._binding); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java deleted file mode 100644 index 31a7459..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/model/WildcardTypeImpl.java +++ /dev/null @@ -1,71 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.apt.model; - -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import javax.lang.model.type.TypeVisitor; -import javax.lang.model.type.WildcardType; - -import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; -import org.eclipse.jdt.internal.compiler.ast.Wildcard; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; - -/** - * Implementation of the WildcardType - */ -public class WildcardTypeImpl extends TypeMirrorImpl implements WildcardType { - - WildcardTypeImpl(BaseProcessingEnvImpl env, WildcardBinding binding) { - super(env, binding); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.WildcardType#getExtendsBound() - */ - @Override - public TypeMirror getExtendsBound() { - WildcardBinding wildcardBinding = (WildcardBinding) this._binding; - if (wildcardBinding.boundKind != Wildcard.EXTENDS) return null; - TypeBinding bound = wildcardBinding.bound; - if (bound == null) return null; - return this._env.getFactory().newTypeMirror(bound); - } - - /* (non-Javadoc) - * @see javax.lang.model.type.TypeMirror#getKind() - */ - @Override - public TypeKind getKind() { - return TypeKind.WILDCARD; - } - /* (non-Javadoc) - * @see javax.lang.model.type.WildcardType#getSuperBound() - */ - @Override - public TypeMirror getSuperBound() { - WildcardBinding wildcardBinding = (WildcardBinding) this._binding; - if (wildcardBinding.boundKind != Wildcard.SUPER) return null; - TypeBinding bound = wildcardBinding.bound; - if (bound == null) return null; - return this._env.getFactory().newTypeMirror(bound); - } - - @Override - public R accept(TypeVisitor v, P p) { - return v.visitWildcard(this, p); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java deleted file mode 100644 index 4dcae6c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java +++ /dev/null @@ -1,102 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2022 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.util; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Path; -import java.util.Collection; -import java.util.Locale; - -/** - * Implementation of the Standard Java File Manager - */ -public class EclipseFileManager extends org.eclipse.jdt.internal.compiler.tool.EclipseFileManager { - - - public EclipseFileManager(Locale locale, Charset charset) { - super(locale, charset); - } - - @Override - public Iterable getLocation(Location location) { - /* XXX there are strange differences regarding module name handling with super class - if (location instanceof LocationWrapper) { - return getFiles(((LocationWrapper) location).getPaths()); - } - LocationWrapper loc = this.locationHandler.getLocation(location, ""); //$NON-NLS-1$ - if (loc == null) { - return null; - } - return getFiles(loc.getPaths()); - */ - return super.getLocation(location); - } - - @Override - public boolean hasLocation(Location location) { - /* XXX there are strange differences regarding module name handling with super class - try { - return getLocationForModule(location, "") != null; //$NON-NLS-1$ - } catch (IOException e) { - // nothing to do - } - return false; - */ - return super.hasLocation(location); - } - - @Override - public void setLocation(Location location, Iterable files) throws IOException { - /* XXX there are strange differences regarding module name handling with super class - if (location.isOutputLocation() && files != null) { - // output location - int count = 0; - for (Iterator iterator = files.iterator(); iterator.hasNext(); ) { - iterator.next(); - count++; - } - if (count != 1) { - throw new IllegalArgumentException("output location can only have one path");//$NON-NLS-1$ - } - } - this.locationHandler.setLocation(location, "", getPaths(files)); //$NON-NLS-1$ - */ - super.setLocation(location, files); - } - - @Override - public void setLocationForModule(Location location, String moduleName, Collection paths) throws IOException { - /* XXX there are strange differences regarding module name handling with super class - validateModuleLocation(location, moduleName); - this.locationHandler.setLocation(location, moduleName, paths); - if (location == StandardLocation.MODULE_SOURCE_PATH) { - LocationWrapper wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, moduleName); - if (wrapper == null) { - wrapper = this.locationHandler.getLocation(StandardLocation.CLASS_OUTPUT, ""); //$NON-NLS-1$ - if (wrapper != null) { - Iterator iterator = wrapper.getPaths().iterator(); - if (iterator.hasNext()) { - // Per module output location is always a singleton list - Path path = iterator.next().resolve(moduleName); - this.locationHandler.setLocation(StandardLocation.CLASS_OUTPUT, moduleName, Collections.singletonList(path)); - } - } - } - } - */ - super.setLocationForModule(location, moduleName, paths); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java deleted file mode 100644 index 623f3cf..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/apt/util/ManyToMany.java +++ /dev/null @@ -1,369 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2017 BEA Systems, Inc. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * wharley@bea.com - initial API and implementation - * (originally in org.eclipse.jdt.apt.core) - * IBM Corporation - Bug 513790 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.apt.util; - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -/** - * Manage a {@code Map>}, with reverse links so that it is possible to - * efficiently find all T1s that have a particular T2 associated with them. - * Access to the map is synchronized, so that it is possible to read and - * write simultaneously from multiple threads. - *

- * The map permits the null value for keys nor for value elements. - *

- * Design invariants preserved by all operations on this map are as follows: - *

- */ -public class ManyToMany { - - private final Map> _forward = new HashMap<>(); - private final Map> _reverse = new HashMap<>(); - private boolean _dirty = false; - - /** - * Empty all maps. If the maps previously contained entries, - * this will set the dirty bit. - * @return true if the maps contained any entries prior to being cleared - */ - public synchronized boolean clear() { - boolean hadContent = !this._forward.isEmpty() || !this._reverse.isEmpty(); - this._reverse.clear(); - this._forward.clear(); - this._dirty |= hadContent; - return hadContent; - } - - /** - * Sets the dirty bit to false. Internal operations do not use the dirty - * bit; clearing it will not affect behavior of the map. It's just there - * for the convenience of callers who don't want to keep track of every - * put() and remove(). - */ - public synchronized void clearDirtyBit() { - this._dirty = false; - } - - /** - * Equivalent to keySet().contains(key). - * @return true if the map contains the specified key. - */ - public synchronized boolean containsKey(T1 key) { - return this._forward.containsKey(key); - } - - /** - * Is there a key that is mapped to the specified value? - * Search within the forward map. - * @return true if such a key exists - */ - public synchronized boolean containsKeyValuePair(T1 key, T2 value) { - Set values = this._forward.get(key); - if (null == values) { - return false; - } - return values.contains(value); - } - - /** - * Equivalent to values().contains(value). - * @return true if the map contains the specified value (regardless - * of what key it might be associated with). - */ - public synchronized boolean containsValue(T2 value) { - return this._reverse.containsKey(value); - } - - /** - * Search the reverse map for all keys that have been associated with - * a particular value. - * @return the set of keys that are associated with the specified value, - * or an empty set if the value does not exist in the map. - */ - public synchronized Set getKeys(T2 value) { - Set keys = this._reverse.get(value); - if (null == keys) { - return Collections.emptySet(); - } - return new HashSet<>(keys); - } - - /** - * Search the forward map for all values associated with a particular key. - * Returns a copy of the set of values. - * @return a copy of the set of values that are associated with the - * specified key, or an empty set if the key does not exist in the map. - */ - public synchronized Set getValues(T1 key) { - Set values = this._forward.get(key); - if (null == values) { - return Collections.emptySet(); - } - return new HashSet<>(values); - } - - /** - * @return a copy of the set of all keys (that is, all items of type T1). - * If the maps are empty, the returned set will be empty, not null. The - * returned set can be modified by the caller without affecting the map. - * @see #getValueSet() - */ - public synchronized Set getKeySet() { - Set keys = new HashSet<>(this._forward.keySet()); - return keys; - } - - /** - * @return a copy of the set of all values (that is, all items of type T2). - * If the maps are empty, the returned set will be empty, not null. The - * returned set can be modified by the caller without affecting the map. - * @see #getKeySet() - */ - public synchronized Set getValueSet() { - Set values = new HashSet<>(this._reverse.keySet()); - return values; - } - - /** - * Return the state of the dirty bit. All operations that change the state - * of the maps, including @see #clear(), set the dirty bit if any content actually - * changed. The only way to clear the dirty bit is to call @see #clearDirtyBit(). - * @return true if the map content has changed since it was created or since - * the last call to clearDirtyBit(). - * @see #clearDirtyBit() - */ - public synchronized boolean isDirty() { - return this._dirty; - } - - /** - * Check whether key has an association to any values other - * than value - that is, whether the same key has been added - * with multiple values. Equivalent to asking whether the intersection of - * getValues(key) and the set containing value is - * non-empty. - * @return true iff key is in the map and is associated - * with values other than value. - * @see #valueHasOtherKeys(Object, Object) - */ - public synchronized boolean keyHasOtherValues(T1 key, T2 value) { - Set values = this._forward.get(key); - if (values == null) - return false; - int size = values.size(); - if (size == 0) - return false; - else if (size > 1) - return true; - else // size == 1 - return !values.contains(value); - } - - /** - * Associate the specified value with the key. Adds the entry - * to both the forward and reverse maps. Adding the same value - * twice to a particular key has no effect. Because this is a - * many-to-many map, adding a new value for an existing key does - * not change the existing association, it adds a new one. - * @param key can be null - * @param value can be null - * @return true if the key/value pair did not exist prior to being added - */ - public synchronized boolean put(T1 key, T2 value) { - // Add to forward map - Set values = this._forward.get(key); - if (null == values) { - values = new HashSet<>(); - this._forward.put(key, values); - } - boolean added = values.add(value); - this._dirty |= added; - - // Add to reverse map - Set keys = this._reverse.get(value); - if (null == keys) { - keys = new HashSet<>(); - this._reverse.put(value, keys); - } - keys.add(key); - - assert checkIntegrity(); - return added; - } - - /** - * Remove a particular key-value association. This is the inverse - * of put(key, value). If the key does not exist, or the value - * does not exist, or the association does not exist, this call - * has no effect. - * @return true if the key/value pair existed in the map prior to removal - */ - public synchronized boolean remove(T1 key, T2 value) { - Set values = this._forward.get(key); - if (values == null) { - assert checkIntegrity(); - return false; - } - boolean removed = values.remove(value); - if (values.isEmpty()) { - this._forward.remove(key); - } - if (removed) { - this._dirty = true; - // it existed, so we need to remove from reverse map as well - Set keys = this._reverse.get(value); - keys.remove(key); - if (keys.isEmpty()) { - this._reverse.remove(value); - } - } - assert checkIntegrity(); - return removed; - } - - /** - * Remove the key and its associated key/value entries. - * Calling removeKey(k) is equivalent to calling remove(k,v) - * for every v in getValues(k). - * @return true if the key existed in the map prior to removal - */ - public synchronized boolean removeKey(T1 key) { - // Remove all back-references to key. - Set values = this._forward.get(key); - if (null == values) { - // key does not exist in map. - assert checkIntegrity(); - return false; - } - for (T2 value : values) { - Set keys = this._reverse.get(value); - if (null != keys) { - keys.remove(key); - if (keys.isEmpty()) { - this._reverse.remove(value); - } - } - } - // Now remove the forward references from key. - this._forward.remove(key); - this._dirty = true; - assert checkIntegrity(); - return true; - } - - /** - * Remove the value and its associated key/value entries. - * Calling removeValue(v) is equivalent to calling remove(k,v) - * for every k in getKeys(v). - * @return true if the value existed in the map prior to removal. - */ - public synchronized boolean removeValue(T2 value) { - // Remove any forward references to value - Set keys = this._reverse.get(value); - if (null == keys) { - // value does not exist in map. - assert checkIntegrity(); - return false; - } - for (T1 key : keys) { - Set values = this._forward.get(key); - if (null != values) { - values.remove(value); - if (values.isEmpty()) { - this._forward.remove(key); - } - } - } - // Now remove the reverse references from value. - this._reverse.remove(value); - this._dirty = true; - assert checkIntegrity(); - return true; - } - - /** - * Check whether value has an association from any keys other - * than key - that is, whether the same value has been added - * with multiple keys. Equivalent to asking whether the intersection of - * getKeys(value) and the set containing key is - * non-empty. - * @return true iff value is in the map and is associated - * with keys other than key. - * @see #keyHasOtherValues(Object, Object) - */ - public synchronized boolean valueHasOtherKeys(T2 value, T1 key) { - Set keys = this._reverse.get(value); - if (keys == null) - return false; - int size = keys.size(); - if (size == 0) - return false; - else if (size > 1) - return true; - else // size == 1 - return !keys.contains(key); - } - - /** - * Check the integrity of the internal data structures. This is intended to - * be called within an assert, so that if asserts are disabled the integrity - * checks will not cause a performance impact. - * @return true if everything is okay. - * @throws IllegalStateException if there is a problem. - */ - private boolean checkIntegrity() { - // For every T1->T2 mapping in the forward map, there should be a corresponding - // T2->T1 mapping in the reverse map. - for (Map.Entry> entry : this._forward.entrySet()) { - Set values = entry.getValue(); - if (values.isEmpty()) { - throw new IllegalStateException("Integrity compromised: forward map contains an empty set"); //$NON-NLS-1$ - } - for (T2 value : values) { - Set keys = this._reverse.get(value); - if (null == keys || !keys.contains(entry.getKey())) { - throw new IllegalStateException("Integrity compromised: forward map contains an entry missing from reverse map: " + value); //$NON-NLS-1$ - } - } - } - // And likewise in the other direction. - for (Map.Entry> entry : this._reverse.entrySet()) { - Set keys = entry.getValue(); - if (keys.isEmpty()) { - throw new IllegalStateException("Integrity compromised: reverse map contains an empty set"); //$NON-NLS-1$ - } - for (T1 key : keys) { - Set values = this._forward.get(key); - if (null == values || !values.contains(entry.getKey())) { - throw new IllegalStateException("Integrity compromised: reverse map contains an entry missing from forward map: " + key); //$NON-NLS-1$ - } - } - } - return true; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java deleted file mode 100644 index c048207..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AND_AND_Expression.java +++ /dev/null @@ -1,319 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE - * bug 403086 - [compiler][null] include the effect of 'assert' in syntactic null analysis for fields - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 422796 - [compiler][null] boxed boolean reported as potentially null after null test in lazy disjunction - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -/** dedicated treatment for the {@code &&} */ -public class AND_AND_Expression extends BinaryExpression { - - int rightInitStateIndex = -1; - int mergedInitStateIndex = -1; - - public AND_AND_Expression(Expression left, Expression right, int operator) { - super(left, right, operator); - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - - Constant cst = this.left.optimizedBooleanConstant(); - boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isLeftOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - - if (isLeftOptimizedTrue) { - // TRUE && anything - // need to be careful of scenario: - // (x && y) && !z, if passing the left info to the right, it would - // be swapped by the ! - FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo); - this.mergedInitStateIndex = currentScope.methodScope() - .recordInitializationStates(mergedInfo); - return mergedInfo; - } - - FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo); - if ((flowContext.tagBits & FlowContext.INSIDE_NEGATION) != 0) - flowContext.expireNullCheckedFieldInfo(); - // need to be careful of scenario: - // (x && y) && !z, if passing the left info to the right, it would be - // swapped by the ! - FlowInfo rightInfo = leftInfo.initsWhenTrue().unconditionalCopy(); - this.rightInitStateIndex = currentScope.methodScope().recordInitializationStates(rightInfo); - - int previousMode = rightInfo.reachMode(); - if (isLeftOptimizedFalse) { - if ((rightInfo.reachMode() & FlowInfo.UNREACHABLE) == 0) { - currentScope.problemReporter().fakeReachable(this.right); - rightInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - } - this.left.updateFlowOnBooleanResult(rightInfo, true); - rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo); - if ((flowContext.tagBits & FlowContext.INSIDE_NEGATION) != 0) - flowContext.expireNullCheckedFieldInfo(); - this.left.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - this.right.checkNPEbyUnboxing(currentScope, flowContext, leftInfo.initsWhenTrue()); - FlowInfo mergedInfo = FlowInfo.conditional( - rightInfo.safeInitsWhenTrue(), - leftInfo.initsWhenFalse().unconditionalInits().mergedWith( - rightInfo.initsWhenFalse().setReachMode(previousMode).unconditionalInits())); - // reset after trueMergedInfo got extracted - this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } - - /** - * Code generation for a binary operation - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - - int pc = codeStream.position; - if (this.constant != Constant.NotAConstant) { - // inlined value - if (valueRequired) - codeStream.generateConstant(this.constant, this.implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - Constant cst = this.right.constant; - if (cst != Constant.NotAConstant) { - // && true --> - if (cst.booleanValue() == true) { - this.left.generateCode(currentScope, codeStream, valueRequired); - } else { - // && false --> false - this.left.generateCode(currentScope, codeStream, false); - if (valueRequired) codeStream.iconst_0(); - } - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - - BranchLabel falseLabel = new BranchLabel(codeStream), endLabel; - cst = this.left.optimizedBooleanConstant(); - boolean leftIsConst = cst != Constant.NotAConstant; - boolean leftIsTrue = leftIsConst && cst.booleanValue() == true; - - cst = this.right.optimizedBooleanConstant(); - boolean rightIsConst = cst != Constant.NotAConstant; - boolean rightIsTrue = rightIsConst && cst.booleanValue() == true; - - generateOperands : { - if (leftIsConst) { - this.left.generateCode(currentScope, codeStream, false); - if (!leftIsTrue) { - break generateOperands; // no need to generate right operand - } - } else { - this.left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, true); - // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1 - } - if (this.rightInitStateIndex != -1) { - codeStream.addDefinitelyAssignedVariables(currentScope, this.rightInitStateIndex); - } - if (rightIsConst) { - this.right.generateCode(currentScope, codeStream, false); - } else { - this.right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired); - } - } - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - /* - * improving code gen for such a case: boolean b = i < 0 && false since - * the label has never been used, we have the inlined value on the - * stack. - */ - if (valueRequired) { - if (leftIsConst && !leftIsTrue) { - codeStream.iconst_0(); - } else { - if (rightIsConst && !rightIsTrue) { - codeStream.iconst_0(); - } else { - codeStream.iconst_1(); - } - if (falseLabel.forwardReferenceCount() > 0) { - if ((this.bits & IsReturnedValue) != 0) { - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - falseLabel.place(); - codeStream.iconst_0(); - } else { - codeStream.goto_(endLabel = new BranchLabel(codeStream)); - codeStream.decrStackSize(1); - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } else { - falseLabel.place(); - } - } - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } else { - falseLabel.place(); - } - } - - /** - * Boolean operator code generation Optimized operations are: {@code &&} - */ - @Override - public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - - if (this.constant != Constant.NotAConstant) { - super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, - valueRequired); - return; - } - - // && true --> - Constant cst = this.right.constant; - if (cst != Constant.NotAConstant && cst.booleanValue() == true) { - int pc = codeStream.position; - this.left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - cst = this.left.optimizedBooleanConstant(); - boolean leftIsConst = cst != Constant.NotAConstant; - boolean leftIsTrue = leftIsConst && cst.booleanValue() == true; - - cst = this.right.optimizedBooleanConstant(); - boolean rightIsConst = cst != Constant.NotAConstant; - boolean rightIsTrue = rightIsConst && cst.booleanValue() == true; - - // default case - generateOperands : { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - BranchLabel internalFalseLabel = new BranchLabel(codeStream); - this.left.generateOptimizedBoolean(currentScope, codeStream, null, internalFalseLabel, !leftIsConst); - // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1 - if (leftIsConst && !leftIsTrue) { - internalFalseLabel.place(); - break generateOperands; // no need to generate right operand - } - if (this.rightInitStateIndex != -1) { - codeStream - .addDefinitelyAssignedVariables(currentScope, this.rightInitStateIndex); - } - this.right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, - valueRequired && !rightIsConst); - if (valueRequired && rightIsConst && rightIsTrue) { - codeStream.goto_(trueLabel); - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } - internalFalseLabel.place(); - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - this.left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, !leftIsConst); - // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1 - int pc = codeStream.position; - if (leftIsConst && !leftIsTrue) { - if (valueRequired) { - codeStream.goto_(falseLabel); - } - codeStream.recordPositionsFrom(pc, this.sourceEnd); - break generateOperands; // no need to generate right operand - } - if (this.rightInitStateIndex != -1) { - codeStream - .addDefinitelyAssignedVariables(currentScope, this.rightInitStateIndex); - } - this.right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired && !rightIsConst); - if (valueRequired && rightIsConst && !rightIsTrue) { - codeStream.goto_(falseLabel); - codeStream.recordPositionsFrom(pc, this.sourceEnd); - } - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - } - - @Override - public LocalVariableBinding[] bindingsWhenTrue() { - - LocalVariableBinding [] leftVars = this.left.bindingsWhenTrue(); - LocalVariableBinding [] rightVars = this.right.bindingsWhenTrue(); - - if (leftVars == NO_VARIABLES) - return rightVars; - - if (rightVars == NO_VARIABLES) - return leftVars; - - return LocalVariableBinding.merge(leftVars, rightVars); - } - - @Override - public boolean isCompactableOperation() { - return false; - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.BinaryExpression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public TypeBinding resolveType(BlockScope scope) { - TypeBinding result = super.resolveType(scope); - // check whether comparing identical expressions - Binding leftDirect = Expression.getDirectBinding(this.left); - if (leftDirect != null && leftDirect == Expression.getDirectBinding(this.right)) { - if (!(this.right instanceof Assignment)) - scope.problemReporter().comparingIdenticalExpressions(this); - } - return result; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.left.traverse(visitor, scope); - this.right.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ASTNode.java deleted file mode 100644 index 85bcb0f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ASTNode.java +++ /dev/null @@ -1,1526 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Matt McCutchen - partial fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=122995 - * Karen Moore - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=207411 - * Stephan Herrmann - Contributions for - * bug 185682 - Increment/decrement operators mark local variables as read - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 365519 - editorial cleanup after bug 186342 and bug 365387 - * bug 374605 - Unreasonable warning for enum-based switch statements - * bug 384870 - [compiler] @Deprecated annotation not detected if preceded by other annotation - * bug 393719 - [compiler] inconsistent warnings on iteration variables - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 424742 - [1.8] NPE in LambdaExpression.isCompatibleWith - * Bug 424710 - [1.8][compiler] CCE in SingleNameReference.localVariableBinding - * Bug 424205 - [1.8] Cannot infer type for diamond type with lambda on method invocation - * Bug 424415 - [1.8][compiler] Eventual resolution of ReferenceExpression is not seen to be happening. - * Bug 426366 - [1.8][compiler] Type inference doesn't handle multiple candidate target types in outer overload context - * Bug 427282 - [1.8][compiler] AIOOB (-1) at org.eclipse.jdt.internal.compiler.ClassFile.traverse(ClassFile.java:6209) - * Bug 427483 - [Java 8] Variables in lambdas sometimes can't be resolved - * Bug 428352 - [1.8][compiler] Resolution errors don't always surface - * Bug 427163 - [1.8][null] bogus error "Contradictory null specification" on varags - * Bug 432348 - [1.8] Internal compiler error (NPE) after upgrade to 1.8 - * Bug 440143 - [1.8][null] one more case of contradictory null annotations regarding type variables - * Bug 441693 - [1.8][null] Bogus warning for type argument annotated with @NonNull - * Bug 434483 - [1.8][compiler][inference] Type inference not picked up with method reference - * Bug 446442 - [1.8] merge null annotations from super methods - * Bug 437072 - [compiler][null] Null analysis emits possibly incorrect warning for new int[][] despite @NonNullByDefault - * Jesper S Moller - Contributions for - * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment - * bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable - * bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable - * bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container - * bug 419209 - [1.8] Repeating container annotations should be rejected in the presence of annotation it contains - * Till Brychcy - Contributions for - * bug 467094 - [1.8][null] TYPE_USE NullAnnotations of array contents are applied to field. - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.env.AccessRestriction; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -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.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.lookup.VariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; - -@SuppressWarnings({"rawtypes", "unchecked"}) -public abstract class ASTNode implements TypeConstants, TypeIds { - - public int sourceStart, sourceEnd; - - // storage for internal flags (32 bits) BIT USAGE - public final static int Bit1 = 0x1; // return type (operator) | name reference kind (name ref) | add assertion (type decl) | useful empty statement (empty statement) - public final static int Bit2 = 0x2; // return type (operator) | name reference kind (name ref) | has local type (type, method, field decl) | if type elided (local) - public final static int Bit3 = 0x4; // return type (operator) | name reference kind (name ref) | implicit this (this ref) | is argument(local) - public final static int Bit4 = 0x8; // return type (operator) | first assignment to local (name ref,local decl) | undocumented empty block (block, type and method decl) - public final static int Bit5 = 0x10; // value for return (expression) | has all method bodies (unit) | supertype ref (type ref) | resolved (field decl)| name ref (yield result value) - public final static int Bit6 = 0x20; // depth (name ref, msg) | ignore need cast check (cast expression) | error in signature (method declaration/ initializer) | is recovered (annotation reference) - public final static int Bit7 = 0x40; // depth (name ref, msg) | need runtime checkcast (cast expression) | label used (labelStatement) | needFreeReturn (AbstractMethodDeclaration) | Used in Pattern Guard expression (NameReference) - public final static int Bit8 = 0x80; // depth (name ref, msg) | unsafe cast (cast expression) | is default constructor (constructor declaration) | isElseStatementUnreachable (if statement) - public final static int Bit9 = 0x100; // depth (name ref, msg) | operator (operator) | is local type (type decl) | isThenStatementUnreachable (if statement) | can be static - public final static int Bit10= 0x200; // depth (name ref, msg) | operator (operator) | is anonymous type (type decl) | is implicit constructor (constructor) - public final static int Bit11 = 0x400; // depth (name ref, msg) | operator (operator) | is member type (type decl) - public final static int Bit12 = 0x800; // depth (name ref, msg) | operator (operator) | has abstract methods (type decl) - public final static int Bit13 = 0x1000; // depth (name ref, msg) | operator (operator) | is secondary type (type decl) - public final static int Bit14 = 0x2000; // strictly assigned (reference lhs) | discard enclosing instance (explicit constr call) | hasBeenGenerated (type decl) - public final static int Bit15 = 0x4000; // is unnecessary cast (expression) | is varargs (type ref) | isSubRoutineEscaping (try statement) | superAccess (javadoc allocation expression/javadoc message send/javadoc return statement) - public final static int Bit16 = 0x8000; // in javadoc comment (name ref, type ref, msg) - public final static int Bit17 = 0x10000; // compound assigned (reference lhs) | unchecked (msg, alloc, explicit constr call) - public final static int Bit18 = 0x20000; // non null (expression) | onDemand (import reference) - public final static int Bit19 = 0x40000; // didResolve (parameterized qualified type ref/parameterized single type ref) | empty (javadoc return statement) | needReceiverGenericCast (msg/fieldref) - public final static int Bit20 = 0x80000; // contains syntax errors (method declaration, type declaration, field declarations, initializer), typeref: <> name ref: lambda capture) - public final static int Bit21 = 0x100000; // for all declarations that can contain type references that have type annotations | insideExpressionStatement - public final static int Bit22 = 0x200000; // parenthesis count (expression) | used (import reference) shadows outer local (local declarations) - public final static int Bit23 = 0x400000; // parenthesis count (expression) | second or later declarator in declaration (local declarations) - public final static int Bit24 = 0x800000; // parenthesis count (expression) - public final static int Bit25 = 0x1000000; // parenthesis count (expression) - public final static int Bit26 = 0x2000000; // parenthesis count (expression) - public final static int Bit27 = 0x4000000; // parenthesis count (expression) - public final static int Bit28 = 0x8000000; // parenthesis count (expression) - public final static int Bit29 = 0x10000000; // parenthesis count (expression) - public final static int Bit30 = 0x20000000; // elseif (if statement) | try block exit (try statement) | fall-through (case statement) | ignore no effect assign (expression ref) | needScope (for statement) | isAnySubRoutineEscaping (return statement) | blockExit (synchronized statement) - public final static int Bit31 = 0x40000000; // local declaration reachable (local decl) | ignore raw type check (type ref) | discard entire assignment (assignment) | isSynchronized (return statement) | thenExit (if statement) - public final static int Bit32 = 0x80000000; // reachable (statement) - - public final static long Bit32L = 0x80000000L; - public final static long Bit33L = 0x100000000L; - public final static long Bit34L = 0x200000000L; - public final static long Bit35L = 0x400000000L; - public final static long Bit36L = 0x800000000L; - public final static long Bit37L = 0x1000000000L; - public final static long Bit38L = 0x2000000000L; - public final static long Bit39L = 0x4000000000L; - public final static long Bit40L = 0x8000000000L; - public final static long Bit41L = 0x10000000000L; - public final static long Bit42L = 0x20000000000L; - public final static long Bit43L = 0x40000000000L; - public final static long Bit44L = 0x80000000000L; - public final static long Bit45L = 0x100000000000L; - public final static long Bit46L = 0x200000000000L; - public final static long Bit47L = 0x400000000000L; - public final static long Bit48L = 0x800000000000L; - public final static long Bit49L = 0x1000000000000L; - public final static long Bit50L = 0x2000000000000L; - public final static long Bit51L = 0x4000000000000L; - public final static long Bit52L = 0x8000000000000L; - public final static long Bit53L = 0x10000000000000L; - public final static long Bit54L = 0x20000000000000L; - public final static long Bit55L = 0x40000000000000L; - public final static long Bit56L = 0x80000000000000L; - public final static long Bit57L = 0x100000000000000L; - public final static long Bit58L = 0x200000000000000L; - public final static long Bit59L = 0x400000000000000L; - public final static long Bit60L = 0x800000000000000L; - public final static long Bit61L = 0x1000000000000000L; - public final static long Bit62L = 0x2000000000000000L; - public final static long Bit63L = 0x4000000000000000L; - public final static long Bit64L = 0x8000000000000000L; - - public int bits = IsReachable; // reachable by default - - // for operators - public static final int ReturnTypeIDMASK = Bit1|Bit2|Bit3|Bit4; - public static final int OperatorSHIFT = 8; // Bit9 -> Bit14 - public static final int OperatorMASK = Bit9|Bit10|Bit11|Bit12|Bit13; // 5 bits for operator ID - see org.eclipse.jdt.internal.compiler.ast.OperatorIds - - // for binary expressions - public static final int IsReturnedValue = Bit5; - - // for cast expressions - public static final int UnnecessaryCast = Bit15; - public static final int DisableUnnecessaryCastCheck = Bit6; - public static final int GenerateCheckcast = Bit7; - public static final int UnsafeCast = Bit8; - - public static final int RestrictiveFlagMASK = Bit1 | Bit2 | Bit3 ; - - // for local decls - public static final int IsTypeElided = Bit2; // type elided lambda argument. - public static final int IsArgument = Bit3; - public static final int IsLocalDeclarationReachable = Bit31; - public static final int IsForeachElementVariable = Bit5; - public static final int ShadowsOuterLocal = Bit22; - public static final int IsAdditionalDeclarator = Bit23; - - // for name refs or local decls - public static final int FirstAssignmentToLocal = Bit4; - - // for msg or field references - public static final int NeedReceiverGenericCast = Bit19; - - // for this reference - public static final int IsImplicitThis = Bit3; - - // for single name references - public static final int DepthSHIFT = 5; // Bit6 -> Bit13 - public static final int DepthMASK = Bit6|Bit7|Bit8|Bit9|Bit10|Bit11|Bit12|Bit13; // 8 bits for actual depth value (max. 255) - public static final int IsCapturedOuterLocal = Bit20; - public static final int IsUsedInPatternGuard = Bit7; - public static final int IsSecretYieldValueUsage = Bit5; - - // for statements -// public static final int IsImplicit = Bit11; // record declaration - public static final int IsReachable = Bit32; - public static final int LabelUsed = Bit7; - public static final int DocumentedFallthrough = Bit30; // switch statement - public static final int DocumentedCasesOmitted = Bit31; // switch statement - - - // try statements - public static final int IsSubRoutineEscaping = Bit15; - public static final int IsTryBlockExiting = Bit30; - - // for type declaration - public static final int ContainsAssertion = Bit1; - public static final int IsLocalType = Bit9; - public static final int IsAnonymousType = Bit10; // used to test for anonymous - public static final int IsMemberType = Bit11; // local member do not know it is local at parse time (need to look at binding) - public static final int HasAbstractMethods = Bit12; // used to promote abstract enums - public static final int IsSecondaryType = Bit13; // used to test for secondary - public static final int HasBeenGenerated = Bit14; - - // for type, method and field declarations - public static final int HasLocalType = Bit2; // cannot conflict with AddAssertionMASK - public static final int HasBeenResolved = Bit5; // field decl only (to handle forward references) - - // for expression - public static final int ParenthesizedSHIFT = 21; // Bit22 -> Bit29 - public static final int ParenthesizedMASK = Bit22|Bit23|Bit24|Bit25|Bit26|Bit27|Bit28|Bit29; // 8 bits for parenthesis count value (max. 255) - public static final int IgnoreNoEffectAssignCheck = Bit30; - - // for references on lhs of assignment - public static final int IsStrictlyAssigned = Bit14; // set only for true assignments, as opposed to compound ones - public static final int IsCompoundAssigned = Bit17; // set only for compound assignments, as opposed to other ones - - // for explicit constructor call - public static final int DiscardEnclosingInstance = Bit14; // used for codegen - - // for all method/constructor invocations (msg, alloc, expl. constr call) - public static final int Unchecked = Bit17; - - // for javadoc - used to indicate whether the javadoc has to be resolved - public static final int ResolveJavadoc = Bit17; - - // for empty statement - public static final int IsUsefulEmptyStatement = Bit1; - - // for block and method declaration - public static final int UndocumentedEmptyBlock = Bit4; - public static final int OverridingMethodWithSupercall = Bit5; - public static final int CanBeStatic = Bit9; // used to flag a method that can be declared static - - // for initializer and method declaration - public static final int ErrorInSignature = Bit6; - - // for abstract method declaration - public static final int NeedFreeReturn = Bit7; // abstract method declaration - - // for constructor declaration - public static final int IsDefaultConstructor = Bit8; - public static final int IsCanonicalConstructor = Bit10; // record declaration - public static final int IsImplicit = Bit11; // record declaration / generated statements in compact constructor - - // for compilation unit - public static final int HasAllMethodBodies = Bit5; - public static final int IsImplicitUnit = Bit1; - - // for references in Javadoc comments - public static final int InsideJavadoc = Bit16; - - // for javadoc allocation expression/javadoc message send/javadoc return statement - public static final int SuperAccess = Bit15; - - // for javadoc return statement - public static final int Empty = Bit19; - - // for if statement - public static final int IsElseIfStatement = Bit30; - public static final int ThenExit = Bit31; - public static final int IsElseStatementUnreachable = Bit8; // as computed by control flow analysis or null analysis. - public static final int IsThenStatementUnreachable = Bit9; // as computed by control flow analysis or null analysis - - // for type reference - public static final int IsSuperType = Bit5; - public static final int IsVarArgs = Bit15; - public static final int IgnoreRawTypeCheck = Bit31; - - // for array initializer - public static final int IsAnnotationDefaultValue = Bit1; - - // for null reference analysis - public static final int IsNonNull = Bit18; - - // for for statement - public static final int NeededScope = Bit30; - - // for import reference - public static final int OnDemand = Bit18; - public static final int Used = Bit2; - public static final int inModule = Bit19; - - // for parameterized qualified/single type ref - public static final int DidResolve = Bit19; - - // for return statement - public static final int IsAnySubRoutineEscaping = Bit30; - public static final int IsSynchronized = Bit31; - - // for synchronized statement - public static final int BlockExit = Bit30; - - // for annotation reference - public static final int IsRecovered = Bit6; - - // for type declaration, initializer and method declaration - public static final int HasSyntaxErrors = Bit20; - - // constants used when checking invocation arguments - public static final int INVOCATION_ARGUMENT_OK = 0; - public static final int INVOCATION_ARGUMENT_UNCHECKED = 1; - public static final int INVOCATION_ARGUMENT_WILDCARD = 2; - - // for all declarations that can contain type references that have type annotations - public static final int HasTypeAnnotations = Bit21; - - // for type reference (diamond case) - Java 7 - public static final int IsUnionType = Bit30; - // Used to tag ParameterizedSingleTypeReference or ParameterizedQualifiedTypeReference when they are - // used without any type args. It is also used to tag CompletionOnQualifiedExpression when the - // generics inference has failed and the resolved type still has <>. - public static final int IsDiamond = Bit20; - - // this is only used for method invocation as the expression inside an expression statement - public static final int InsideExpressionStatement = Bit21; - - // for annotation reference, signal if annotation was created from a default: - // also used for implicit method creation of records Java 14 - public static final int IsSynthetic = ASTNode.Bit7; - - // for all reference context entries. - public static final int HasFunctionalInterfaceTypes = ASTNode.Bit22; - - public static final Argument [] NO_ARGUMENTS = new Argument [0]; - public static final RecordComponent [] NO_RECORD_COMPONENTS = new RecordComponent [0]; - public static final TypePattern[] NO_TYPE_PATTERNS = new TypePattern[0]; - public static final LocalVariableBinding[] NO_VARIABLES = new LocalVariableBinding[0]; - - public ASTNode() { - - super(); - } - private static int checkInvocationArgument(BlockScope scope, Expression argument, TypeBinding parameterType, TypeBinding argumentType, TypeBinding originalParameterType) { - argument.computeConversion(scope, parameterType, argumentType); - if (argument instanceof AllocationExpression) { - AllocationExpression allocExp = (AllocationExpression) argument; - // we need this only when the error is not reported in AllocationExpression#checkTypeArgumentRedundancy() - if (allocExp.typeExpected == null && !allocExp.expectedTypeWasInferred) { - final boolean isDiamond = allocExp.type != null && (allocExp.type.bits & ASTNode.IsDiamond) != 0; - allocExp.typeExpected = parameterType; - if (!isDiamond && allocExp.resolvedType.isParameterizedTypeWithActualArguments()) { - ParameterizedTypeBinding pbinding = (ParameterizedTypeBinding) allocExp.resolvedType; - scope.problemReporter().redundantSpecificationOfTypeArguments(allocExp.type, pbinding.arguments); - } - } - } - if (argumentType != TypeBinding.NULL && parameterType.kind() == Binding.WILDCARD_TYPE) { // intersection types are tolerated - WildcardBinding wildcard = (WildcardBinding) parameterType; - if (wildcard.boundKind != Wildcard.SUPER) { - return INVOCATION_ARGUMENT_WILDCARD; - } - } - TypeBinding checkedParameterType = parameterType; // originalParameterType == null ? parameterType : originalParameterType; - if (TypeBinding.notEquals(argumentType, checkedParameterType) && argumentType.needsUncheckedConversion(checkedParameterType)) { - scope.problemReporter().unsafeTypeConversion(argument, argumentType, checkedParameterType); - return INVOCATION_ARGUMENT_UNCHECKED; - } - return INVOCATION_ARGUMENT_OK; - } - public static boolean checkInvocationArguments(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding method, Expression[] arguments, TypeBinding[] argumentTypes, boolean argsContainCast, InvocationSite invocationSite) { - long sourceLevel = scope.compilerOptions().sourceLevel; - boolean is1_7 = sourceLevel >= ClassFileConstants.JDK1_7; - TypeBinding[] params = method.parameters; - int paramLength = params.length; - boolean isRawMemberInvocation = !method.isStatic() - && !receiverType.isUnboundWildcard() - && method.declaringClass.isRawType() - && method.hasSubstitutedParameters(); - - boolean uncheckedBoundCheck = (method.tagBits & TagBits.HasUncheckedTypeArgumentForBoundCheck) != 0; - MethodBinding rawOriginalGenericMethod = null; - if (!isRawMemberInvocation) { - if (method instanceof ParameterizedGenericMethodBinding) { - ParameterizedGenericMethodBinding paramMethod = (ParameterizedGenericMethodBinding) method; - if (paramMethod.isRaw && method.hasSubstitutedParameters()) { - rawOriginalGenericMethod = method.original(); - } - } - } - int invocationStatus = INVOCATION_ARGUMENT_OK; - if (arguments == null) { - if (method.isVarargs()) { - TypeBinding parameterType = ((ArrayBinding) params[paramLength-1]).elementsType(); // no element was supplied for vararg parameter - if (!parameterType.isReifiable() - && (!is1_7 || ((method.tagBits & TagBits.AnnotationSafeVarargs) == 0))) { - scope.problemReporter().unsafeGenericArrayForVarargs(parameterType, (ASTNode)invocationSite); - } - } - } else { - if (method.isVarargs()) { - // 4 possibilities exist for a call to the vararg method foo(int i, long ... value) : foo(1), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new long[] {1, 2}) - int lastIndex = paramLength - 1; - for (int i = 0; i < lastIndex; i++) { - TypeBinding originalRawParam = rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i]; - invocationStatus |= checkInvocationArgument(scope, arguments[i], params[i] , argumentTypes[i], originalRawParam); - } - int argLength = arguments.length; - if (lastIndex <= argLength) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=337093 - TypeBinding parameterType = params[lastIndex]; - TypeBinding originalRawParam = null; - - if (paramLength != argLength || parameterType.dimensions() != argumentTypes[lastIndex].dimensions()) { - parameterType = ((ArrayBinding) parameterType).elementsType(); // single element was provided for vararg parameter - if (!parameterType.isReifiable() - && (!is1_7 || ((method.tagBits & TagBits.AnnotationSafeVarargs) == 0))) { - scope.problemReporter().unsafeGenericArrayForVarargs(parameterType, (ASTNode)invocationSite); - } - originalRawParam = rawOriginalGenericMethod == null ? null : ((ArrayBinding)rawOriginalGenericMethod.parameters[lastIndex]).elementsType(); - } - for (int i = lastIndex; i < argLength; i++) { - invocationStatus |= checkInvocationArgument(scope, arguments[i], parameterType, argumentTypes[i], originalRawParam); - } - } - if (paramLength == argLength) { // 70056 - int varargsIndex = paramLength - 1; - ArrayBinding varargsType = (ArrayBinding) params[varargsIndex]; - TypeBinding lastArgType = argumentTypes[varargsIndex]; - int dimensions; - if (lastArgType == TypeBinding.NULL) { - if (!(varargsType.leafComponentType().isBaseType() && varargsType.dimensions() == 1)) - scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); - } else if (varargsType.dimensions <= (dimensions = lastArgType.dimensions())) { - if (lastArgType.leafComponentType().isBaseType()) { - dimensions--; - } - if (varargsType.dimensions < dimensions) { - scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); - } else if (varargsType.dimensions == dimensions - && TypeBinding.notEquals(lastArgType, varargsType) - && TypeBinding.notEquals(lastArgType.leafComponentType().erasure(), varargsType.leafComponentType.erasure()) - && lastArgType.isCompatibleWith(varargsType.elementsType()) - && lastArgType.isCompatibleWith(varargsType)) { - scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); - } - } - } - } else { - for (int i = 0; i < paramLength; i++) { - TypeBinding originalRawParam = rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i]; - invocationStatus |= checkInvocationArgument(scope, arguments[i], params[i], argumentTypes[i], originalRawParam); - } - } - if (argsContainCast) { - CastExpression.checkNeedForArgumentCasts(scope, receiver, receiverType, method, arguments, argumentTypes, invocationSite); - } - } - if ((invocationStatus & INVOCATION_ARGUMENT_WILDCARD) != 0) { - scope.problemReporter().wildcardInvocation((ASTNode)invocationSite, receiverType, method, argumentTypes); - } else if (!method.isStatic() && !receiverType.isUnboundWildcard() && method.declaringClass.isRawType() && method.hasSubstitutedParameters()) { - if (scope.compilerOptions().reportUnavoidableGenericTypeProblems || receiver == null || !receiver.forcedToBeRaw(scope.referenceContext())) { - scope.problemReporter().unsafeRawInvocation((ASTNode)invocationSite, method); - } - } else if (rawOriginalGenericMethod != null - || uncheckedBoundCheck - || ((invocationStatus & INVOCATION_ARGUMENT_UNCHECKED) != 0)) { - if (method instanceof ParameterizedGenericMethodBinding) { - scope.problemReporter().unsafeRawGenericMethodInvocation((ASTNode)invocationSite, method, argumentTypes); - return true; - } - if (sourceLevel >= ClassFileConstants.JDK1_8) - return true; // signal to erase return type and exceptions, while keeping javac compatibility at 1.7- - } - return false; - } - public ASTNode concreteStatement() { - return this; - } - private void reportPreviewAPI(Scope scope, long modifiers) { - if (scope.compilerOptions().enablePreviewFeatures) - return; - if((modifiers & TagBits.AnnotationPreviewFeature) == TagBits.AnnotationPreviewFeature) { - scope.problemReporter().previewAPIUsed(this.sourceStart, this.sourceEnd, - (modifiers & TagBits.EssentialAPI) != 0); - } - } - public final boolean isFieldUseDeprecated(FieldBinding field, Scope scope, int filteredBits) { - if ((this.bits & ASTNode.InsideJavadoc) == 0 // ignore references inside Javadoc comments - && (filteredBits & IsStrictlyAssigned) == 0 // ignore write access - && field.isOrEnclosedByPrivateType() - && !scope.isDefinedInField(field)) // ignore cases where field is used from inside itself - { - if (((filteredBits & IsCompoundAssigned) != 0)) - // used, but usage may not be relevant - field.original().compoundUseFlag++; - else - field.original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - reportPreviewAPI(scope, field.tagBits); - - if ((field.modifiers & ExtraCompilerModifiers.AccRestrictedAccess) != 0) { - ModuleBinding module = field.declaringClass.module(); - LookupEnvironment env = (module == null) ? scope.environment() : module.environment; - AccessRestriction restriction = - env.getAccessRestriction(field.declaringClass.erasure()); - if (restriction != null) { - scope.problemReporter().forbiddenReference(field, this, - restriction.classpathEntryType, restriction.classpathEntryName, - restriction.getProblemId()); - } - } - - if (!field.isViewedAsDeprecated()) return false; - - // inside same unit - no report - if (scope.isDefinedInSameUnit(field.declaringClass)) return false; - - // if context is deprecated, may avoid reporting - if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false; - return true; - } - - public boolean isImplicitThis() { - - return false; - } - - public boolean receiverIsImplicitThis() { - - return false; - } - - /* Answer true if the method use is considered deprecated. - * An access in the same compilation unit is allowed. - */ - public final boolean isMethodUseDeprecated(MethodBinding method, Scope scope, - boolean isExplicitUse, InvocationSite invocation) { - - reportPreviewAPI(scope, method.tagBits); - - // ignore references insing Javadoc comments - if ((this.bits & ASTNode.InsideJavadoc) == 0 && method.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(method)) { - // ignore cases where method is used from inside itself (e.g. direct recursions) - method.original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - - // TODO (maxime) consider separating concerns between deprecation and access restriction. - // Caveat: this was not the case when access restriction funtion was added. - if (isExplicitUse && (method.modifiers & ExtraCompilerModifiers.AccRestrictedAccess) != 0) { - // note: explicit constructors calls warnings are kept despite the 'new C1()' case (two - // warnings, one on type, the other on constructor), because of the 'super()' case. - ModuleBinding module = method.declaringClass.module(); - LookupEnvironment env = (module == null) ? scope.environment() : module.environment; - AccessRestriction restriction = - env.getAccessRestriction(method.declaringClass.erasure()); - if (restriction != null) { - scope.problemReporter().forbiddenReference(method, invocation, - restriction.classpathEntryType, restriction.classpathEntryName, - restriction.getProblemId()); - } - } - - if (!method.isViewedAsDeprecated()) return false; - - // inside same unit - no report - if (scope.isDefinedInSameUnit(method.declaringClass)) return false; - - // non explicit use and non explicitly deprecated - no report - if (!isExplicitUse && - (method.modifiers & ClassFileConstants.AccDeprecated) == 0) { - return false; - } - - // if context is deprecated, may avoid reporting - if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false; - return true; - } - - public boolean isSuper() { - - return false; - } - - public boolean isQualifiedSuper() { - - return false; - } - - public boolean isThis() { - - return false; - } - - public boolean isUnqualifiedSuper() { - return false; - } - - /* Answer true if the type use is considered deprecated. - * An access in the same compilation unit is allowed. - */ - public final boolean isTypeUseDeprecated(TypeBinding type, Scope scope) { - - if (type.isArrayType()) { - type = ((ArrayBinding) type).leafComponentType; - } - if (type.isBaseType()) - return false; - - ReferenceBinding refType = (ReferenceBinding) type; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=397888 - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=385780 - if ((this.bits & ASTNode.InsideJavadoc) == 0 && refType instanceof TypeVariableBinding) { - refType.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - // ignore references insing Javadoc comments - if ((this.bits & ASTNode.InsideJavadoc) == 0 && refType.isOrEnclosedByPrivateType() && !scope.isDefinedInType(refType)) { - // ignore cases where type is used from inside itself - ((ReferenceBinding)refType.erasure()).modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - reportPreviewAPI(scope, type.extendedTagBits); - if (refType.hasRestrictedAccess()) { - ModuleBinding module = refType.module(); - LookupEnvironment env = (module == null) ? scope.environment() : module.environment; - AccessRestriction restriction = env.getAccessRestriction(type.erasure()); - if (restriction != null) { - scope.problemReporter().forbiddenReference(type, this, restriction.classpathEntryType, - restriction.classpathEntryName, restriction.getProblemId()); - } - } - - // force annotations resolution before deciding whether the type may be deprecated - refType.initializeDeprecatedAnnotationTagBits(); - - if (!refType.isViewedAsDeprecated()) return false; - - // inside same unit - no report - if (scope.isDefinedInSameUnit(refType)) return false; - - // if context is deprecated, may avoid reporting - if (!scope.compilerOptions().reportDeprecationInsideDeprecatedCode && scope.isInsideDeprecatedCode()) return false; - return true; - } - - - /** - * Returns whether this node represents a binding of type {@link Binding#TYPE} - * - * @return true if the node represents a {@link Binding#TYPE} binding type. - */ - public boolean isType() { - return false; - } - - public abstract StringBuilder print(int indent, StringBuilder output); - - public static StringBuilder printAnnotations(Annotation[] annotations, StringBuilder output) { - int length = annotations.length; - for (int i = 0; i < length; i++) { - if (i > 0) { - output.append(" "); //$NON-NLS-1$ - } - Annotation annotation2 = annotations[i]; - if (annotation2 != null) { - annotation2.print(0, output); - } else { - output.append('?'); - } - } - return output; - } - - public static StringBuilder printIndent(int indent, StringBuilder output) { - - for (int i = indent; i > 0; i--) output.append(" "); //$NON-NLS-1$ - return output; - } - - public static StringBuilder printModifiers(int modifiers, StringBuilder output) { - - if ((modifiers & ClassFileConstants.AccPublic) != 0) - output.append("public "); //$NON-NLS-1$ - if ((modifiers & ClassFileConstants.AccPrivate) != 0) - output.append("private "); //$NON-NLS-1$ - if ((modifiers & ClassFileConstants.AccProtected) != 0) - output.append("protected "); //$NON-NLS-1$ - if ((modifiers & ClassFileConstants.AccStatic) != 0) - output.append("static "); //$NON-NLS-1$ - if ((modifiers & ClassFileConstants.AccFinal) != 0) - output.append("final "); //$NON-NLS-1$ - if ((modifiers & ClassFileConstants.AccSynchronized) != 0) - output.append("synchronized "); //$NON-NLS-1$ - if ((modifiers & ClassFileConstants.AccVolatile) != 0) - output.append("volatile "); //$NON-NLS-1$ - if ((modifiers & ClassFileConstants.AccTransient) != 0) - output.append("transient "); //$NON-NLS-1$ - if ((modifiers & ClassFileConstants.AccNative) != 0) - output.append("native "); //$NON-NLS-1$ - if ((modifiers & ClassFileConstants.AccAbstract) != 0) - output.append("abstract "); //$NON-NLS-1$ - if ((modifiers & ExtraCompilerModifiers.AccDefaultMethod) != 0) - output.append("default "); //$NON-NLS-1$ - if ((modifiers & ExtraCompilerModifiers.AccNonSealed) != 0) - output.append("non-sealed "); //$NON-NLS-1$ - if ((modifiers & ExtraCompilerModifiers.AccSealed) != 0) - output.append("sealed "); //$NON-NLS-1$ - return output; - } - - public static void resolveStatements(Statement[] statements, BlockScope scope) { - LocalVariableBinding [] livePatternVariables = NO_VARIABLES; - for (int i = 0, length = statements.length; i < length; i++) { - final Statement stmt = statements[i]; - stmt.resolveWithBindings(livePatternVariables, scope); - livePatternVariables = LocalVariableBinding.merge(livePatternVariables, stmt.bindingsWhenComplete()); - } - } - - /** - * After method lookup has produced 'methodBinding' but when poly expressions have been seen as arguments, - * inspect the arguments to trigger another round of resolving with improved target types from the methods parameters. - * If this resolving produces better types for any arguments, update the 'argumentTypes' array in-place as an - * intended side effect that will feed better type information in checkInvocationArguments() and others. - * @param invocation the outer invocation which is being resolved - * @param method the method produced by lookup (possibly involving type inference). - * @param argumentTypes the argument types as collected from first resolving the invocation arguments and as used for the method lookup. - * @param scope scope for resolution. - * @return either the original method or a problem method - */ - public static MethodBinding resolvePolyExpressionArguments(Invocation invocation, MethodBinding method, TypeBinding[] argumentTypes, BlockScope scope) { - ClassScope cScope = scope.enclosingClassScope(); - boolean resolvingPolyExpressionArguments = cScope.resolvingPolyExpressionArguments; - try { - cScope.resolvingPolyExpressionArguments = true; - return resolvePolyExpressionArguments0(invocation, method, argumentTypes, scope); - } finally { - cScope.resolvingPolyExpressionArguments = resolvingPolyExpressionArguments; - } - } - private static MethodBinding resolvePolyExpressionArguments0(Invocation invocation, MethodBinding method, TypeBinding[] argumentTypes, BlockScope scope) { - MethodBinding candidateMethod = method.isValidBinding() ? method : method instanceof ProblemMethodBinding ? ((ProblemMethodBinding) method).closestMatch : null; - if (candidateMethod == null) - return method; - ProblemMethodBinding problemMethod = null; - boolean variableArity = candidateMethod.isVarargs(); - final TypeBinding[] parameters = candidateMethod.parameters; - Expression[] arguments = invocation.arguments(); - if (variableArity && arguments != null && parameters.length == arguments.length) { - if (arguments[arguments.length-1].isCompatibleWith(parameters[parameters.length-1], scope)) { - variableArity = false; - } - } - for (int i = 0, length = arguments == null ? 0 : arguments.length; i < length; i++) { - Expression argument = arguments[i]; - TypeBinding parameterType = InferenceContext18.getParameter(parameters, i, variableArity); - if (parameterType == null) - continue; // not much we can do without a target type, assume it only happens after some resolve error - if (argumentTypes[i] != null && argumentTypes[i].isPolyType()) { - argument.setExpectedType(parameterType); - TypeBinding updatedArgumentType; - if (argument instanceof LambdaExpression) { - LambdaExpression lambda = (LambdaExpression) argument; - // avoid complaining about non-kosher descriptor as secondary problem - boolean skipKosherCheck = method.problemId() == ProblemReasons.Ambiguous; - updatedArgumentType = lambda.resolveType(scope, skipKosherCheck); - // additional checks, because LE.resolveType may return a valid binding even in the presence of structural errors - if (lambda.hasErrors() || lambda.hasDescripterProblem) { - continue; - } - // avoid that preliminary local type bindings escape beyond this point: - lambda.updateLocalTypesInMethod(candidateMethod); - parameterType = InferenceContext18.getParameter(parameters, i, variableArity); // refresh after update - if (!lambda.isCompatibleWith(parameterType, scope)) { - if (method.isValidBinding() && problemMethod == null) { - TypeBinding[] originalArguments = Arrays.copyOf(argumentTypes, argumentTypes.length); - if (lambda.reportShapeError(parameterType, scope)) { - problemMethod = new ProblemMethodBinding(candidateMethod, method.selector, originalArguments, ProblemReasons.ErrorAlreadyReported); - } else { - problemMethod = new ProblemMethodBinding(candidateMethod, method.selector, originalArguments, ProblemReasons.NotFound); - } - } - continue; - } - } else { - updatedArgumentType = argument.resolveType(scope); - } - if (updatedArgumentType != null && updatedArgumentType.kind() != Binding.POLY_TYPE) { - argumentTypes[i] = updatedArgumentType; - if (candidateMethod.isPolymorphic()) - candidateMethod.parameters[i] = updatedArgumentType; - } - } - } - if (method.returnType instanceof ReferenceBinding) { - scope.referenceCompilationUnit().updateLocalTypesInMethod(method); - } - if (method instanceof ParameterizedGenericMethodBinding) { - InferenceContext18 ic18 = invocation.getInferenceContext((ParameterizedMethodBinding) method); - if (ic18 != null && !ic18.isInexactVarargsInference()) - ic18.flushBoundOutbox(); // overload resolution is done, now perform the push of bounds from inner to outer - } - if (problemMethod != null) - return problemMethod; - return method; - } - - public static void resolveAnnotations(BlockScope scope, Annotation[] sourceAnnotations, Binding recipient) { - resolveAnnotations(scope, sourceAnnotations, recipient, false); - if (recipient instanceof SourceTypeBinding) - ((SourceTypeBinding) recipient).evaluateNullAnnotations(); - } - - /** - * Resolve annotations, and check duplicates, answers combined tagBits - * for recognized standard annotations. Return null if nothing new is - * resolved. - */ - public static AnnotationBinding [] resolveAnnotations(BlockScope scope, Annotation[] sourceAnnotations, Binding recipient, boolean copySE8AnnotationsToType) { - AnnotationBinding[] annotations = null; - int length = sourceAnnotations == null ? 0 : sourceAnnotations.length; - if (recipient != null) { - switch (recipient.kind()) { - case Binding.PACKAGE : - PackageBinding packageBinding = (PackageBinding) recipient; - if ((packageBinding.tagBits & TagBits.AnnotationResolved) != 0) return annotations; - packageBinding.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); - break; - case Binding.TYPE : - case Binding.GENERIC_TYPE : - ReferenceBinding type = (ReferenceBinding) recipient; - if ((type.tagBits & TagBits.AnnotationResolved) != 0) return annotations; - type.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); - if (length > 0) { - annotations = new AnnotationBinding[length]; - type.setAnnotations(annotations, false); - } - break; - case Binding.METHOD : - MethodBinding method = (MethodBinding) recipient; - if ((method.tagBits & TagBits.AnnotationResolved) != 0) return annotations; - method.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); - if (length > 0) { - annotations = new AnnotationBinding[length]; - method.setAnnotations(annotations, false); - } - break; - case Binding.FIELD : - FieldBinding field = (FieldBinding) recipient; - if ((field.tagBits & TagBits.AnnotationResolved) != 0) return annotations; - field.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); - if (length > 0) { - annotations = new AnnotationBinding[length]; - field.setAnnotations(annotations, false); - } - break; - case Binding.RECORD_COMPONENT : - RecordComponentBinding rcb = (RecordComponentBinding) recipient; - if ((rcb.tagBits & TagBits.AnnotationResolved) != 0) return annotations; - rcb.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); - if (length > 0) { - annotations = new AnnotationBinding[length]; - rcb.setAnnotations(annotations, false); - } - break; - case Binding.LOCAL : - LocalVariableBinding local = (LocalVariableBinding) recipient; - if ((local.tagBits & TagBits.AnnotationResolved) != 0) return annotations; - local.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); - if (length > 0) { - annotations = new AnnotationBinding[length]; - local.setAnnotations(annotations, scope, false); - } - break; - case Binding.TYPE_PARAMETER : - ((TypeVariableBinding) recipient).tagBits |= TagBits.AnnotationResolved; - //$FALL-THROUGH$ - case Binding.TYPE_USE : - // for TYPE_USE we deliberately don't set the annotation resolved tagbits, - // it is not material and also we are working with a dummy static object. - annotations = new AnnotationBinding[length]; - break; - case Binding.MODULE: - ModuleBinding module = (ModuleBinding)recipient; - if ((module.tagBits & TagBits.AnnotationResolved) != 0) return annotations; - module.tagBits |= (TagBits.AnnotationResolved | TagBits.DeprecatedAnnotationResolved); - if (length > 0) { - annotations = new AnnotationBinding[length]; - module.setAnnotations(annotations, scope, false); - } - break; - default : - return annotations; - } - } - if (sourceAnnotations == null) - return annotations; - for (int i = 0; i < length; i++) { - Annotation annotation = sourceAnnotations[i]; - final Binding annotationRecipient = annotation.recipient; - if (annotationRecipient != null && recipient != null) { - // only local and field can share annotations and their types. - switch (recipient.kind()) { - case Binding.TYPE_USE: - if (annotations != null) { - // need to fill the instances array - for (int j = 0; j < length; j++) { - annotations[j] = sourceAnnotations[j].getCompilerAnnotation(); - } - } - break; - case Binding.FIELD : - FieldBinding field = (FieldBinding) recipient; - field.tagBits = ((FieldBinding) annotationRecipient).tagBits; - if (annotations != null) { - // need to fill the instances array - for (int j = 0; j < length; j++) { - Annotation annot = sourceAnnotations[j]; - annotations[j] = annot.getCompilerAnnotation(); - } - } - break; - case Binding.RECORD_COMPONENT : - RecordComponentBinding recordComponentBinding = (RecordComponentBinding) recipient; - recordComponentBinding.tagBits = ((RecordComponentBinding) annotationRecipient).tagBits; - if (annotations != null) { - // need to fill the instances array - for (int j = 0; j < length; j++) { - Annotation annot = sourceAnnotations[j]; - annotations[j] = annot.getCompilerAnnotation(); - } - } - break; - case Binding.LOCAL : - LocalVariableBinding local = (LocalVariableBinding) recipient; - // Note for JDK>=14, this could be LVB or RCB, hence typecasting to VB - long otherLocalTagBits = ((VariableBinding) annotationRecipient).tagBits; - // Make sure we retain the TagBits.IsArgument bit - local.tagBits = otherLocalTagBits | (local.tagBits & TagBits.IsArgument); - if ((otherLocalTagBits & TagBits.AnnotationSuppressWarnings) == 0) { - // None of the annotations is a SuppressWarnings annotation - // need to fill the instances array - if (annotations != null) { - for (int j = 0; j < length; j++) { - Annotation annot = sourceAnnotations[j]; - annotations[j] = annot.getCompilerAnnotation(); - } - } - } else if (annotations != null) { - // One of the annotations at least is a SuppressWarnings annotation - LocalDeclaration localDeclaration = local.declaration; - int declarationSourceEnd = localDeclaration.declarationSourceEnd; - int declarationSourceStart = localDeclaration.declarationSourceStart; - for (int j = 0; j < length; j++) { - Annotation annot = sourceAnnotations[j]; - /* - * Annotations are shared between two locals, but we still need to record - * the suppress annotation range for the second local - */ - AnnotationBinding annotationBinding = annot.getCompilerAnnotation(); - annotations[j] = annotationBinding; - if (annotationBinding != null) { - final ReferenceBinding annotationType = annotationBinding.getAnnotationType(); - if (annotationType != null && annotationType.id == TypeIds.T_JavaLangSuppressWarnings) { - annot.recordSuppressWarnings(scope, declarationSourceStart, declarationSourceEnd, scope.compilerOptions().suppressWarnings); - } - } - } - } - // Note: This is the argument of an implicit canonical constructor of a record declaration - // copy the se8 annotations. - if (annotationRecipient instanceof RecordComponentBinding && copySE8AnnotationsToType) - copySE8AnnotationsToType(scope, recipient, sourceAnnotations, false); - break; - } - return annotations; - } else { - annotation.recipient = recipient; - annotation.resolveType(scope); - // null if receiver is a package binding - if (annotations != null) { - annotations[i] = annotation.getCompilerAnnotation(); - } - } - } - - /* See if the recipient is meta-annotated with @Repeatable and if so validate constraints. We can't do this during resolution of @Repeatable itself as @Target and - @Retention etc could come later - */ - if (recipient != null && recipient.isTaggedRepeatable()) { - for (int i = 0; i < length; i++) { - Annotation annotation = sourceAnnotations[i]; - ReferenceBinding annotationType = annotations[i] != null ? annotations[i].getAnnotationType() : null; - if (annotationType != null && annotationType.id == TypeIds.T_JavaLangAnnotationRepeatable) - annotation.checkRepeatableMetaAnnotation(scope); - } - } - - // check duplicate annotations - if (annotations != null && length > 1) { - AnnotationBinding[] distinctAnnotations = annotations; // only copy after 1st duplicate is detected - Map implicitContainerAnnotations = null; - for (int i = 0; i < length; i++) { - AnnotationBinding annotation = distinctAnnotations[i]; - if (annotation == null) continue; - ReferenceBinding annotationType = annotation.getAnnotationType(); - boolean foundDuplicate = false; - ContainerAnnotation container = null; - for (int j = i+1; j < length; j++) { - AnnotationBinding otherAnnotation = distinctAnnotations[j]; - if (otherAnnotation == null) continue; - if (TypeBinding.equalsEquals(otherAnnotation.getAnnotationType(), annotationType)) { - if (distinctAnnotations == annotations) { - System.arraycopy(distinctAnnotations, 0, distinctAnnotations = new AnnotationBinding[length], 0, length); - } - distinctAnnotations[j] = null; // report/process it only once - if (annotationType.isRepeatableAnnotationType()) { - Annotation persistibleAnnotation = sourceAnnotations[i].getPersistibleAnnotation(); - if (persistibleAnnotation instanceof ContainerAnnotation) - container = (ContainerAnnotation) persistibleAnnotation; - if (container == null) { // first encounter with a duplicate. - ReferenceBinding containerAnnotationType = annotationType.containerAnnotationType(); - container = new ContainerAnnotation(sourceAnnotations[i], containerAnnotationType, scope); - if (implicitContainerAnnotations == null) implicitContainerAnnotations = new HashMap(3); - implicitContainerAnnotations.put(containerAnnotationType, sourceAnnotations[i]); - Annotation.checkForInstancesOfRepeatableWithRepeatingContainerAnnotation(scope, annotationType, sourceAnnotations); - } - container.addContainee(sourceAnnotations[j]); - } else { - foundDuplicate = true; - scope.problemReporter().duplicateAnnotation(sourceAnnotations[j], scope.compilerOptions().sourceLevel); - } - } - } - if (container != null) { - container.resolveType(scope); - } - if (foundDuplicate) { - scope.problemReporter().duplicateAnnotation(sourceAnnotations[i], scope.compilerOptions().sourceLevel); - } - } - // Check for presence of repeating annotation together with the containing annotation - if (implicitContainerAnnotations != null) { - for (int i = 0; i < length; i++) { - if (distinctAnnotations[i] == null) continue; - Annotation annotation = sourceAnnotations[i]; - ReferenceBinding annotationType = distinctAnnotations[i].getAnnotationType(); - if (implicitContainerAnnotations.containsKey(annotationType)) { - scope.problemReporter().repeatedAnnotationWithContainer((Annotation) implicitContainerAnnotations.get(annotationType), annotation); - } - } - } - } - if (copySE8AnnotationsToType) - copySE8AnnotationsToType(scope, recipient, sourceAnnotations, false); - return annotations; - } - - /** Resolve JSR308 annotations on a type reference, array creation expression or a wildcard. Type parameters go directly to the subroutine, - By construction the bindings associated with QTR, PQTR etc get resolved first and then annotations for different levels get resolved - and applied at one go. Likewise for multidimensional arrays. - - @return the annotated type binding. - */ - public static TypeBinding resolveAnnotations(BlockScope scope, Annotation[][] sourceAnnotations, TypeBinding type) { - int levels = sourceAnnotations == null ? 0 : sourceAnnotations.length; - if (type == null || levels == 0) - return type; - AnnotationBinding [][] annotationBindings = new AnnotationBinding [levels][]; - - for (int i = 0; i < levels; i++) { - Annotation[] annotations = sourceAnnotations[i]; - if (annotations != null && annotations.length > 0) { - annotationBindings[i] = resolveAnnotations(scope, annotations, TypeBinding.TYPE_USE_BINDING, false); - } - } - return scope.environment().createAnnotatedType(type, annotationBindings); - } - - /** - * "early" handling of NonNullByDefault because for local variables annotations are resolved after their type because of bug - * 96991. - */ - public static void handleNonNullByDefault(BlockScope scope, Annotation[] sourceAnnotations, LocalDeclaration localDeclaration) { - if (sourceAnnotations == null || sourceAnnotations.length == 0) { - return; - } - int length = sourceAnnotations.length; - - int defaultNullness = 0; - Annotation lastNNBDAnnotation = null; - for (int i = 0; i < length; i++) { - Annotation annotation = sourceAnnotations[i]; - long value = annotation.handleNonNullByDefault(scope); - if (value != 0) { - defaultNullness |= value; - lastNNBDAnnotation = annotation; - } - } - if (defaultNullness != 0) { - // the actual localDeclaration.binding is not set yet. fake one for problemreporter. - LocalVariableBinding binding = new LocalVariableBinding(localDeclaration, null, 0, false); - Binding target = scope.checkRedundantDefaultNullness(defaultNullness, localDeclaration.sourceStart); - boolean recorded = scope.recordNonNullByDefault(binding, defaultNullness, lastNNBDAnnotation, - lastNNBDAnnotation.sourceStart, localDeclaration.declarationSourceEnd); - if (recorded) { - if (target != null) { - scope.problemReporter().nullDefaultAnnotationIsRedundant(localDeclaration, - new Annotation[] { lastNNBDAnnotation }, target); - } - } - } - } - - - - // When SE8 annotations feature in SE7 locations, they get attributed to the declared entity. Copy/move these to the type of the declared entity (field, local, argument etc.) - public static void copySE8AnnotationsToType(BlockScope scope, Binding recipient, Annotation[] annotations, boolean annotatingEnumerator) { - - if (annotations == null || annotations.length == 0 || recipient == null) - return; - - long recipientTargetMask = 0; - switch (recipient.kind()) { - case Binding.LOCAL: - recipientTargetMask = recipient.isParameter() ? TagBits.AnnotationForParameter : TagBits.AnnotationForLocalVariable; - break; - case Binding.FIELD: - recipientTargetMask = TagBits.AnnotationForField; - break; - case Binding.METHOD: - MethodBinding method = (MethodBinding) recipient; - recipientTargetMask = method.isConstructor() ? TagBits.AnnotationForConstructor : TagBits.AnnotationForMethod; - break; - case Binding.RECORD_COMPONENT: - recipientTargetMask = TagBits.AnnotationForRecordComponent; - break; - default: - return; - } - - AnnotationBinding [] se8Annotations = null; - int se8count = 0; - long se8nullBits = 0; - Annotation se8NullAnnotation = null; // just any involved annotation so we have a location for error reporting - int firstSE8 = -1; - for (int i = 0, length = annotations.length; i < length; i++) { - AnnotationBinding annotation = annotations[i].getCompilerAnnotation(); - if (annotation == null) continue; - final ReferenceBinding annotationType = annotation.getAnnotationType(); - long metaTagBits = annotationType.getAnnotationTagBits(); - if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - if (annotatingEnumerator) { - if ((metaTagBits & recipientTargetMask) == 0) { - scope.problemReporter().misplacedTypeAnnotations(annotations[i], annotations[i]); - } - continue; - } - if (firstSE8 == -1) firstSE8 = i; - if (se8Annotations == null) { - se8Annotations = new AnnotationBinding[] { annotation }; - se8count = 1; - } else { - System.arraycopy(se8Annotations, 0, se8Annotations = new AnnotationBinding[se8count + 1], 0, se8count); - se8Annotations[se8count++] = annotation; - } - if (annotationType.hasNullBit(TypeIds.BitNonNullAnnotation)) { - se8nullBits |= TagBits.AnnotationNonNull; - se8NullAnnotation = annotations[i]; - } else if (annotationType.hasNullBit(TypeIds.BitNullableAnnotation)) { - se8nullBits |= TagBits.AnnotationNullable; - se8NullAnnotation = annotations[i]; - } - } - } - if (se8Annotations != null) { - switch (recipient.kind()) { - case Binding.LOCAL: - LocalVariableBinding local = (LocalVariableBinding) recipient; - TypeReference typeRef = local.declaration.type; - if (Annotation.isTypeUseCompatible(typeRef, scope)) { // discard hybrid annotations on name qualified types. - local.declaration.bits |= HasTypeAnnotations; - typeRef.bits |= HasTypeAnnotations; - int location = local.isParameter() ? Binding.DefaultLocationParameter : 0 /*no default for locals*/; - local.type = mergeAnnotationsIntoType(scope, se8Annotations, se8nullBits, se8NullAnnotation, typeRef, location, local.type); - if(scope.environment().usesNullTypeAnnotations()) { - local.tagBits &= ~(se8nullBits); - } - } - break; - case Binding.FIELD: - FieldBinding field = (FieldBinding) recipient; - SourceTypeBinding sourceType = (SourceTypeBinding) field.declaringClass; - FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(field); - if (Annotation.isTypeUseCompatible(fieldDeclaration.type, scope)) { // discard hybrid annotations on name qualified types. - fieldDeclaration.bits |= HasTypeAnnotations; - fieldDeclaration.type.bits |= HasTypeAnnotations; - field.type = mergeAnnotationsIntoType(scope, se8Annotations, se8nullBits, se8NullAnnotation, - fieldDeclaration.type, Binding.DefaultLocationField, field.type); - if(scope.environment().usesNullTypeAnnotations()) { - field.tagBits &= ~(se8nullBits); - } - } - break; - case Binding.RECORD_COMPONENT: - RecordComponentBinding recordComponentBinding = (RecordComponentBinding) recipient; - RecordComponent recordComponent = recordComponentBinding.sourceRecordComponent(); - if (Annotation.isTypeUseCompatible(recordComponent.type, scope)) { // discard hybrid annotations on name qualified types. - recordComponent.bits |= HasTypeAnnotations; - recordComponent.type.bits |= HasTypeAnnotations; - recordComponentBinding.type = mergeAnnotationsIntoType(scope, se8Annotations, se8nullBits, se8NullAnnotation, recordComponent.type, - Binding.DefaultLocationField, recordComponentBinding.type); - if(scope.environment().usesNullTypeAnnotations()) { //TODO Bug 562478 - recordComponentBinding.tagBits &= ~(se8nullBits); - } - } - break; - case Binding.METHOD: - MethodBinding method = (MethodBinding) recipient; - if (!method.isConstructor()) { - sourceType = (SourceTypeBinding) method.declaringClass; - MethodDeclaration methodDecl = (MethodDeclaration) sourceType.scope.referenceContext.declarationOf(method); - if (Annotation.isTypeUseCompatible(methodDecl.returnType, scope)) { - methodDecl.bits |= HasTypeAnnotations; - methodDecl.returnType.bits |= HasTypeAnnotations; - method.returnType = mergeAnnotationsIntoType(scope, se8Annotations, se8nullBits, se8NullAnnotation, - methodDecl.returnType, Binding.DefaultLocationReturnType, method.returnType); - if(scope.environment().usesNullTypeAnnotations()) { - method.tagBits &= ~(se8nullBits); - } - } - } else { - method.setTypeAnnotations(se8Annotations); - } - break; - } - AnnotationBinding [] recipientAnnotations = recipient.getAnnotations(); - int length = recipientAnnotations == null ? 0 : recipientAnnotations.length; - int newLength = 0; - for (int i = 0; i < length; i++) { - final AnnotationBinding recipientAnnotation = recipientAnnotations[i]; - if (recipientAnnotation == null) - continue; - long annotationTargetMask = recipientAnnotation.getAnnotationType().getAnnotationTagBits() & TagBits.AnnotationTargetMASK; - if (annotationTargetMask == 0 || (annotationTargetMask & recipientTargetMask) != 0) - recipientAnnotations[newLength++] = recipientAnnotation; - } - if (newLength != length) { - System.arraycopy(recipientAnnotations, 0, recipientAnnotations = new AnnotationBinding[newLength], 0, newLength); - recipient.setAnnotations(recipientAnnotations, scope, false); - } - } - } - - public static Annotation[] getRelevantAnnotations(Annotation[] annotations, long rcMask, - List relevantAnnotations) { - - if (annotations == null || annotations.length == 0) - return null; - - List filteredAnnotations = new ArrayList<>(); - for (Annotation annot : annotations) { - AnnotationBinding annotationBinding = annot.getCompilerAnnotation(); - if (annotationBinding == null) continue; - final ReferenceBinding annotationType = annotationBinding.getAnnotationType(); - long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference - if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0 || (metaTagBits & rcMask) != 0) { - filteredAnnotations.add(annot); - if (relevantAnnotations != null) - relevantAnnotations.add(annotationBinding); - } - } - return filteredAnnotations.toArray(new Annotation[0]); - } - public static Annotation[] copyRecordComponentAnnotations(Scope scope, Binding recipient, Annotation[] annotations) { - if (annotations == null || annotations.length == 0 || recipient == null) - return null; - - long recipientTargetMask = 0; - switch (recipient.kind()) { - case Binding.LOCAL: - assert recipient.isParameter(); // only for implicit canonical constructor arguments - recipientTargetMask = recipient.isParameter() ? TagBits.AnnotationForParameter : TagBits.AnnotationForLocalVariable; - break; - case Binding.FIELD: - recipientTargetMask = TagBits.AnnotationForField; - break; - case Binding.METHOD: - MethodBinding method = (MethodBinding) recipient; - recipientTargetMask = method.isConstructor() ? TagBits.AnnotationForConstructor : TagBits.AnnotationForMethod; - break; - case Binding.RECORD_COMPONENT: - // Use it on record component itself to filter out non-record component annotations. - recipientTargetMask = TagBits.AnnotationForRecordComponent; - break; - default: - return null; - } - // TODO: Null Analysis Address via bug 562478? - - List relevantAnnotations = new ArrayList<>(); - Annotation[] filteredAnnotations = ASTNode.getRelevantAnnotations(annotations, recipientTargetMask, relevantAnnotations); - AnnotationBinding [] recipientAnnotations = relevantAnnotations.toArray(new AnnotationBinding[relevantAnnotations.size()]); - recipient.setAnnotations(recipientAnnotations, scope, true /* forceStore*/);// forceStore since we require at codegen - return filteredAnnotations; - } - - private static TypeBinding mergeAnnotationsIntoType(BlockScope scope, AnnotationBinding[] se8Annotations, long se8nullBits, Annotation se8NullAnnotation, - TypeReference typeRef, int location, TypeBinding existingType) - { - if (existingType == null || !existingType.isValidBinding()) return existingType; - TypeReference unionRef = typeRef.isUnionType() ? ((UnionTypeReference) typeRef).typeReferences[0] : null; - - // for arrays: @T X[] SE7 associates @T to the type, but in SE8 it affects the leaf component type - TypeBinding oldLeafType = (unionRef == null) ? existingType.leafComponentType() : unionRef.resolvedType; - if (se8nullBits != 0) { - if (typeRef instanceof ArrayTypeReference) { // NOTE: no corresponding code for ArrayQualifiedTypeReference is necessary - ArrayTypeReference arrayTypeReference = (ArrayTypeReference) typeRef; - if(arrayTypeReference.leafComponentTypeWithoutDefaultNullness != null) { - oldLeafType=arrayTypeReference.leafComponentTypeWithoutDefaultNullness; - } - } - } - if (se8nullBits != 0 && oldLeafType.isBaseType()) { - scope.problemReporter().illegalAnnotationForBaseType(typeRef, new Annotation[] { se8NullAnnotation }, se8nullBits); - return existingType; - } - - if (typeRef.dimensions() > 0) { - location = Binding.DefaultLocationArrayContents; // moving from SE7 to SE8 position applies to the array contents! - } - - long prevNullBits = oldLeafType.tagBits & TagBits.AnnotationNullMASK; - if ((prevNullBits | se8nullBits) == TagBits.AnnotationNullMASK && typeRef.hasNullTypeAnnotation(AnnotationPosition.MAIN_TYPE)) { - // would merging introduce a contradiction? - if (!(oldLeafType instanceof TypeVariableBinding)) { // let type-use annotations override annotations on the type parameter declaration - if (prevNullBits != TagBits.AnnotationNullMASK && se8nullBits != TagBits.AnnotationNullMASK) { // conflict caused by the merge? - scope.problemReporter().contradictoryNullAnnotations(se8NullAnnotation); - } - se8nullBits = TagBits.AnnotationNullMASK; - } - oldLeafType = oldLeafType.withoutToplevelNullAnnotation(); - } else if (se8nullBits == TagBits.AnnotationNonNull - && location != Binding.DefaultLocationReturnType // normal return type cases are handled in MethodBinding.fillInDefaultNonNullness18() - && location != Binding.DefaultLocationField // normal field type cases are handled in FieldBinding.fillInDefaultNonNullness() - && scope.hasDefaultNullnessForType(typeRef.resolvedType, location, typeRef.sourceStart)) { - scope.problemReporter().nullAnnotationIsRedundant(typeRef, new Annotation[] { se8NullAnnotation }); - } - if (se8nullBits == TagBits.AnnotationNullMASK) { - // withdraw contradicting null annotations - se8Annotations = scope.environment().filterNullTypeAnnotations(se8Annotations); - } - if (se8Annotations.length > 0) { - AnnotationBinding [][] goodies = new AnnotationBinding[typeRef.getAnnotatableLevels()][]; - goodies[0] = se8Annotations; // @T X.Y.Z local; ==> @T should annotate X - TypeBinding newLeafType = scope.environment().createAnnotatedType(oldLeafType, goodies); - - if (unionRef == null) { - typeRef.resolvedType = existingType.isArrayType() ? scope.environment().createArrayType(newLeafType, existingType.dimensions(), existingType.getTypeAnnotations()) : newLeafType; - } else { - unionRef.resolvedType = newLeafType; - unionRef.bits |= HasTypeAnnotations; - } - } - return typeRef.resolvedType; - } - -/** - * Figures if @Deprecated annotation is specified, do not resolve entire annotations. - */ -public static void resolveDeprecatedAnnotations(BlockScope scope, Annotation[] annotations, Binding recipient) { - if (recipient != null) { - int kind = recipient.kind(); - if (annotations != null) { - int length; - if ((length = annotations.length) >= 0) { - switch (kind) { - case Binding.PACKAGE : - PackageBinding packageBinding = (PackageBinding) recipient; - if ((packageBinding.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return; - break; - case Binding.TYPE : - case Binding.GENERIC_TYPE : - ReferenceBinding type = (ReferenceBinding) recipient; - if ((type.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return; - break; - case Binding.METHOD : - MethodBinding method = (MethodBinding) recipient; - if ((method.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return; - break; - case Binding.FIELD : - FieldBinding field = (FieldBinding) recipient; - if ((field.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return; - break; - case Binding.LOCAL : - LocalVariableBinding local = (LocalVariableBinding) recipient; - if ((local.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return; - break; - case Binding.RECORD_COMPONENT : - RecordComponentBinding recordComponentBinding = (RecordComponentBinding) recipient; - if ((recordComponentBinding.tagBits & TagBits.DeprecatedAnnotationResolved) != 0) return; - break; - default : - return; - } - for (int i = 0; i < length; i++) { - TypeReference annotationTypeRef = annotations[i].type; - // only resolve type name if 'Deprecated' last token - if (!CharOperation.equals(TypeConstants.JAVA_LANG_DEPRECATED[2], annotationTypeRef.getLastToken())) continue; - TypeBinding annotationType = annotations[i].type.resolveType(scope); - if(annotationType != null && annotationType.isValidBinding() && annotationType.id == TypeIds.T_JavaLangDeprecated) { - long deprecationTagBits = TagBits.AnnotationDeprecated | TagBits.DeprecatedAnnotationResolved; - if (scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK9) { - for (MemberValuePair memberValuePair : annotations[i].memberValuePairs()) { - if (CharOperation.equals(memberValuePair.name, TypeConstants.FOR_REMOVAL)) { - if (memberValuePair.value instanceof TrueLiteral) - deprecationTagBits |= TagBits.AnnotationTerminallyDeprecated; - break; - } - } - } - switch (kind) { - case Binding.PACKAGE : - PackageBinding packageBinding = (PackageBinding) recipient; - packageBinding.tagBits |= deprecationTagBits; - return; - case Binding.TYPE : - case Binding.GENERIC_TYPE : - case Binding.TYPE_PARAMETER : - ReferenceBinding type = (ReferenceBinding) recipient; - type.tagBits |= deprecationTagBits; - return; - case Binding.METHOD : - MethodBinding method = (MethodBinding) recipient; - method.tagBits |= deprecationTagBits; - return; - case Binding.FIELD : - FieldBinding field = (FieldBinding) recipient; - field.tagBits |= deprecationTagBits; - return; - case Binding.LOCAL : - LocalVariableBinding local = (LocalVariableBinding) recipient; - local.tagBits |= deprecationTagBits; - return; - case Binding.RECORD_COMPONENT : - RecordComponentBinding recordComponentBinding = (RecordComponentBinding) recipient; - recordComponentBinding.tagBits |= deprecationTagBits; - return; - default: - return; - } - } - } - } - } - switch (kind) { - case Binding.PACKAGE : - PackageBinding packageBinding = (PackageBinding) recipient; - packageBinding.tagBits |= TagBits.DeprecatedAnnotationResolved; - return; - case Binding.TYPE : - case Binding.GENERIC_TYPE : - case Binding.TYPE_PARAMETER : - ReferenceBinding type = (ReferenceBinding) recipient; - type.tagBits |= TagBits.DeprecatedAnnotationResolved; - return; - case Binding.METHOD : - MethodBinding method = (MethodBinding) recipient; - method.tagBits |= TagBits.DeprecatedAnnotationResolved; - return; - case Binding.FIELD : - FieldBinding field = (FieldBinding) recipient; - field.tagBits |= TagBits.DeprecatedAnnotationResolved; - return; - case Binding.LOCAL : - LocalVariableBinding local = (LocalVariableBinding) recipient; - local.tagBits |= TagBits.DeprecatedAnnotationResolved; - return; - case Binding.RECORD_COMPONENT : - RecordComponentBinding recordComponentBinding = (RecordComponentBinding) recipient; - recordComponentBinding.tagBits |= TagBits.DeprecatedAnnotationResolved; - return; - default: - return; - } - } -} - - // ---- "default methods" for InvocationSite. Can we move to 1.8 and spare ourselves this ugliness please ? - public boolean checkingPotentialCompatibility() { - return false; - } - - public void acceptPotentiallyCompatibleMethods(MethodBinding [] methods) { - // Discard. Interested subclasses should override and grab these goodies. - } - // --- "default methods" for InvocationSite - - public int sourceStart() { - return this.sourceStart; - } - public int sourceEnd() { - return this.sourceEnd; - } - @Override - public String toString() { - - return print(0, new StringBuilder(30)).toString(); - } - - public void traverse(ASTVisitor visitor, BlockScope scope) { - // do nothing by default - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java deleted file mode 100644 index d05c302..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AbstractMethodDeclaration.java +++ /dev/null @@ -1,761 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 367203 - [compiler][null] detect assigning null to nonnull argument - * bug 365519 - editorial cleanup after bug 186342 and bug 365387 - * bug 365531 - [compiler][null] investigate alternative strategy for internally encoding nullness defaults - * bug 382353 - [1.8][compiler] Implementation property modifiers should be accepted on default methods. - * bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * bug 388281 - [compiler][null] inheritance of null annotations as an option - * bug 401030 - [1.8][null] Null analysis support for lambda methods. - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 403216 - [1.8][null] TypeReference#captureTypeAnnotations treats type annotations as type argument annotations - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" - * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations - * Bug 466713 - Null Annotations: NullPointerException using as Type Param - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.List; - -import static org.eclipse.jdt.internal.compiler.lookup.MethodBinding.PARAM_NONNULL; -import static org.eclipse.jdt.internal.compiler.lookup.MethodBinding.PARAM_NULLABLE; -import static org.eclipse.jdt.internal.compiler.lookup.MethodBinding.PARAM_NULLITY; -import static org.eclipse.jdt.internal.compiler.lookup.MethodBinding.PARAM_OWNING; -import static org.eclipse.jdt.internal.compiler.lookup.MethodBinding.PARAM_NOTOWNING; - -import org.eclipse.jdt.core.compiler.*; -import org.eclipse.jdt.internal.compiler.*; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.problem.*; -import org.eclipse.jdt.internal.compiler.parser.*; -import org.eclipse.jdt.internal.compiler.util.Util; - -@SuppressWarnings({"rawtypes"}) -public abstract class AbstractMethodDeclaration - extends ASTNode - implements ProblemSeverities, ReferenceContext { - - public MethodScope scope; - //it is not relevent for constructor but it helps to have the name of the constructor here - //which is always the name of the class.....parsing do extra work to fill it up while it do not have to.... - public char[] selector; - public int declarationSourceStart; - public int declarationSourceEnd; - public int modifiers; - public int modifiersSourceStart; - public Annotation[] annotations; - // jsr 308 - public Receiver receiver; - public Argument[] arguments; - public TypeReference[] thrownExceptions; - public Statement[] statements; - public int explicitDeclarations; - public MethodBinding binding; - public boolean ignoreFurtherInvestigation = false; - - public Javadoc javadoc; - - public int bodyStart; - public int bodyEnd = -1; - public CompilationResult compilationResult; - public boolean containsSwitchWithTry = false; - - AbstractMethodDeclaration(CompilationResult compilationResult){ - this.compilationResult = compilationResult; - this.containsSwitchWithTry = false; - } - - /* - * We cause the compilation task to abort to a given extent. - */ - @Override - public void abort(int abortLevel, CategorizedProblem problem) { - - switch (abortLevel) { - case AbortCompilation : - throw new AbortCompilation(this.compilationResult, problem); - case AbortCompilationUnit : - throw new AbortCompilationUnit(this.compilationResult, problem); - case AbortType : - throw new AbortType(this.compilationResult, problem); - default : - throw new AbortMethod(this.compilationResult, problem); - } - } - - /** - * When a method is accessed via SourceTypeBinding.resolveTypesFor(MethodBinding) - * we create the argument binding and resolve annotations in order to compute null annotation tagbits. - */ - public void createArgumentBindings() { - createArgumentBindings(this.arguments, this.binding, this.scope); - } - // version for invocation from LambdaExpression: - static void createArgumentBindings(Argument[] arguments, MethodBinding binding, MethodScope scope) { - boolean useTypeAnnotations = scope.environment().usesNullTypeAnnotations(); - if (arguments != null && binding != null) { - for (int i = 0, length = arguments.length; i < length; i++) { - Argument argument = arguments[i]; - binding.parameters[i] = argument.createBinding(scope, binding.parameters[i]); - long argumentTagBits = argument.binding.tagBits; - if ((argumentTagBits & TagBits.AnnotationOwning) != 0) { - if (binding.parameterFlowBits == null) { - binding.parameterFlowBits = new byte[arguments.length]; - } - binding.parameterFlowBits[i] |= PARAM_OWNING; - } else if ((argumentTagBits & TagBits.AnnotationNotOwning) != 0) { - if (binding.parameterFlowBits == null) { - binding.parameterFlowBits = new byte[arguments.length]; - } - binding.parameterFlowBits[i] |= PARAM_NOTOWNING; - } - if (useTypeAnnotations) - continue; // no business with SE7 null annotations in the 1.8 case. - // createBinding() has resolved annotations, now transfer nullness info from the argument to the method: - long argTypeTagBits = (argumentTagBits & TagBits.AnnotationNullMASK); - if (argTypeTagBits != 0) { - if (binding.parameterFlowBits == null) { - binding.parameterFlowBits = new byte[arguments.length]; - binding.tagBits |= TagBits.IsNullnessKnown; - } - binding.parameterFlowBits[i] = MethodBinding.flowBitFromAnnotationTagBit(argTypeTagBits); - } - } - } - } - - /** - * Bind and add argument's binding into the scope of the method - */ - public void bindArguments() { - - if (this.arguments != null) { - // by default arguments in abstract/native methods are considered to be used (no complaint is expected) - if (this.binding == null) { - for (int i = 0, length = this.arguments.length; i < length; i++) { - this.arguments[i].bind(this.scope, null, true); - } - return; - } - boolean used = this.binding.isAbstract() || this.binding.isNative(); - AnnotationBinding[][] paramAnnotations = null; - for (int i = 0, length = this.arguments.length; i < length; i++) { - Argument argument = this.arguments[i]; - this.binding.parameters[i] = argument.bind(this.scope, this.binding.parameters[i], used); - if (argument.annotations != null) { - if (paramAnnotations == null) { - paramAnnotations = new AnnotationBinding[length][]; - for (int j=0; j - *
  • NonNull - for null analysis - *
  • Nullable - for null analysis - *
  • Owning - for resource leak analysis - *
  • NotOwning - for resource leak analysis - * - */ - static void analyseArguments(LookupEnvironment environment, FlowInfo flowInfo, FlowContext flowContext, Argument[] methodArguments, MethodBinding methodBinding) { - if (methodArguments != null) { - boolean usesNullTypeAnnotations = environment.usesNullTypeAnnotations(); - boolean usesOwningAnnotations = environment.usesOwningAnnotations(); - - int length = Math.min(methodBinding.parameters.length, methodArguments.length); - for (int i = 0; i < length; i++) { - TypeBinding parameterBinding = methodBinding.parameters[i]; - LocalVariableBinding local = methodArguments[i].binding; - if (usesNullTypeAnnotations) { - // leverage null type annotations: - long tagBits = parameterBinding.tagBits & TagBits.AnnotationNullMASK; - if (tagBits == TagBits.AnnotationNonNull) - flowInfo.markAsDefinitelyNonNull(local); - else if (tagBits == TagBits.AnnotationNullable) - flowInfo.markPotentiallyNullBit(local); - else if (parameterBinding.isFreeTypeVariable()) - flowInfo.markNullStatus(local, FlowInfo.FREE_TYPEVARIABLE); - } else { - if (methodBinding.parameterFlowBits != null) { - // leverage null-info from parameter annotations: - int nullity = methodBinding.parameterFlowBits[i] & PARAM_NULLITY; - if (nullity == PARAM_NONNULL) - flowInfo.markAsDefinitelyNonNull(local); - else if (nullity == PARAM_NULLABLE) - flowInfo.markPotentiallyNullBit(local); - } - } - if (!flowInfo.hasNullInfoFor(local)) - flowInfo.markNullStatus(local, FlowInfo.UNKNOWN); // ensure nullstatus is initialized - // tag parameters as being set: - flowInfo.markAsDefinitelyAssigned(local); - - if (usesOwningAnnotations && local.type.hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) { - long owningTagBits = local.tagBits & TagBits.AnnotationOwningMASK; - int initialNullStatus = (local.tagBits & TagBits.AnnotationOwning) !=0 ? FlowInfo.NULL : FlowInfo.NON_NULL; // defaulting to not-owning - local.closeTracker = new FakedTrackingVariable(local, methodArguments[i], flowInfo, flowContext, initialNullStatus, usesOwningAnnotations); - local.closeTracker.owningState = FakedTrackingVariable.owningStateFromTagBits(owningTagBits, FakedTrackingVariable.NOT_OWNED_PER_DEFAULT); - } - } - } - } - - @Override - public CompilationResult compilationResult() { - - return this.compilationResult; - } - - /** - * Bytecode generation for a method - */ - public void generateCode(ClassScope classScope, ClassFile classFile) { - - classFile.codeStream.wideMode = false; // reset wideMode to false - if (this.ignoreFurtherInvestigation) { - // method is known to have errors, dump a problem method - if (this.binding == null) - return; // handle methods with invalid signature or duplicates - int problemsLength; - CategorizedProblem[] problems = - this.scope.referenceCompilationUnit().compilationResult.getProblems(); - CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; - System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); - classFile.addProblemMethod(this, this.binding, problemsCopy); - return; - } - int problemResetPC = 0; - CompilationResult unitResult = null; - int problemCount = 0; - if (classScope != null) { - TypeDeclaration referenceContext = classScope.referenceContext; - if (referenceContext != null) { - unitResult = referenceContext.compilationResult(); - problemCount = unitResult.problemCount; - } - } - boolean restart = false; - boolean abort = false; - // regular code generation - do { - try { - problemResetPC = classFile.contentsOffset; - this.generateCode(classFile); - restart = false; - } catch (AbortMethod e) { - // a fatal error was detected during code generation, need to restart code gen if possible - if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { - // a branch target required a goto_w, restart code gen in wide mode. - classFile.contentsOffset = problemResetPC; - classFile.methodCount--; - classFile.codeStream.resetInWideMode(); // request wide mode - // reset the problem count to prevent reporting the same warning twice - if (unitResult != null) { - unitResult.problemCount = problemCount; - } - restart = true; - } else if (e.compilationResult == CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE) { - classFile.contentsOffset = problemResetPC; - classFile.methodCount--; - classFile.codeStream.resetForCodeGenUnusedLocals(); - // reset the problem count to prevent reporting the same warning twice - if (unitResult != null) { - unitResult.problemCount = problemCount; - } - restart = true; - } else { - restart = false; - abort = true; - } - } - } while (restart); - // produce a problem method accounting for this fatal error - if (abort) { - int problemsLength; - CategorizedProblem[] problems = - this.scope.referenceCompilationUnit().compilationResult.getAllProblems(); - CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; - System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); - classFile.addProblemMethod(this, this.binding, problemsCopy, problemResetPC); - } - } - - public void generateCode(ClassFile classFile) { - - classFile.generateMethodInfoHeader(this.binding); - int methodAttributeOffset = classFile.contentsOffset; - int attributeNumber = classFile.generateMethodInfoAttributes(this.binding); - if ((!this.binding.isNative()) && (!this.binding.isAbstract())) { - int codeAttributeOffset = classFile.contentsOffset; - classFile.generateCodeAttributeHeader(); - CodeStream codeStream = classFile.codeStream; - codeStream.reset(this, classFile); - // initialize local positions - this.scope.computeLocalVariablePositions(this.binding.isStatic() ? 0 : 1, codeStream); - - // arguments initialization for local variable debug attributes - if (this.arguments != null) { - for (int i = 0, max = this.arguments.length; i < max; i++) { - LocalVariableBinding argBinding; - codeStream.addVisibleLocalVariable(argBinding = this.arguments[i].binding); - argBinding.recordInitializationStartPC(0); - } - } - codeStream.pushPatternAccessTrapScope(this.scope); - if (this.statements != null) { - for (Statement stmt : this.statements) { - stmt.generateCode(this.scope, codeStream); - } - } - // if a problem got reported during code gen, then trigger problem method creation - if (this.ignoreFurtherInvestigation) { - throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null); - } - if ((this.bits & ASTNode.NeedFreeReturn) != 0) { - codeStream.return_(); - } - // See https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1796#issuecomment-1933458054 - codeStream.exitUserScope(this.scope, lvb -> !lvb.isParameter()); - codeStream.handleRecordAccessorExceptions(this.scope); - // local variable attributes - codeStream.exitUserScope(this.scope); - codeStream.recordPositionsFrom(0, this.declarationSourceEnd); - try { - classFile.completeCodeAttribute(codeAttributeOffset,this.scope); - } catch(NegativeArraySizeException e) { - throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null); - } - attributeNumber++; - } else { - checkArgumentsSize(); - } - classFile.completeMethodInfo(this.binding, methodAttributeOffset, attributeNumber); - } - - public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) { - // do nothing - } - - private void checkArgumentsSize() { - TypeBinding[] parameters = this.binding.parameters; - int size = 1; // an abstract method or a native method cannot be static - for (int i = 0, max = parameters.length; i < max; i++) { - switch(parameters[i].id) { - case TypeIds.T_long : - case TypeIds.T_double : - size += 2; - break; - default : - size++; - break; - } - if (size > 0xFF) { - this.scope.problemReporter().noMoreAvailableSpaceForArgument(this.scope.locals[i], this.scope.locals[i].declaration); - } - } - } - - @Override - public CompilationUnitDeclaration getCompilationUnitDeclaration() { - if (this.scope != null) { - return this.scope.compilationUnitScope().referenceContext; - } - return null; - } - - @Override - public boolean hasErrors() { - return this.ignoreFurtherInvestigation; - } - - public boolean isAbstract() { - - if (this.binding != null) - return this.binding.isAbstract(); - return (this.modifiers & ClassFileConstants.AccAbstract) != 0; - } - - public boolean isAnnotationMethod() { - - return false; - } - - public boolean isClinit() { - - return false; - } - - public boolean isConstructor() { - - return false; - } - - public boolean isCanonicalConstructor() { - - return false; - } - public boolean isDefaultConstructor() { - - return false; - } - - public boolean isDefaultMethod() { - return false; - } - - public boolean isInitializationMethod() { - - return false; - } - - public boolean isMethod() { - - return false; - } - - public boolean isNative() { - - if (this.binding != null) - return this.binding.isNative(); - return (this.modifiers & ClassFileConstants.AccNative) != 0; - } - - public RecordComponent getRecordComponent() { - return null; - } - - public boolean isStatic() { - - if (this.binding != null) - return this.binding.isStatic(); - return (this.modifiers & ClassFileConstants.AccStatic) != 0; - } - - /** - * Fill up the method body with statement - */ - public abstract void parseStatements(Parser parser, CompilationUnitDeclaration unit); - - @Override - public StringBuilder print(int tab, StringBuilder output) { - - if (this.javadoc != null) { - this.javadoc.print(tab, output); - } - printIndent(tab, output); - printModifiers(this.modifiers, output); - if (this.annotations != null) { - printAnnotations(this.annotations, output); - output.append(' '); - } - - TypeParameter[] typeParams = typeParameters(); - if (typeParams != null) { - output.append('<'); - int max = typeParams.length - 1; - for (int j = 0; j < max; j++) { - typeParams[j].print(0, output); - output.append(", ");//$NON-NLS-1$ - } - typeParams[max].print(0, output); - output.append('>'); - } - - printReturnType(0, output).append(this.selector).append('('); - if (this.receiver != null) { - this.receiver.print(0, output); - } - if (this.arguments != null) { - for (int i = 0; i < this.arguments.length; i++) { - if (i > 0 || this.receiver != null) output.append(", "); //$NON-NLS-1$ - this.arguments[i].print(0, output); - } - } - output.append(')'); - if (this.thrownExceptions != null) { - output.append(" throws "); //$NON-NLS-1$ - for (int i = 0; i < this.thrownExceptions.length; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.thrownExceptions[i].print(0, output); - } - } - printBody(tab + 1, output); - return output; - } - - public StringBuilder printBody(int indent, StringBuilder output) { - - if (isAbstract() || (this.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) - return output.append(';'); - - output.append(" {"); //$NON-NLS-1$ - if (this.statements != null) { - for (int i = 0; i < this.statements.length; i++) { - output.append('\n'); - this.statements[i].printStatement(indent, output); - } - } - output.append('\n'); - printIndent(indent == 0 ? 0 : indent - 1, output).append('}'); - return output; - } - - public StringBuilder printReturnType(int indent, StringBuilder output) { - - return output; - } - - public void resolve(ClassScope upperScope) { - - if (this.binding == null) { - this.ignoreFurtherInvestigation = true; - } - - try { - bindArguments(); - resolveReceiver(); - bindThrownExceptions(); - resolveAnnotations(this.scope, this.annotations, this.binding, this.isConstructor()); - - long sourceLevel = this.scope.compilerOptions().sourceLevel; - if (sourceLevel < ClassFileConstants.JDK1_8) // otherwise already checked via Argument.createBinding - validateNullAnnotations(this.scope.environment().usesNullTypeAnnotations()); - - resolveStatements(); - // check @Deprecated annotation presence - if (this.binding != null - && (this.binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) == 0 - && (this.binding.modifiers & ClassFileConstants.AccDeprecated) != 0 - && sourceLevel >= ClassFileConstants.JDK1_5) { - this.scope.problemReporter().missingDeprecatedAnnotationForMethod(this); - } - } catch (AbortMethod e) { - // ========= abort on fatal error ============= - this.ignoreFurtherInvestigation = true; - } - } - - public void resolveReceiver() { - if (this.receiver == null) return; - - if (this.receiver.modifiers != 0) { - this.scope.problemReporter().illegalModifiers(this.receiver.declarationSourceStart, this.receiver.declarationSourceEnd); - } - - TypeBinding resolvedReceiverType = this.receiver.type.resolvedType; - if (this.binding == null || resolvedReceiverType == null || !resolvedReceiverType.isValidBinding()) { - return; - } - - ReferenceBinding declaringClass = this.binding.declaringClass; - /* neither static methods nor methods in anonymous types can have explicit 'this' */ - if (this.isStatic() || declaringClass.isAnonymousType()) { - this.scope.problemReporter().disallowedThisParameter(this.receiver); - return; // No need to do further validation - } - - ReferenceBinding enclosingReceiver = this.scope.enclosingReceiverType(); - if (this.isConstructor()) { - /* Only non static member types or local types can declare explicit 'this' params in constructors */ - if (declaringClass.isStatic() - || (declaringClass.tagBits & (TagBits.IsLocalType | TagBits.IsMemberType)) == 0) { /* neither member nor local type */ - this.scope.problemReporter().disallowedThisParameter(this.receiver); - return; // No need to do further validation - } - enclosingReceiver = enclosingReceiver.enclosingType(); - } - - char[][] tokens = (this.receiver.qualifyingName == null) ? null : this.receiver.qualifyingName.getName(); - if (this.isConstructor()) { - if (tokens == null || tokens.length > 1 || !CharOperation.equals(enclosingReceiver.sourceName(), tokens[0])) { - this.scope.problemReporter().illegalQualifierForExplicitThis(this.receiver, enclosingReceiver); - this.receiver.qualifyingName = null; - } - } else if (tokens != null && tokens.length > 0) { - this.scope.problemReporter().illegalQualifierForExplicitThis2(this.receiver); - this.receiver.qualifyingName = null; - } - - if (TypeBinding.notEquals(enclosingReceiver, resolvedReceiverType)) { - this.scope.problemReporter().illegalTypeForExplicitThis(this.receiver, enclosingReceiver); - } - - if (this.receiver.type.hasNullTypeAnnotation(AnnotationPosition.ANY)) { - this.scope.problemReporter().nullAnnotationUnsupportedLocation(this.receiver.type); - } - if (this.scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled && this.receiver.type.resolvedType != null) { - for (AnnotationBinding annotationBinding : this.receiver.type.resolvedType.getTypeAnnotations()) { - ReferenceBinding annotationType = annotationBinding.getAnnotationType(); - if (annotationType != null && annotationType.hasTypeBit(TypeIds.BitOwningAnnotation)) { - this.binding.extendedTagBits = ExtendedTagBits.IsClosingMethod; - break; - } - } - } - } - public void resolveJavadoc() { - - if (this.binding == null) return; - if (this.javadoc != null) { - this.javadoc.resolve(this.scope); - return; - } - if (this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) { - // Set javadoc visibility - int javadocVisibility = this.binding.modifiers & ExtraCompilerModifiers.AccVisibilityMASK; - ClassScope classScope = this.scope.classScope(); - ProblemReporter reporter = this.scope.problemReporter(); - try { - int severity = reporter.computeSeverity(IProblem.JavadocMissing); - if (severity != ProblemSeverities.Ignore) { - if (classScope != null) { - javadocVisibility = Util.computeOuterMostVisibility(classScope.referenceType(), javadocVisibility); - } - int javadocModifiers = (this.binding.modifiers & ~ExtraCompilerModifiers.AccVisibilityMASK) | javadocVisibility; - reporter.javadocMissing(this.sourceStart, this.sourceEnd, severity, javadocModifiers); - } - } finally { - reporter.close(); - } - } - } - - public void resolveStatements() { - - if (this.statements != null) { - resolveStatements(this.statements, this.scope); - } else if ((this.bits & UndocumentedEmptyBlock) != 0) { - if (!this.isConstructor() || this.arguments != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=319626 - this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd+1); - } - } - } - - @Override - public void tagAsHavingErrors() { - this.ignoreFurtherInvestigation = true; - } - - @Override - public void tagAsHavingIgnoredMandatoryErrors(int problemId) { - // Nothing to do for this context; - } - - public void traverse( - ASTVisitor visitor, - ClassScope classScope) { - // default implementation: subclass will define it - } - - public TypeParameter[] typeParameters() { - return null; - } - - void validateNullAnnotations(boolean useTypeAnnotations) { - if (this.binding == null) return; - // null annotations on parameters? - if (!useTypeAnnotations) { - if (this.binding.parameterFlowBits != null) { - int length = this.binding.parameters.length; - for (int i=0; i wrong method resolution ? - * Bug 426764 - [1.8] Presence of conditional expression as method argument confuses compiler - * Bug 424930 - [1.8][compiler] Regression: "Cannot infer type arguments" error from compiler. - * Bug 427483 - [Java 8] Variables in lambdas sometimes can't be resolved - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 426996 - [1.8][inference] try to avoid method Expression.unresolve()? - * Bug 428352 - [1.8][compiler] Resolution errors don't always surface - * Bug 429203 - [1.8][compiler] NPE in AllocationExpression.binding - * Bug 429430 - [1.8] Lambdas and method reference infer wrong exception type with generics (RuntimeException instead of IOException) - * Bug 434297 - [1.8] NPE in LamdaExpression.analyseCode with lamda expression nested in a conditional expression - * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression - * Bug 448709 - [1.8][null] ensure we don't infer types that violate null constraints on a type parameter's bound - * Jesper S Moller - Contributions for - * bug 378674 - "The method can be declared as static" is wrong - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - * Bug 409245 - [1.8][compiler] Type annotations dropped when call is routed through a synthetic bridge method - * Till Brychcy - Contributions for - * bug 413460 - NonNullByDefault is not inherited to Constructors when accessed via Class File - * Lars Vogel - Contributions for - * Bug 473178 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.*; - -import java.util.HashMap; - -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; -import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable; - -public class AllocationExpression extends Expression implements IPolyExpression, Invocation { - - public TypeReference type; - public Expression[] arguments; - public MethodBinding binding; // exact binding resulting from lookup - MethodBinding syntheticAccessor; // synthetic accessor for inner-emulation - public TypeReference[] typeArguments; - public TypeBinding[] genericTypeArguments; - public FieldDeclaration enumConstant; // for enum constant initializations - protected TypeBinding typeExpected; // for <> inference - public boolean inferredReturnType; - - public FakedTrackingVariable closeTracker; // when allocation a Closeable store a pre-liminary tracking variable here - public ExpressionContext expressionContext = VANILLA_CONTEXT; - - // hold on to this context from invocation applicability inference until invocation type inference (per method candidate): - private SimpleLookupTable/**/ inferenceContexts; - public HashMap solutionsPerTargetType; - private InferenceContext18 outerInferenceContext; // resolving within the context of an outer (lambda) inference? - public boolean argsContainCast; - public TypeBinding[] argumentTypes = Binding.NO_PARAMETERS; - public boolean argumentsHaveErrors = false; - /** - * This flag avoids "Redundant specification of type arguments" if the target type was inferred in an outer context, - * possibly based on the provided type arguments of this allocation: - */ - public boolean expectedTypeWasInferred; - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // check captured variables are initialized in current context (26134) - checkCapturedLocalInitializationIfNecessary((ReferenceBinding)this.binding.declaringClass.erasure(), currentScope, flowInfo); - - // process arguments - if (this.arguments != null) { - boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; - boolean hasResourceWrapperType = analyseResources - && this.resolvedType instanceof ReferenceBinding - && ((ReferenceBinding)this.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable); - for (int i = 0, count = this.arguments.length; i < count; i++) { - Expression argument = this.arguments[i]; - flowInfo = - argument - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - // if argument is an AutoCloseable insert info that it *may* be closed (by the target method, i.e.) - if (analyseResources && !hasResourceWrapperType) { // allocation of wrapped closeables is analyzed specially - flowInfo = handleResourcePassedToInvocation(currentScope, this.binding, argument, i, flowContext, flowInfo); - } - argument.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - } - analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); - } - - // record some dependency information for exception types - ReferenceBinding[] thrownExceptions; - if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) { - if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6 - thrownExceptions = currentScope.environment().convertToRawTypes(this.binding.thrownExceptions, true, true); - } - // check exception handling - flowContext.checkExceptionHandlers( - thrownExceptions, - this, - flowInfo.unconditionalCopy(), - currentScope); - } - - // after having analysed exceptions above start tracking newly allocated resource: - if (currentScope.compilerOptions().analyseResourceLeaks && FakedTrackingVariable.isAnyCloseable(this.resolvedType)) - FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, flowContext, this); - - ReferenceBinding declaringClass = this.binding.declaringClass; - MethodScope methodScope = currentScope.methodScope(); - if ((declaringClass.isMemberType() && !declaringClass.isStatic()) || - (declaringClass.isLocalType() && !methodScope.isStatic && methodScope.isLambdaScope())) { - // allocating a non-static member type without an enclosing instance of parent type - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=335845 - currentScope.tagAsAccessingEnclosingInstanceStateOf(this.binding.declaringClass.enclosingType(), false /* type variable access */); - // Reviewed for https://bugs.eclipse.org/bugs/show_bug.cgi?id=378674 : - // The corresponding problem (when called from static) is not produced until during code generation - } - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - manageSyntheticAccessIfNecessary(currentScope, flowInfo); - - // account for possible exceptions thrown by the constructor - flowContext.recordAbruptExit(); // TODO whitelist of ctors that cannot throw any exc.?? - - return flowInfo; -} - -public void checkCapturedLocalInitializationIfNecessary(ReferenceBinding checkedType, BlockScope currentScope, FlowInfo flowInfo) { - if (((checkedType.tagBits & ( TagBits.AnonymousTypeMask|TagBits.LocalTypeMask)) == TagBits.LocalTypeMask) - && !currentScope.isDefinedInType(checkedType)) { // only check external allocations - NestedTypeBinding nestedType = (NestedTypeBinding) checkedType; - SyntheticArgumentBinding[] syntheticArguments = nestedType.syntheticOuterLocalVariables(); - if (syntheticArguments != null) - for (int i = 0, count = syntheticArguments.length; i < count; i++){ - SyntheticArgumentBinding syntheticArgument = syntheticArguments[i]; - LocalVariableBinding targetLocal; - if ((targetLocal = syntheticArgument.actualOuterLocalVariable) == null) continue; - if (targetLocal.declaration != null && !flowInfo.isDefinitelyAssigned(targetLocal)){ - currentScope.problemReporter().uninitializedLocalVariable(targetLocal, this, currentScope); - } - } - } -} - -public Expression enclosingInstance() { - return null; -} - -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - cleanUpInferenceContexts(); - if (!valueRequired) - currentScope.problemReporter().unusedObjectAllocation(this); - - int pc = codeStream.position; - MethodBinding codegenBinding = this.binding.original(); - ReferenceBinding allocatedType = codegenBinding.declaringClass; - - codeStream.new_(this.type, allocatedType); - boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; - if (valueRequired || isUnboxing) { - codeStream.dup(); - } - // better highlight for allocation: display the type individually - if (this.type != null) { // null for enum constant body - codeStream.recordPositionsFrom(pc, this.type.sourceStart); - } else { - // push enum constant name and ordinal - codeStream.ldc(String.valueOf(this.enumConstant.name)); - codeStream.generateInlinedValue(this.enumConstant.binding.id); - } - - // handling innerclass instance allocation - enclosing instance arguments - if (allocatedType.isNestedType()) { - codeStream.generateSyntheticEnclosingInstanceValues( - currentScope, - allocatedType, - enclosingInstance(), - this); - } - // generate the arguments for constructor - generateArguments(this.binding, this.arguments, currentScope, codeStream); - // handling innerclass instance allocation - outer local arguments - if (allocatedType.isNestedType()) { - codeStream.generateSyntheticOuterArgumentValues( - currentScope, - allocatedType, - this); - } - // invoke constructor - if (this.syntheticAccessor == null) { - codeStream.invoke(Opcodes.OPC_invokespecial, codegenBinding, null /* default declaringClass */, this.typeArguments); - } else { - // synthetic accessor got some extra arguments appended to its signature, which need values - for (int i = 0, - max = this.syntheticAccessor.parameters.length - codegenBinding.parameters.length; - i < max; - i++) { - codeStream.aconst_null(); - } - codeStream.invoke(Opcodes.OPC_invokespecial, this.syntheticAccessor, null /* default declaringClass */, this.typeArguments); - } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else if (isUnboxing) { - // conversion only generated if unboxing - codeStream.generateImplicitConversion(this.implicitConversion); - switch (postConversionType(currentScope).id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -/** - * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() - */ -@Override -public TypeBinding[] genericTypeArguments() { - return this.genericTypeArguments; -} - -@Override -public boolean isSuperAccess() { - return false; -} - -@Override -public boolean isTypeAccess() { - return true; -} - -/* Inner emulation consists in either recording a dependency - * link only, or performing one level of propagation. - * - * Dependency mechanism is used whenever dealing with source target - * types, since by the time we reach them, we might not yet know their - * exact need. - */ -public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return; - ReferenceBinding allocatedTypeErasure = (ReferenceBinding) this.binding.declaringClass.erasure(); - - // perform some emulation work in case there is some and we are inside a local type only - if (allocatedTypeErasure.isNestedType() - && (currentScope.enclosingSourceType().isLocalType() || currentScope.isLambdaSubscope())) { - - if (allocatedTypeErasure.isLocalType()) { - ((LocalTypeBinding) allocatedTypeErasure).addInnerEmulationDependent(currentScope, false); - // request cascade of accesses - } else { - // locally propagate, since we already now the desired shape for sure - currentScope.propagateInnerEmulation(allocatedTypeErasure, false); - // request cascade of accesses - } - } -} - -public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return; - // if constructor from parameterized type got found, use the original constructor at codegen time - MethodBinding codegenBinding = this.binding.original(); - - ReferenceBinding declaringClass; - if (codegenBinding.isPrivate() && - !currentScope.enclosingSourceType().isNestmateOf(this.binding.declaringClass) && - TypeBinding.notEquals(currentScope.enclosingSourceType(), (declaringClass = codegenBinding.declaringClass))) { - - // from 1.4 on, local type constructor can lose their private flag to ease emulation - if ((declaringClass.tagBits & TagBits.IsLocalType) != 0 && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) { - // constructor will not be dumped as private, no emulation required thus - codegenBinding.tagBits |= TagBits.ClearPrivateModifier; - } else { - this.syntheticAccessor = ((SourceTypeBinding) declaringClass).addSyntheticMethod(codegenBinding, isSuperAccess()); - currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this); - } - } -} - -@Override -public StringBuilder printExpression(int indent, StringBuilder output) { - if (this.type != null) { // type null for enum constant initializations - output.append("new "); //$NON-NLS-1$ - } - if (this.typeArguments != null) { - output.append('<'); - int max = this.typeArguments.length - 1; - for (int j = 0; j < max; j++) { - this.typeArguments[j].print(0, output); - output.append(", ");//$NON-NLS-1$ - } - this.typeArguments[max].print(0, output); - output.append('>'); - } - if (this.type != null) { // type null for enum constant initializations - this.type.printExpression(0, output); - } - output.append('('); - if (this.arguments != null) { - for (int i = 0; i < this.arguments.length; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.arguments[i].printExpression(0, output); - } - } - return output.append(')'); -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - // Propagate the type checking to the arguments, and check if the constructor is defined. - final boolean isDiamond = this.type != null && (this.type.bits & ASTNode.IsDiamond) != 0; - final CompilerOptions compilerOptions = scope.compilerOptions(); - long sourceLevel = compilerOptions.sourceLevel; - if (this.constant != Constant.NotAConstant) { - this.constant = Constant.NotAConstant; - if (this.type == null) { - // initialization of an enum constant - this.resolvedType = scope.enclosingReceiverType(); - } else { - this.resolvedType = this.type.resolveType(scope, true /* check bounds*/); - } - if (this.type != null) { - checkIllegalNullAnnotation(scope, this.resolvedType); - checkParameterizedAllocation: { - if (this.type instanceof ParameterizedQualifiedTypeReference) { // disallow new X.Y() - ReferenceBinding currentType = (ReferenceBinding)this.resolvedType; - if (currentType == null) return currentType; - do { - // isStatic() is answering true for toplevel types - if ((currentType.modifiers & ClassFileConstants.AccStatic) != 0) break checkParameterizedAllocation; - if (currentType.isRawType()) break checkParameterizedAllocation; - } while ((currentType = currentType.enclosingType())!= null); - ParameterizedQualifiedTypeReference qRef = (ParameterizedQualifiedTypeReference) this.type; - for (int i = qRef.typeArguments.length - 2; i >= 0; i--) { - if (qRef.typeArguments[i] != null) { - scope.problemReporter().illegalQualifiedParameterizedTypeAllocation(this.type, this.resolvedType); - break; - } - } - } - } - } - // will check for null after args are resolved - - // resolve type arguments (for generic constructor call) - if (this.typeArguments != null) { - int length = this.typeArguments.length; - this.argumentsHaveErrors = sourceLevel < ClassFileConstants.JDK1_5; - this.genericTypeArguments = new TypeBinding[length]; - for (int i = 0; i < length; i++) { - TypeReference typeReference = this.typeArguments[i]; - if ((this.genericTypeArguments[i] = typeReference.resolveType(scope, true /* check bounds*/)) == null) { - this.argumentsHaveErrors = true; - } - if (this.argumentsHaveErrors && typeReference instanceof Wildcard) { - scope.problemReporter().illegalUsageOfWildcard(typeReference); - } - } - if (isDiamond) { - scope.problemReporter().diamondNotWithExplicitTypeArguments(this.typeArguments); - return null; - } - if (this.argumentsHaveErrors) { - if (this.arguments != null) { // still attempt to resolve arguments - for (int i = 0, max = this.arguments.length; i < max; i++) { - this.arguments[i].resolveType(scope); - } - } - return null; - } - } - - // buffering the arguments' types - if (this.arguments != null) { - this.argumentsHaveErrors = false; - int length = this.arguments.length; - this.argumentTypes = new TypeBinding[length]; - for (int i = 0; i < length; i++) { - Expression argument = this.arguments[i]; - if (argument instanceof CastExpression) { - argument.bits |= DisableUnnecessaryCastCheck; // will check later on - this.argsContainCast = true; - } - argument.setExpressionContext(INVOCATION_CONTEXT); - if (this.arguments[i].resolvedType != null) - scope.problemReporter().genericInferenceError("Argument was unexpectedly found resolved", this); //$NON-NLS-1$ - if ((this.argumentTypes[i] = argument.resolveType(scope)) == null) { - this.argumentsHaveErrors = true; - } - } - if (this.argumentsHaveErrors) { - /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=345359, if arguments have errors, completely bail out in the <> case. - No meaningful type resolution is possible since inference of the elided types is fully tied to argument types. Do - not return the partially resolved type. - */ - if (isDiamond) { - return null; // not the partially cooked this.resolvedType - } - if (this.resolvedType instanceof ReferenceBinding) { - // record a best guess, for clients who need hint about possible constructor match - TypeBinding[] pseudoArgs = new TypeBinding[length]; - for (int i = length; --i >= 0;) { - pseudoArgs[i] = this.argumentTypes[i] == null ? TypeBinding.NULL : this.argumentTypes[i]; // replace args with errors with null type - } - this.binding = scope.findMethod((ReferenceBinding) this.resolvedType, TypeConstants.INIT, pseudoArgs, this, false); - if (this.binding != null && !this.binding.isValidBinding()) { - MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; - // record the closest match, for clients who may still need hint about possible method match - if (closestMatch != null) { - if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method - // shouldn't return generic method outside its context, rather convert it to raw method (175409) - closestMatch = scope.environment().createParameterizedGenericMethod(closestMatch.original(), (RawTypeBinding)null); - } - this.binding = closestMatch; - MethodBinding closestMatchOriginal = closestMatch.original(); - if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { - // ignore cases where method is used from within inside itself (e.g. direct recursions) - closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - } - } - } - return this.resolvedType; - } - } - if (this.resolvedType == null || !this.resolvedType.isValidBinding()) { - return null; - } - - // null type denotes fake allocation for enum constant inits - if (this.type != null && !this.resolvedType.canBeInstantiated()) { - scope.problemReporter().cannotInstantiate(this.type, this.resolvedType); - return this.resolvedType; - } - } - if (isDiamond) { - this.binding = inferConstructorOfElidedParameterizedType(scope); - if (this.binding == null || !this.binding.isValidBinding()) { - scope.problemReporter().cannotInferElidedTypes(this); - return this.resolvedType = null; - } - if (this.typeExpected == null && compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 && this.expressionContext.definesTargetType()) { - return new PolyTypeBinding(this); - } - this.resolvedType = this.type.resolvedType = this.binding.declaringClass; - // 15.9.3 - If the compile-time declaration is applicable by variable arity invocation... - if (this.binding.isVarargs()) { - TypeBinding lastArg = this.binding.parameters[this.binding.parameters.length - 1].leafComponentType(); - if (!lastArg.erasure().canBeSeenBy(scope)) { - scope.problemReporter().invalidType(this, new ProblemReferenceBinding(new char[][] {lastArg.readableName()}, (ReferenceBinding)lastArg, ProblemReasons.NotVisible)); - return this.resolvedType = null; - } - } - this.binding = resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope); - } else { - this.binding = findConstructorBinding(scope, this, (ReferenceBinding) this.resolvedType, this.argumentTypes); - } - if (!this.binding.isValidBinding()) { - if (this.binding.declaringClass == null) { - this.binding.declaringClass = (ReferenceBinding) this.resolvedType; - } - if (this.type != null && !this.type.resolvedType.isValidBinding()) { - return null; - } - scope.problemReporter().invalidConstructor(this, this.binding); - return this.resolvedType; - } - if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { - scope.problemReporter().missingTypeInConstructor(this, this.binding); - } - if (isMethodUseDeprecated(this.binding, scope, true, this)) { - scope.problemReporter().deprecatedMethod(this.binding, this); - } - if (checkInvocationArguments(scope, null, this.resolvedType, this.binding, this.arguments, this.argumentTypes, this.argsContainCast, this)) { - this.bits |= ASTNode.Unchecked; - } - if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { - scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(this.binding, this.genericTypeArguments, this.typeArguments); - } - if (!isDiamond && this.resolvedType.isParameterizedTypeWithActualArguments()) { - checkTypeArgumentRedundancy((ParameterizedTypeBinding) this.resolvedType, scope); - } - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { - ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope); - if (scope.environment().usesNullTypeAnnotations()) { - if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) { - TypeVariableBinding[] typeVariables = this.binding.original().typeVariables(); - for (int i = 0; i < this.typeArguments.length; i++) - this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i); - } - this.resolvedType = scope.environment().createNonNullAnnotatedType(this.resolvedType); - } - } - if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 && - this.binding.getTypeAnnotations() != Binding.NO_ANNOTATIONS) { - this.resolvedType = scope.environment().createAnnotatedType(this.resolvedType, this.binding.getTypeAnnotations()); - } - return this.resolvedType; -} - -/** - * Check if 'allocationType' illegally has a top-level null annotation. - */ -void checkIllegalNullAnnotation(BlockScope scope, TypeBinding allocationType) { - if (allocationType != null) { - // only check top-level null annotation (annots on details are OK): - long nullTagBits = allocationType.tagBits & TagBits.AnnotationNullMASK; - if (nullTagBits != 0) { - Annotation annotation = this.type.findAnnotation(nullTagBits); - if (annotation != null) - scope.problemReporter().nullAnnotationUnsupportedLocation(annotation); - } - } -} - -// For allocation expressions, boxing compatibility is same as vanilla compatibility, since java.lang's wrapper types are not generic. -@Override -public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope scope) { - if (isPolyExpression()) - return false; - if (this.argumentsHaveErrors || this.binding == null || - !this.binding.isValidBinding() || targetType == null || scope == null) - return false; - return isBoxingCompatible(this.resolvedType, targetType, this, scope); -} - -@Override -public boolean isCompatibleWith(TypeBinding targetType, final Scope scope) { - if (this.argumentsHaveErrors || this.binding == null || !this.binding.isValidBinding() || targetType == null || scope == null) - return false; - TypeBinding allocationType = this.resolvedType; - if (isPolyExpression()) { - TypeBinding originalExpectedType = this.typeExpected; - try { - MethodBinding method = this.solutionsPerTargetType != null ? this.solutionsPerTargetType.get(targetType) : null; - if (method == null) { - this.typeExpected = targetType; - method = inferConstructorOfElidedParameterizedType(scope); // caches result already. - if (method == null || !method.isValidBinding()) - return false; - } - allocationType = method.declaringClass; - } finally { - this.typeExpected = originalExpectedType; - } - } - return allocationType != null && allocationType.isCompatibleWith(targetType, scope); -} - -public MethodBinding inferConstructorOfElidedParameterizedType(final Scope scope) { - if (this.typeExpected != null && this.binding != null) { - MethodBinding cached = this.solutionsPerTargetType != null ? this.solutionsPerTargetType.get(this.typeExpected) : null; - if (cached != null) - return cached; - } - boolean[] inferredReturnTypeOut = new boolean[1]; - MethodBinding constructor = inferDiamondConstructor(scope, this, this.type.resolvedType, this.argumentTypes, inferredReturnTypeOut); - if (constructor != null) { - this.inferredReturnType = inferredReturnTypeOut[0]; - if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8 - && this.expressionContext == INVOCATION_CONTEXT && this.typeExpected == null) { // not ready for invocation type inference - if (constructor instanceof PolyParameterizedGenericMethodBinding) { - return constructor; // keep this placeholder binding, which also serves as a key into #inferenceContexts - } else if (constructor instanceof ParameterizedGenericMethodBinding) { - // force an inference context to be established for nested poly allocations (to be able to transfer b2), but avoid tunneling through overload resolution. We know this is the MSMB. - constructor = ParameterizedGenericMethodBinding.computeCompatibleMethod18(constructor.shallowOriginal(), this.argumentTypes, scope, this); - } - } else if (this.typeExpected != null && this.typeExpected.isProperType(true)) { - registerResult(this.typeExpected, constructor); - } - } - return constructor; -} - -public static MethodBinding inferDiamondConstructor(Scope scope, InvocationSite site, TypeBinding type, TypeBinding[] argumentTypes, boolean[] inferredReturnTypeOut) { - ReferenceBinding genericType = ((ParameterizedTypeBinding) type).genericType(); - ReferenceBinding enclosingType = type.enclosingType(); - ParameterizedTypeBinding allocationType = scope.environment().createParameterizedType(genericType, genericType.typeVariables(), enclosingType); - - // Given the allocation type and the arguments to the constructor, see if we can infer the constructor of the elided parameterized type. - MethodBinding factory = scope.getStaticFactory(allocationType, enclosingType, argumentTypes, site); - if (factory instanceof ParameterizedGenericMethodBinding && factory.isValidBinding()) { - if (site.invocationTargetType() == null && site.getExpressionContext().definesTargetType() && factory instanceof PolyParameterizedGenericMethodBinding) - return factory; // during applicability inference keep the PolyParameterizedGenericMethodBinding - ParameterizedGenericMethodBinding genericFactory = (ParameterizedGenericMethodBinding) factory; - inferredReturnTypeOut[0] = genericFactory.inferredReturnType; - SyntheticFactoryMethodBinding sfmb = (SyntheticFactoryMethodBinding) factory.original(); - TypeVariableBinding[] constructorTypeVariables = sfmb.getConstructor().typeVariables(); - TypeBinding [] constructorTypeArguments = constructorTypeVariables != null ? new TypeBinding[constructorTypeVariables.length] : Binding.NO_TYPES; - if (constructorTypeArguments.length > 0) - System.arraycopy(((ParameterizedGenericMethodBinding)factory).typeArguments, sfmb.typeVariables().length - constructorTypeArguments.length , - constructorTypeArguments, 0, constructorTypeArguments.length); - if (allocationType.isInterface()) { - ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) factory.returnType; - return new ParameterizedMethodBinding(parameterizedType, sfmb.getConstructor()); - } - return sfmb.applyTypeArgumentsOnConstructor(((ParameterizedTypeBinding)factory.returnType).arguments, constructorTypeArguments, genericFactory.inferredWithUncheckedConversion, site.invocationTargetType()); - } - return null; -} -public TypeBinding[] inferElidedTypes(final Scope scope) { - return inferElidedTypes((ParameterizedTypeBinding) this.resolvedType, scope); -} -public TypeBinding[] inferElidedTypes(ParameterizedTypeBinding parameterizedType, final Scope scope) { - - ReferenceBinding genericType = parameterizedType.genericType(); - ReferenceBinding enclosingType = parameterizedType.enclosingType(); - ParameterizedTypeBinding allocationType = scope.environment().createParameterizedType(genericType, genericType.typeVariables(), enclosingType); - - /* Given the allocation type and the arguments to the constructor, see if we can synthesize a generic static factory - method that would, given the argument types and the invocation site, manufacture a parameterized object of type allocationType. - If we are successful then by design and construction, the parameterization of the return type of the factory method is identical - to the types elided in the <>. - */ - MethodBinding factory = scope.getStaticFactory(allocationType, enclosingType, this.argumentTypes, this); - if (factory instanceof ParameterizedGenericMethodBinding && factory.isValidBinding()) { - ParameterizedGenericMethodBinding genericFactory = (ParameterizedGenericMethodBinding) factory; - this.inferredReturnType = genericFactory.inferredReturnType; - return ((ParameterizedTypeBinding)factory.returnType).arguments; - } - return null; -} - -public void checkTypeArgumentRedundancy(ParameterizedTypeBinding allocationType, final BlockScope scope) { - if (scope.enclosingClassScope().resolvingPolyExpressionArguments) // express arguments may end up influencing the target type - return; // so, conservatively shut off diagnostic. - if ((scope.problemReporter().computeSeverity(IProblem.RedundantSpecificationOfTypeArguments) == ProblemSeverities.Ignore) || scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_7) return; - if (allocationType.arguments == null) return; // raw binding - if (this.genericTypeArguments != null) return; // diamond can't occur with explicit type args for constructor - if (this.type == null) return; - if (this.argumentTypes == Binding.NO_PARAMETERS && this.typeExpected instanceof ParameterizedTypeBinding) { - ParameterizedTypeBinding expected = (ParameterizedTypeBinding) this.typeExpected; - if (expected.arguments != null && allocationType.arguments.length == expected.arguments.length) { - // check the case when no ctor takes no params and inference uses the expected type directly - // eg. X x = new X() - int i; - for (i = 0; i < allocationType.arguments.length; i++) { - if (TypeBinding.notEquals(allocationType.arguments[i], expected.arguments[i])) - break; - } - if (i == allocationType.arguments.length) { - reportTypeArgumentRedundancyProblem(allocationType, scope); - return; - } - } - } - TypeBinding [] inferredTypes; - int previousBits = this.type.bits; - try { - // checking for redundant type parameters must fake a diamond, - // so we infer the same results as we would get with a diamond in source code: - this.type.bits |= IsDiamond; - inferredTypes = inferElidedTypes(allocationType, scope); - } finally { - // reset effects of inference - this.type.bits = previousBits; - } - if (inferredTypes == null) { - return; - } - for (int i = 0; i < inferredTypes.length; i++) { - if (TypeBinding.notEquals(inferredTypes[i], allocationType.arguments[i])) - return; - } - reportTypeArgumentRedundancyProblem(allocationType, scope); -} - -protected void reportTypeArgumentRedundancyProblem(ParameterizedTypeBinding allocationType, final BlockScope scope) { - scope.problemReporter().redundantSpecificationOfTypeArguments(this.type, allocationType.arguments); -} - -@Override -public void setActualReceiverType(ReferenceBinding receiverType) { - // ignored -} - -@Override -public void setDepth(int i) { - // ignored -} - -@Override -public void setFieldIndex(int i) { - // ignored -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.typeArguments != null) { - for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) { - this.typeArguments[i].traverse(visitor, scope); - } - } - if (this.type != null) { // enum constant scenario - this.type.traverse(visitor, scope); - } - if (this.arguments != null) { - for (int i = 0, argumentsLength = this.arguments.length; i < argumentsLength; i++) - this.arguments[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); -} -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#setExpectedType(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) - */ -@Override -public void setExpectedType(TypeBinding expectedType) { - this.typeExpected = expectedType; -} - -@Override -public void setExpressionContext(ExpressionContext context) { - this.expressionContext = context; -} - -@Override -public boolean isPolyExpression() { - return isPolyExpression(this.binding); -} -@Override -public boolean isPolyExpression(MethodBinding method) { - return (this.expressionContext == ASSIGNMENT_CONTEXT || this.expressionContext == INVOCATION_CONTEXT) && - this.type != null && (this.type.bits & ASTNode.IsDiamond) != 0; -} - -/** - * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#invocationTargetType() - */ -@Override -public TypeBinding invocationTargetType() { - return this.typeExpected; -} - -@Override -public boolean statementExpression() { - return ((this.bits & ASTNode.ParenthesizedMASK) == 0); -} - -//-- interface Invocation: -- -@Override -public MethodBinding binding() { - return this.binding; -} -@Override -public Expression[] arguments() { - return this.arguments; -} - -@Override -public void registerInferenceContext(ParameterizedGenericMethodBinding method, InferenceContext18 infCtx18) { - if (this.inferenceContexts == null) - this.inferenceContexts = new SimpleLookupTable(); - this.inferenceContexts.put(method, infCtx18); -} - -@Override -public void registerResult(TypeBinding targetType, MethodBinding method) { - if (method != null && method.isConstructor()) { // ignore the factory. - if (this.solutionsPerTargetType == null) - this.solutionsPerTargetType = new HashMap<>(); - this.solutionsPerTargetType.put(targetType, method); - } -} - -@Override -public InferenceContext18 getInferenceContext(ParameterizedMethodBinding method) { - if (this.inferenceContexts == null) - return null; - return (InferenceContext18) this.inferenceContexts.get(method); -} - -@Override -public void cleanUpInferenceContexts() { - if (this.inferenceContexts == null) - return; - for (Object value : this.inferenceContexts.valueTable) - if (value != null) - ((InferenceContext18) value).cleanUp(); - this.inferenceContexts = null; - this.outerInferenceContext = null; - this.solutionsPerTargetType = null; -} - -//-- interface InvocationSite: -- -@Override -public ExpressionContext getExpressionContext() { - return this.expressionContext; -} -@Override -public InferenceContext18 freshInferenceContext(Scope scope) { - return new InferenceContext18(scope, this.arguments, this, this.outerInferenceContext); -} -@Override -public int nameSourceStart() { - if (this.enumConstant != null) - return this.enumConstant.sourceStart; - else - return this.type.sourceStart; -} -@Override -public int nameSourceEnd() { - if (this.enumConstant != null) - return this.enumConstant.sourceEnd; - else - return this.type.sourceEnd; -} -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Annotation.java deleted file mode 100644 index 744acd2..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Annotation.java +++ /dev/null @@ -1,1440 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 365662 - [compiler][null] warn on contradictory and redundant null annotations - * bug 331649 - [compiler][null] consider null annotations for fields - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 424728 - [1.8][null] Unexpected error: The nullness annotation 'XXXX' is not applicable at this location - * Bug 392245 - [1.8][compiler][null] Define whether / how @NonNullByDefault applies to TYPE_USE locations - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations - * Bug 457210 - [1.8][compiler][null] Wrong Nullness errors given on full build build but not on incremental build? - * Bug 469584 - ClassCastException in Annotation.detectStandardAnnotation (320) - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - * Bug 409517 - [1.8][compiler] Type annotation problems on more elaborate array references - * Bug 415397 - [1.8][compiler] Type Annotations on wildcard type argument dropped - * Bug 414384 - [1.8] type annotation on abbreviated inner class is not marked as inner type - * Jesper S Moller - Contributions for - * Bug 412153 - [1.8][compiler] Check validity of annotations which may be repeatable - * Bug 412151 - [1.8][compiler] Check repeating annotation's collection type - * Bug 412149 - [1.8][compiler] Emit repeated annotations into the designated container - * Bug 419209 - [1.8] Repeating container annotations should be rejected in the presence of annotation it contains - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.Stack; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.env.EnumConstantSignature; -import org.eclipse.jdt.internal.compiler.impl.BooleanConstant; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.IrritantSet; -import org.eclipse.jdt.internal.compiler.lookup.*; - -/** - * Annotation - */ -@SuppressWarnings({"rawtypes", "unchecked"}) -public abstract class Annotation extends Expression { - - Annotation persistibleAnnotation = this; // Emit this into class file, unless this is a repeating annotation, in which case package this into the designated container. - - /** - * Return the location for the corresponding annotation inside the type reference, null if none. - */ - public static int[] getLocations( - final Expression reference, - final Annotation annotation) { - - class LocationCollector extends ASTVisitor { - Stack typePathEntries; - Annotation searchedAnnotation; - boolean continueSearch = true; - - public LocationCollector(Annotation currentAnnotation) { - this.typePathEntries = new Stack(); - this.searchedAnnotation = currentAnnotation; - } - - private int[] computeNestingDepth(TypeReference typeReference) { - TypeBinding type = typeReference.resolvedType == null ? null : typeReference.resolvedType.leafComponentType(); - int[] nestingDepths = new int[typeReference.getAnnotatableLevels()]; - if (type != null && type.isNestedType()) { - int depth = 0; - TypeBinding currentType = type; - while (currentType != null) { - depth += (currentType.isStatic()) ? 0 : 1; - currentType = currentType.enclosingType(); - } - // Work backwards computing whether a INNER_TYPE entry is required for each level - int counter = nestingDepths.length - 1; - while (type != null && counter >= 0) { - nestingDepths[counter--] = depth; - depth -= type.isStatic() ? 0 : 1; - type = type.enclosingType(); - } - } - return nestingDepths; - } - - - private void inspectAnnotations(Annotation [] annotations) { - for (int i = 0, length = annotations == null ? 0 : annotations.length; this.continueSearch && i < length; i++) { - if (annotations[i] == this.searchedAnnotation) { - this.continueSearch = false; - break; - } - } - } - - private void inspectArrayDimensions(Annotation [][] annotationsOnDimensions, int dimensions) { - for (int i = 0; this.continueSearch && i < dimensions; i++) { - Annotation[] annotations = annotationsOnDimensions == null ? null : annotationsOnDimensions[i]; - inspectAnnotations(annotations); - if (!this.continueSearch) return; - this.typePathEntries.push(TYPE_PATH_ELEMENT_ARRAY); - } - } - - private void inspectTypeArguments(TypeReference[] typeReferences) { - for (int i = 0, length = typeReferences == null ? 0 : typeReferences.length; this.continueSearch && i < length; i++) { - int size = this.typePathEntries.size(); - this.typePathEntries.add(new int[]{3,i}); - typeReferences[i].traverse(this, (BlockScope) null); - if (!this.continueSearch) return; - this.typePathEntries.setSize(size); - } - } - - public boolean visit(TypeReference typeReference, BlockScope scope) { - if (this.continueSearch) { - inspectArrayDimensions(typeReference.getAnnotationsOnDimensions(), typeReference.dimensions()); - if (this.continueSearch) { - int[] nestingDepths = computeNestingDepth(typeReference); - Annotation[][] annotations = typeReference.annotations; - TypeReference [][] typeArguments = typeReference.getTypeArguments(); - int levels = typeReference.getAnnotatableLevels(); - int size = this.typePathEntries.size(); - for (int i = levels - 1; this.continueSearch && i >= 0; i--) { // traverse outwards, see comment below about type annotations from SE7 locations. - this.typePathEntries.setSize(size); - for (int j = 0, depth = nestingDepths[i]; j < depth; j++) - this.typePathEntries.add(TYPE_PATH_INNER_TYPE); - if (annotations != null) - inspectAnnotations(annotations[i]); - if (this.continueSearch && typeArguments != null) { - inspectTypeArguments(typeArguments[i]); - } - } - } - } - return false; // if annotation is not found in the type reference, it must be one from SE7 location, typePathEntries captures the proper path entries for them. - } - @Override - public boolean visit(SingleTypeReference typeReference, BlockScope scope) { - return visit((TypeReference) typeReference, scope); - } - - @Override - public boolean visit(ArrayTypeReference typeReference, BlockScope scope) { - return visit((TypeReference) typeReference, scope); - } - - @Override - public boolean visit(ParameterizedSingleTypeReference typeReference, BlockScope scope) { - return visit((TypeReference) typeReference, scope); - } - - @Override - public boolean visit(QualifiedTypeReference typeReference, BlockScope scope) { - return visit((TypeReference) typeReference, scope); - } - - @Override - public boolean visit(ArrayQualifiedTypeReference typeReference, BlockScope scope) { - return visit((TypeReference) typeReference, scope); - } - - @Override - public boolean visit(ParameterizedQualifiedTypeReference typeReference, BlockScope scope) { - return visit((TypeReference) typeReference, scope); - } - - @Override - public boolean visit(Wildcard typeReference, BlockScope scope) { - visit((TypeReference) typeReference, scope); - if (this.continueSearch) { - TypeReference bound = typeReference.bound; - if (bound != null) { - int size = this.typePathEntries.size(); - this.typePathEntries.push(TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND); - bound.traverse(this, scope); - if (this.continueSearch) - this.typePathEntries.setSize(size); - } - } - return false; - } - - @Override - public boolean visit(ArrayAllocationExpression allocationExpression, BlockScope scope) { - if (this.continueSearch) { - inspectArrayDimensions(allocationExpression.getAnnotationsOnDimensions(), allocationExpression.dimensions.length); - if (this.continueSearch) { - allocationExpression.type.traverse(this, scope); - } - if (this.continueSearch) throw new IllegalStateException(); - } - return false; - } - - @Override - public String toString() { - StringBuilder buffer = new StringBuilder(); - buffer - .append("search location for ") //$NON-NLS-1$ - .append(this.searchedAnnotation) - .append("\ncurrent type_path entries : "); //$NON-NLS-1$ - for (int i = 0, maxi = this.typePathEntries.size(); i < maxi; i++) { - int[] typePathEntry = (int[]) this.typePathEntries.get(i); - buffer - .append('(') - .append(typePathEntry[0]) - .append(',') - .append(typePathEntry[1]) - .append(')'); - } - return String.valueOf(buffer); - } - } - if (reference == null) return null; - LocationCollector collector = new LocationCollector(annotation); - reference.traverse(collector, (BlockScope) null); - if (collector.typePathEntries.isEmpty()) { - return null; - } - int size = collector.typePathEntries.size(); - int[] result = new int[size*2]; - int offset=0; - for (int i = 0; i < size; i++) { - int[] pathElement = (int[])collector.typePathEntries.get(i); - result[offset++] = pathElement[0]; - result[offset++] = pathElement[1]; - } - return result; - } - - final static MemberValuePair[] NoValuePairs = new MemberValuePair[0]; - - static final int[] TYPE_PATH_ELEMENT_ARRAY = new int[]{0,0}; - static final int[] TYPE_PATH_INNER_TYPE = new int[]{1,0}; - static final int[] TYPE_PATH_ANNOTATION_ON_WILDCARD_BOUND = new int[]{2,0}; - - public int declarationSourceEnd; - public Binding recipient; - - public TypeReference type; - /** - * The representation of this annotation in the type system. - */ - protected AnnotationBinding compilerAnnotation = null; - - public static long getRetentionPolicy(char[] policyName) { - if (policyName == null || policyName.length == 0) - return 0; - switch(policyName[0]) { - case 'C' : - if (CharOperation.equals(policyName, TypeConstants.UPPER_CLASS)) - return TagBits.AnnotationClassRetention; - break; - case 'S' : - if (CharOperation.equals(policyName, TypeConstants.UPPER_SOURCE)) - return TagBits.AnnotationSourceRetention; - break; - case 'R' : - if (CharOperation.equals(policyName, TypeConstants.UPPER_RUNTIME)) - return TagBits.AnnotationRuntimeRetention; - break; - } - return 0; // unknown - } - - public static long getTargetElementType(char[] elementName) { - if (elementName == null || elementName.length == 0) - return 0; - switch(elementName[0]) { - case 'A' : - if (CharOperation.equals(elementName, TypeConstants.UPPER_ANNOTATION_TYPE)) - return TagBits.AnnotationForAnnotationType; - break; - case 'C' : - if (CharOperation.equals(elementName, TypeConstants.UPPER_CONSTRUCTOR)) - return TagBits.AnnotationForConstructor; - break; - case 'F' : - if (CharOperation.equals(elementName, TypeConstants.UPPER_FIELD)) - return TagBits.AnnotationForField; - break; - case 'L' : - if (CharOperation.equals(elementName, TypeConstants.UPPER_LOCAL_VARIABLE)) - return TagBits.AnnotationForLocalVariable; - break; - case 'M' : - if (CharOperation.equals(elementName, TypeConstants.UPPER_METHOD)) - return TagBits.AnnotationForMethod; - else if (CharOperation.equals(elementName, TypeConstants.UPPER_MODULE)) - return TagBits.AnnotationForModule; - break; - case 'P' : - if (CharOperation.equals(elementName, TypeConstants.UPPER_PARAMETER)) - return TagBits.AnnotationForParameter; - else if (CharOperation.equals(elementName, TypeConstants.UPPER_PACKAGE)) - return TagBits.AnnotationForPackage; - break; - case 'R' : - if (CharOperation.equals(elementName, TypeConstants.UPPER_RECORD_COMPONENT)) - return TagBits.AnnotationForRecordComponent; - break; - case 'T' : - if (CharOperation.equals(elementName, TypeConstants.TYPE)) - return TagBits.AnnotationForType; - if (CharOperation.equals(elementName, TypeConstants.TYPE_USE_TARGET)) - return TagBits.AnnotationForTypeUse; - if (CharOperation.equals(elementName, TypeConstants.TYPE_PARAMETER_TARGET)) - return TagBits.AnnotationForTypeParameter; - break; - } - return 0; // unknown - } - - public ElementValuePair[] computeElementValuePairs() { - return Binding.NO_ELEMENT_VALUE_PAIRS; - } - - /** - * Compute the bit pattern for recognized standard annotations the compiler may need to act upon. - * The lower bits (Binding.NullnessDefaultMASK) do not belong in tagBits, but in defaultNullness. - */ - private long detectStandardAnnotation(Scope scope, ReferenceBinding annotationType, MemberValuePair valueAttribute) { - long tagBits = 0; - switch (annotationType.id) { - // retention annotation - case TypeIds.T_JavaLangAnnotationRetention : - if (valueAttribute != null) { - Expression expr = valueAttribute.value; - if ((expr.bits & Binding.VARIABLE) == Binding.FIELD && expr instanceof Reference) { // anything but Reference would be a type error anyway - FieldBinding field = ((Reference)expr).fieldBinding(); - if (field != null && field.declaringClass.id == T_JavaLangAnnotationRetentionPolicy) { - tagBits |= getRetentionPolicy(field.name); - } - } - } - break; - // target annotation - case TypeIds.T_JavaLangAnnotationTarget : - tagBits |= TagBits.AnnotationTarget; // target specified (could be empty) - if (valueAttribute != null) { - Expression expr = valueAttribute.value; - if (expr instanceof ArrayInitializer) { - ArrayInitializer initializer = (ArrayInitializer) expr; - final Expression[] expressions = initializer.expressions; - if (expressions != null) { - for (int i = 0, length = expressions.length; i < length; i++) { - Expression initExpr = expressions[i]; - if ((initExpr.bits & Binding.VARIABLE) == Binding.FIELD) { - FieldBinding field = ((Reference) initExpr).fieldBinding(); - if (field != null && field.declaringClass.id == T_JavaLangAnnotationElementType) { - long element = getTargetElementType(field.name); - if ((tagBits & element) != 0) { - scope.problemReporter().duplicateTargetInTargetAnnotation(annotationType, (NameReference)initExpr); - } else { - tagBits |= element; - } - } - } - } - } - } else if ((expr.bits & Binding.VARIABLE) == Binding.FIELD) { - FieldBinding field = ((Reference) expr).fieldBinding(); - if (field != null && field.declaringClass.id == T_JavaLangAnnotationElementType) { - tagBits |= getTargetElementType(field.name); - } - } - } - break; - case TypeIds.T_JdkInternalPreviewFeature : - tagBits |= TagBits.AnnotationPreviewFeature; - for (MemberValuePair memberValuePair : memberValuePairs()) { - if (CharOperation.equals(memberValuePair.name, TypeConstants.ESSENTIAL_API)) { - if (memberValuePair.value instanceof TrueLiteral) { - tagBits |= TagBits.EssentialAPI; - } - } - } - break; - // marker annotations - case TypeIds.T_JavaLangDeprecated : - tagBits |= TagBits.AnnotationDeprecated; - if (scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK9) { - for (MemberValuePair memberValuePair : memberValuePairs()) { - if (CharOperation.equals(memberValuePair.name, TypeConstants.FOR_REMOVAL)) { - if (memberValuePair.value instanceof TrueLiteral) - tagBits |= TagBits.AnnotationTerminallyDeprecated; - break; - } - } - } - break; - case TypeIds.T_JavaLangAnnotationDocumented : - tagBits |= TagBits.AnnotationDocumented; - break; - case TypeIds.T_JavaLangAnnotationInherited : - tagBits |= TagBits.AnnotationInherited; - break; - case TypeIds.T_JavaLangOverride : - tagBits |= TagBits.AnnotationOverride; - break; - case TypeIds.T_JavaLangFunctionalInterface : - tagBits |= TagBits.AnnotationFunctionalInterface; - break; - case TypeIds.T_JavaLangAnnotationRepeatable: - tagBits |= TagBits.AnnotationRepeatable; - break; - case TypeIds.T_JavaLangSuppressWarnings : - tagBits |= TagBits.AnnotationSuppressWarnings; - break; - case TypeIds.T_JavaLangSafeVarargs : - tagBits |= TagBits.AnnotationSafeVarargs; - break; - case TypeIds.T_JavaLangInvokeMethodHandlePolymorphicSignature : - tagBits |= TagBits.AnnotationPolymorphicSignature; - break; - } - CompilerOptions compilerOptions = scope.compilerOptions(); - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { - if (annotationType.hasNullBit(TypeIds.BitNullableAnnotation)) { - tagBits |= TagBits.AnnotationNullable; - } else if (annotationType.hasNullBit(TypeIds.BitNonNullAnnotation)) { - tagBits |= TagBits.AnnotationNonNull; - } else if (annotationType.hasNullBit(TypeIds.BitNonNullByDefaultAnnotation)) { - tagBits |= determineNonNullByDefaultTagBits(annotationType, valueAttribute); - } - } - if (compilerOptions.isAnnotationBasedResourceAnalysisEnabled) { - if (annotationType.hasTypeBit(TypeIds.BitOwningAnnotation)) { - tagBits |= TagBits.AnnotationOwning; - } else if (annotationType.hasTypeBit(TypeIds.BitNotOwningAnnotation)) { - tagBits |= TagBits.AnnotationNotOwning; - } - } - return tagBits; - } - - private long determineNonNullByDefaultTagBits(ReferenceBinding annotationType, MemberValuePair valueAttribute) { - long tagBits = 0; - Object value = null; - if (valueAttribute != null) { - if (valueAttribute.compilerElementPair != null) - value = valueAttribute.compilerElementPair.value; - } else { // fetch default value - TODO: cache it? - MethodBinding[] methods = annotationType.methods(); - if (methods != null && methods.length == 1) - value = methods[0].getDefaultValue(); - else - tagBits |= Binding.DefaultLocationsForTrueValue; // custom unconfigurable NNBD - } - if (value instanceof BooleanConstant) { - // boolean value is used for declaration annotations, signal using the annotation tag bit: - tagBits |= ((BooleanConstant)value).booleanValue() ? Binding.DefaultLocationsForTrueValue : Binding.NULL_UNSPECIFIED_BY_DEFAULT; - } else if (value != null) { - // non-boolean value signals type annotations, evaluate from DefaultLocation[] to bitvector a la Binding#NullnessDefaultMASK: - tagBits |= nullLocationBitsFromAnnotationValue(value); - } else { - int result = BinaryTypeBinding.evaluateTypeQualifierDefault(annotationType); - if(result != 0) { - return result; - } - } - return tagBits; - } - - /** - * Convert the value() attribute of @NonNullByDefault into a bitvector a la {@link Binding#NullnessDefaultMASK}. - * This method understands value encodings from source and binary types. - * - * pre: null annotation analysis is enabled - */ - public static int nullLocationBitsFromAnnotationValue(Object value) { - if (value instanceof Object[]) { - if (((Object[]) value).length == 0) { // ({}) - return Binding.NULL_UNSPECIFIED_BY_DEFAULT; - } else { // ({vals...}) - int bits = 0; - for (Object single : (Object[])value) - bits |= evaluateDefaultNullnessLocation(single); - return bits; - } - } else { // (val) - return evaluateDefaultNullnessLocation(value); - } - } - - private static int evaluateDefaultNullnessLocation(Object value) { - char[] name = null; - if (value instanceof FieldBinding) { - name = ((FieldBinding) value).name; - } else if (value instanceof EnumConstantSignature) { - name = ((EnumConstantSignature) value).getEnumConstantName(); - } else if (value instanceof ElementValuePair.UnresolvedEnumConstant) { - name = ((ElementValuePair.UnresolvedEnumConstant) value).getEnumConstantName(); - } else if (value instanceof BooleanConstant) { - return ((BooleanConstant)value).booleanValue() ? Binding.DefaultLocationsForTrueValue : Binding.NULL_UNSPECIFIED_BY_DEFAULT; - } - if (name != null) { - switch (name.length) { - case 5: - if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__FIELD)) - return Binding.DefaultLocationField; - break; - case 9: - if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__PARAMETER)) - return Binding.DefaultLocationParameter; - break; - case 10: - if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__TYPE_BOUND)) - return Binding.DefaultLocationTypeBound; - break; - case 11: - if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__RETURN_TYPE)) - return Binding.DefaultLocationReturnType; - break; - case 13 : - if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__TYPE_ARGUMENT)) - return Binding.DefaultLocationTypeArgument; - break; - case 14 : - if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__TYPE_PARAMETER)) - return Binding.DefaultLocationTypeParameter; - if (CharOperation.equals(name, TypeConstants.DEFAULT_LOCATION__ARRAY_CONTENTS)) - return Binding.DefaultLocationArrayContents; - break; - } - } - return 0; - } - - public static int nullLocationBitsFromElementTypeAnnotationValue(Object value) { - if (value instanceof Object[]) { - if (((Object[]) value).length == 0) { // ({}) - return Binding.NULL_UNSPECIFIED_BY_DEFAULT; - } else { // ({vals...}) - int bits = 0; - for (Object single : (Object[])value) - bits |= evaluateElementTypeNullnessLocation(single); - return bits; - } - } else { // (val) - return evaluateElementTypeNullnessLocation(value); - } - } - - private static int evaluateElementTypeNullnessLocation(Object value) { - char[] name = null; - if (value instanceof FieldBinding) { - name = ((FieldBinding) value).name; - } else if (value instanceof EnumConstantSignature) { - name = ((EnumConstantSignature) value).getEnumConstantName(); - } else if (value instanceof ElementValuePair.UnresolvedEnumConstant) { - name = ((ElementValuePair.UnresolvedEnumConstant) value).getEnumConstantName(); - } - if (name != null) { - switch (name.length) { - case 5: - if (CharOperation.equals(name, TypeConstants.UPPER_FIELD)) - return Binding.DefaultLocationField; - break; - case 6: - if (CharOperation.equals(name, TypeConstants.UPPER_METHOD)) - return Binding.DefaultLocationReturnType; - break; - case 9: - if (CharOperation.equals(name, TypeConstants.UPPER_PARAMETER)) - return Binding.DefaultLocationParameter; - break; - } - } - return 0; - } - - - static String getRetentionName(long tagBits) { - if ((tagBits & TagBits.AnnotationRuntimeRetention) == TagBits.AnnotationRuntimeRetention) { - // TagBits.AnnotationRuntimeRetention combines both TagBits.AnnotationClassRetention & TagBits.AnnotationSourceRetention - return new String(UPPER_RUNTIME); - } else if ((tagBits & TagBits.AnnotationSourceRetention) != 0) { - return new String(UPPER_SOURCE); - } else { - return new String(TypeConstants.UPPER_CLASS); - } - } - - private static long getAnnotationRetention(ReferenceBinding binding) { - long retention = binding.getAnnotationTagBits() & TagBits.AnnotationRetentionMASK; - // Retention defaults to CLASS - return retention != 0 ? retention : TagBits.AnnotationClassRetention; - } - - public void checkRepeatableMetaAnnotation(BlockScope scope) { - - // `this' is the @Repeatable meta annotation, its recipient is the *repeatable* annotation type - we are at the declaration site, not the repeating use site. - - ReferenceBinding repeatableAnnotationType = (ReferenceBinding) this.recipient; // know it to be an annotation type. On target miss we don't get here - - MemberValuePair[] valuePairs = this.memberValuePairs(); - if (valuePairs == null || valuePairs.length != 1) - return; - - Object value = valuePairs[0].compilerElementPair.value; - if (!(value instanceof ReferenceBinding)) - return; // Has deeper problems, will bark elsewhere. - ReferenceBinding containerAnnotationType = (ReferenceBinding) value; - if (!containerAnnotationType.isAnnotationType()) - return; // Has deeper problems, will bark elsewhere. - - repeatableAnnotationType.setContainerAnnotationType(containerAnnotationType); // For now. May be reset later to PRB in case of problems. - checkContainerAnnotationType(valuePairs[0], scope, containerAnnotationType, repeatableAnnotationType, false); // false => not use site, i.e declaration site error reporting requested. - } - - public static void checkContainerAnnotationType(ASTNode culpritNode, BlockScope scope, ReferenceBinding containerAnnotationType, ReferenceBinding repeatableAnnotationType, boolean useSite) { - MethodBinding[] annotationMethods = containerAnnotationType.methods(); - boolean sawValue = false; - for (int i = 0, length = annotationMethods.length; i < length; ++i) { - MethodBinding method = annotationMethods[i]; - if (CharOperation.equals(method.selector, TypeConstants.VALUE)) { - sawValue = true; - if (method.returnType.isArrayType() && method.returnType.dimensions() == 1) { - ArrayBinding array = (ArrayBinding) method.returnType; - if (TypeBinding.equalsEquals(array.elementsType(), repeatableAnnotationType)) continue; - } - repeatableAnnotationType.tagAsHavingDefectiveContainerType(); - scope.problemReporter().containerAnnotationTypeHasWrongValueType(culpritNode, containerAnnotationType, repeatableAnnotationType, method.returnType); - } else { - // Not the value() - must have default (or else isn't suitable as container) - if ((method.modifiers & ClassFileConstants.AccAnnotationDefault) == 0) { - repeatableAnnotationType.tagAsHavingDefectiveContainerType(); - scope.problemReporter().containerAnnotationTypeHasNonDefaultMembers(culpritNode, containerAnnotationType, method.selector); - } - } - } - if (!sawValue) { - repeatableAnnotationType.tagAsHavingDefectiveContainerType(); - scope.problemReporter().containerAnnotationTypeMustHaveValue(culpritNode, containerAnnotationType); - } - - if (useSite) - checkContainingAnnotationTargetAtUse((Annotation) culpritNode, scope, containerAnnotationType, repeatableAnnotationType); - else - checkContainerAnnotationTypeTarget(culpritNode, scope, containerAnnotationType, repeatableAnnotationType); - - long annotationTypeBits = getAnnotationRetention(repeatableAnnotationType); - long containerTypeBits = getAnnotationRetention(containerAnnotationType); - // Due to clever layout of the bits, we can compare the absolute value directly - if (containerTypeBits < annotationTypeBits) { - repeatableAnnotationType.tagAsHavingDefectiveContainerType(); - scope.problemReporter().containerAnnotationTypeHasShorterRetention(culpritNode, repeatableAnnotationType, getRetentionName(annotationTypeBits), containerAnnotationType, getRetentionName(containerTypeBits)); - } - - if ((repeatableAnnotationType.getAnnotationTagBits() & TagBits.AnnotationDocumented) != 0 && (containerAnnotationType.getAnnotationTagBits() & TagBits.AnnotationDocumented) == 0) { - repeatableAnnotationType.tagAsHavingDefectiveContainerType(); - scope.problemReporter().repeatableAnnotationTypeIsDocumented(culpritNode, repeatableAnnotationType, containerAnnotationType); - } - - if ((repeatableAnnotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) != 0 && (containerAnnotationType.getAnnotationTagBits() & TagBits.AnnotationInherited) == 0) { - repeatableAnnotationType.tagAsHavingDefectiveContainerType(); - scope.problemReporter().repeatableAnnotationTypeIsInherited(culpritNode, repeatableAnnotationType, containerAnnotationType); - } - } - - // This is for error reporting for bad targets at annotation type declaration site (as opposed to the repeat site) - private static void checkContainerAnnotationTypeTarget(ASTNode culpritNode, Scope scope, ReferenceBinding containerType, ReferenceBinding repeatableAnnotationType) { - long tagBits = repeatableAnnotationType.getAnnotationTagBits(); - if ((tagBits & TagBits.AnnotationTargetMASK) == 0) - tagBits = TagBits.AnnotationForDeclarationMASK; // absence of @Target meta-annotation implies all declaration targets not all targets. - - long containerAnnotationTypeTypeTagBits = containerType.getAnnotationTagBits(); - if ((containerAnnotationTypeTypeTagBits & TagBits.AnnotationTargetMASK) == 0) - containerAnnotationTypeTypeTagBits = TagBits.AnnotationForDeclarationMASK; - - final long targets = tagBits & TagBits.AnnotationTargetMASK; - final long containerAnnotationTypeTargets = containerAnnotationTypeTypeTagBits & TagBits.AnnotationTargetMASK; - - if ((containerAnnotationTypeTargets & ~targets) != 0) { - class MissingTargetBuilder { - StringBuilder targetBuffer = new StringBuilder(); - void check(long targetMask, char[] targetName) { - if ((containerAnnotationTypeTargets & targetMask & ~targets) != 0) { - // if targetMask equals TagBits.AnnotationForType implies - // TagBits.AnnotationForType is part of containerAnnotationTypeTargets - if (targetMask == TagBits.AnnotationForType && - (targets & TagBits.AnnotationForTypeUse) != 0) { - return; - } - add(targetName); - } - } - void checkAnnotationType(char[] targetName) { - if ((containerAnnotationTypeTargets & TagBits.AnnotationForAnnotationType) != 0 && - ((targets & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType))) == 0) { - add(targetName); - } - } - private void add(char[] targetName) { - if (this.targetBuffer.length() != 0) { - this.targetBuffer.append(", "); //$NON-NLS-1$ - } - this.targetBuffer.append(targetName); - } - @Override - public String toString() { - return this.targetBuffer.toString(); - } - public boolean hasError() { - return this.targetBuffer.length() != 0; - } - } - MissingTargetBuilder builder = new MissingTargetBuilder(); - - builder.check(TagBits.AnnotationForType, TypeConstants.TYPE); - builder.check(TagBits.AnnotationForField, TypeConstants.UPPER_FIELD); - builder.check(TagBits.AnnotationForMethod, TypeConstants.UPPER_METHOD); - builder.check(TagBits.AnnotationForParameter, TypeConstants.UPPER_PARAMETER); - builder.check(TagBits.AnnotationForConstructor, TypeConstants.UPPER_CONSTRUCTOR); - builder.check(TagBits.AnnotationForLocalVariable, TypeConstants.UPPER_LOCAL_VARIABLE); - builder.checkAnnotationType(TypeConstants.UPPER_ANNOTATION_TYPE); - builder.check(TagBits.AnnotationForPackage, TypeConstants.UPPER_PACKAGE); - builder.check(TagBits.AnnotationForTypeParameter, TypeConstants.TYPE_PARAMETER_TARGET); - builder.check(TagBits.AnnotationForTypeUse, TypeConstants.TYPE_USE_TARGET); - builder.check(TagBits.AnnotationForModule, TypeConstants.UPPER_MODULE); - builder.check(TagBits.AnnotationForRecordComponent, TypeConstants.UPPER_RECORD_COMPONENT); - if (builder.hasError()) { - repeatableAnnotationType.tagAsHavingDefectiveContainerType(); - scope.problemReporter().repeatableAnnotationTypeTargetMismatch(culpritNode, repeatableAnnotationType, containerType, builder.toString()); - } - } - } - - // This is for error reporting for bad targets at the repeated annotation use site (as opposed to repeatable annotation type declaration site) - Leads to better message. - public static void checkContainingAnnotationTargetAtUse(Annotation repeatingAnnotation, BlockScope scope, TypeBinding containerAnnotationType, TypeBinding repeatingAnnotationType) { - // check (meta)target compatibility - if (!repeatingAnnotationType.isValidBinding()) { - // no need to check annotation usage if missing - return; - } - if (isAnnotationTargetAllowed(repeatingAnnotation, scope, containerAnnotationType, repeatingAnnotation.recipient.kind()) != AnnotationTargetAllowed.YES) { - scope.problemReporter().disallowedTargetForContainerAnnotation(repeatingAnnotation, containerAnnotationType); - } - } - - public AnnotationBinding getCompilerAnnotation() { - return this.compilerAnnotation; - } - - public boolean isRuntimeInvisible() { - final TypeBinding annotationBinding = this.resolvedType; - if (annotationBinding == null) { - return false; - } - long metaTagBits = annotationBinding.getAnnotationTagBits(); // could be forward reference - if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0) - return true; // by default the retention is CLASS - - return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationClassRetention; - } - - public boolean isRuntimeTypeInvisible(boolean targetingTypeParameter) { - final TypeBinding annotationBinding = this.resolvedType; - if (annotationBinding == null) { - return false; - } - long metaTagBits = annotationBinding.getAnnotationTagBits(); // could be forward reference - - if ((metaTagBits & (TagBits.AnnotationTargetMASK)) == 0) { // In the absence of explicit target, applicable only to declaration sites - if (!targetingTypeParameter) - return false; - } else if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) == 0) { - return false; - } - - if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0) - return true; // by default the retention is CLASS - - return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationClassRetention; - } - - public boolean isRuntimeTypeVisible(boolean targetingTypeParameter) { - final TypeBinding annotationBinding = this.resolvedType; - if (annotationBinding == null) { - return false; - } - long metaTagBits = annotationBinding.getAnnotationTagBits(); - - if ((metaTagBits & (TagBits.AnnotationTargetMASK)) == 0) { // In the absence of explicit target, applicable only to declaration sites - if (!targetingTypeParameter) - return false; - } else if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) == 0) { - return false; - } - if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0) - return false; // by default the retention is CLASS - - return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationRuntimeRetention; - } - - public boolean isRuntimeVisible() { - final TypeBinding annotationBinding = this.resolvedType; - if (annotationBinding == null) { - return false; - } - long metaTagBits = annotationBinding.getAnnotationTagBits(); - if ((metaTagBits & TagBits.AnnotationRetentionMASK) == 0) - return false; // by default the retention is CLASS - - return (metaTagBits & TagBits.AnnotationRetentionMASK) == TagBits.AnnotationRuntimeRetention; - } - - public abstract MemberValuePair[] memberValuePairs(); - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - output.append('@'); - this.type.printExpression(0, output); - return output; - } - - public void recordSuppressWarnings(Scope scope, int startSuppresss, int endSuppress, boolean isSuppressingWarnings) { - IrritantSet suppressWarningIrritants = null; - MemberValuePair[] pairs = memberValuePairs(); - pairLoop: for (int i = 0, length = pairs.length; i < length; i++) { - MemberValuePair pair = pairs[i]; - if (CharOperation.equals(pair.name, TypeConstants.VALUE)) { - Expression value = pair.value; - if (value instanceof ArrayInitializer) { - ArrayInitializer initializer = (ArrayInitializer) value; - Expression[] inits = initializer.expressions; - if (inits != null) { - for (int j = 0, initsLength = inits.length; j < initsLength; j++) { - Constant cst = inits[j].constant; - if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) { - IrritantSet irritants = CompilerOptions.warningTokenToIrritants(cst.stringValue()); - if (irritants != null) { - if (suppressWarningIrritants == null) { - suppressWarningIrritants = new IrritantSet(irritants); - } else if (suppressWarningIrritants.set(irritants) == null) { - scope.problemReporter().unusedWarningToken(inits[j]); - } - } else { - scope.problemReporter().unhandledWarningToken(inits[j]); - } - } - } - } - } else { - Constant cst = value.constant; - if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) { - IrritantSet irritants = CompilerOptions.warningTokenToIrritants(cst.stringValue()); - if (irritants != null) { - suppressWarningIrritants = new IrritantSet(irritants); - // TODO: should check for unused warning token against enclosing annotation as well ? - } else { - scope.problemReporter().unhandledWarningToken(value); - } - } - } - break pairLoop; - } - } - if (isSuppressingWarnings && suppressWarningIrritants != null) { - scope.referenceCompilationUnit().recordSuppressWarnings(suppressWarningIrritants, this, startSuppresss, endSuppress, scope.referenceContext()); - } - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - - if (this.compilerAnnotation != null) - return this.resolvedType; - this.constant = Constant.NotAConstant; - - TypeBinding typeBinding; - if (this.resolvedType == null) { - typeBinding = this.type.resolveType(scope); - if (typeBinding == null) { - this.resolvedType = new ProblemReferenceBinding(this.type.getTypeName(), null, ProblemReasons.NotFound); - return null; - } - this.resolvedType = typeBinding; - } else { - typeBinding = this.resolvedType; - } - // ensure type refers to an annotation type - if (!typeBinding.isAnnotationType() && typeBinding.isValidBinding()) { - scope.problemReporter().notAnnotationType(typeBinding, this.type); - return null; - } - - ReferenceBinding annotationType = (ReferenceBinding) this.resolvedType; - MethodBinding[] methods = annotationType.methods(); - // clone valuePairs to keep track of unused ones - MemberValuePair[] originalValuePairs = memberValuePairs(); - MemberValuePair valueAttribute = null; // remember the first 'value' pair - MemberValuePair[] pairs; - int pairsLength = originalValuePairs.length; - if (pairsLength > 0) { - System.arraycopy(originalValuePairs, 0, pairs = new MemberValuePair[pairsLength], 0, pairsLength); - } else { - pairs = originalValuePairs; - } - - nextMember: for (int i = 0, requiredLength = methods.length; i < requiredLength; i++) { - MethodBinding method = methods[i]; - char[] selector = method.selector; - boolean foundValue = false; - nextPair: for (int j = 0; j < pairsLength; j++) { - MemberValuePair pair = pairs[j]; - if (pair == null) continue nextPair; - char[] name = pair.name; - if (CharOperation.equals(name, selector)) { - if (valueAttribute == null && CharOperation.equals(name, TypeConstants.VALUE)) { - valueAttribute = pair; - } - pair.binding = method; - pair.resolveTypeExpecting(scope, method.returnType); - pairs[j] = null; // consumed - foundValue = true; - - // check duplicates - boolean foundDuplicate = false; - for (int k = j+1; k < pairsLength; k++) { - MemberValuePair otherPair = pairs[k]; - if (otherPair == null) continue; - if (CharOperation.equals(otherPair.name, selector)) { - foundDuplicate = true; - scope.problemReporter().duplicateAnnotationValue(annotationType, otherPair); - otherPair.binding = method; - otherPair.resolveTypeExpecting(scope, method.returnType); - pairs[k] = null; - } - } - if (foundDuplicate) { - scope.problemReporter().duplicateAnnotationValue(annotationType, pair); - continue nextMember; - } - } - } - if (!foundValue - && (method.modifiers & ClassFileConstants.AccAnnotationDefault) == 0 - && (this.bits & IsRecovered) == 0 - && annotationType.isValidBinding()) { - scope.problemReporter().missingValueForAnnotationMember(this, selector); - } - } - // check unused pairs - for (int i = 0; i < pairsLength; i++) { - if (pairs[i] != null) { - if (annotationType.isValidBinding()) { - scope.problemReporter().undefinedAnnotationValue(annotationType, pairs[i]); - } - pairs[i].resolveTypeExpecting(scope, null); // resilient - } - } - this.compilerAnnotation = scope.environment().createAnnotation((ReferenceBinding) this.resolvedType, computeElementValuePairs()); - // recognize standard annotations ? - long tagBits = detectStandardAnnotation(scope, annotationType, valueAttribute); - int defaultNullness = (int)(tagBits & Binding.NullnessDefaultMASK); - tagBits &= ~Binding.NullnessDefaultMASK; - CompilerOptions compilerOptions = scope.compilerOptions(); - if ((tagBits & TagBits.AnnotationDeprecated) != 0 && compilerOptions.complianceLevel >= ClassFileConstants.JDK9 && !compilerOptions.storeAnnotations) { - this.recipient.setAnnotations(new AnnotationBinding[] {this.compilerAnnotation}, true); // force storing enhanced deprecation - } - - // record annotation positions in the compilation result - scope.referenceCompilationUnit().recordSuppressWarnings(IrritantSet.NLS, null, this.sourceStart, this.declarationSourceEnd, scope.referenceContext()); - if (this.recipient != null) { - int kind = this.recipient.kind(); - if (tagBits != 0 || defaultNullness != 0) { - // tag bits onto recipient - switch (kind) { - case Binding.MODULE : - SourceModuleBinding module = (SourceModuleBinding) this.recipient; - module.tagBits |= tagBits; - if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) { - ModuleDeclaration moduleDeclaration = module.scope.referenceContext.moduleDeclaration; - recordSuppressWarnings(scope, 0, moduleDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings); - } - module.defaultNullness |= defaultNullness; - break; - case Binding.PACKAGE : - ((PackageBinding)this.recipient).tagBits |= tagBits; - break; - case Binding.TYPE : - case Binding.GENERIC_TYPE : - SourceTypeBinding sourceType = (SourceTypeBinding) this.recipient; - if ((tagBits & TagBits.AnnotationRepeatable) == 0 || sourceType.isAnnotationType()) // don't set AnnotationRepeatable on non-annotation types. - sourceType.tagBits |= tagBits; - if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) { - TypeDeclaration typeDeclaration = sourceType.scope.referenceContext; - int start; - if (scope.referenceCompilationUnit().types[0] == typeDeclaration) { - start = 0; - } else { - start = typeDeclaration.declarationSourceStart; - } - recordSuppressWarnings(scope, start, typeDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings); - } - sourceType.defaultNullness |= defaultNullness; - break; - case Binding.METHOD : - MethodBinding sourceMethod = (MethodBinding) this.recipient; - sourceMethod.tagBits |= tagBits; - if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) { - sourceType = (SourceTypeBinding) sourceMethod.declaringClass; - AbstractMethodDeclaration methodDeclaration = sourceType.scope.referenceContext.declarationOf(sourceMethod); - recordSuppressWarnings(scope, methodDeclaration.declarationSourceStart, methodDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings); - } - long nullBits = sourceMethod.tagBits & TagBits.AnnotationNullMASK; - if (nullBits == TagBits.AnnotationNullMASK) { - scope.problemReporter().contradictoryNullAnnotations(this); - sourceMethod.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems - } - if (nullBits != 0 && sourceMethod.isConstructor()) { - if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) - scope.problemReporter().nullAnnotationUnsupportedLocation(this); - // for declaration annotations the inapplicability will be reported below - sourceMethod.tagBits &= ~TagBits.AnnotationNullMASK; - } - sourceMethod.defaultNullness |= defaultNullness; - break; - case Binding.RECORD_COMPONENT : - RecordComponentBinding sourceRecordComponent = (RecordComponentBinding) this.recipient; - sourceRecordComponent.tagBits |= tagBits; - if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) { - RecordComponent recordComponent = sourceRecordComponent.sourceRecordComponent(); - recordSuppressWarnings(scope, recordComponent.declarationSourceStart, recordComponent.declarationSourceEnd, compilerOptions.suppressWarnings); - } -// TODO: BUG 562478 Consideration - to uncomment/modify the following: -// if (defaultNullness != 0) { -// RecordComponent recordComponent = sourceRecordComponent.sourceRecordComponent(); -// // test merged value of defaultNullness contributed by this annotation and previous annotations on same target is redundant w.r.t. containing value -// // (for targets other than fields the resulting value is tested only once after processing all annotations, but this is hard to do for fields) -// Binding target = scope.parent.checkRedundantDefaultNullness( -// defaultNullness | scope.localNonNullByDefaultValue(recordComponent.sourceStart), -// recordComponent.sourceStart); -// scope.recordNonNullByDefault(recordComponent.binding, defaultNullness, this, recordComponent.declarationSourceStart, recordComponent.declarationSourceEnd); -// if (target != null) { -// scope.problemReporter().nullDefaultAnnotationIsRedundant(recordComponent, new Annotation[]{this}, target); -// } -// } -// // fields don't yet have their type resolved, in 1.8 null annotations -// // will be transfered from the field to its type during STB.resolveTypeFor(). -// if ((sourceRecordComponent.tagBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) { -// scope.problemReporter().contradictoryNullAnnotations(this); -// sourceRecordComponent.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems -// } - break; - case Binding.FIELD : - FieldBinding sourceField = (FieldBinding) this.recipient; - sourceField.tagBits |= tagBits; - if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) { - sourceType = (SourceTypeBinding) sourceField.declaringClass; - FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField); - recordSuppressWarnings(scope, fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings); - } - if (defaultNullness != 0) { - sourceType = (SourceTypeBinding) sourceField.declaringClass; - FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField); - // test merged value of defaultNullness contributed by this annotation and previous annotations on same target is redundant w.r.t. containing value - // (for targets other than fields the resulting value is tested only once after processing all annotations, but this is hard to do for fields) - Binding target = scope.parent.checkRedundantDefaultNullness( - defaultNullness | scope.localNonNullByDefaultValue(fieldDeclaration.sourceStart), - fieldDeclaration.sourceStart); - scope.recordNonNullByDefault(fieldDeclaration.binding, defaultNullness, this, fieldDeclaration.declarationSourceStart, fieldDeclaration.declarationSourceEnd); - if (target != null) { - scope.problemReporter().nullDefaultAnnotationIsRedundant(fieldDeclaration, new Annotation[]{this}, target); - } - } - // fields don't yet have their type resolved, in 1.8 null annotations - // will be transfered from the field to its type during STB.resolveTypeFor(). - if ((sourceField.tagBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) { - scope.problemReporter().contradictoryNullAnnotations(this); - sourceField.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems - } - break; - case Binding.LOCAL : - LocalVariableBinding variable = (LocalVariableBinding) this.recipient; - variable.tagBits |= tagBits; - if ((variable.tagBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) { - scope.problemReporter().contradictoryNullAnnotations(this); - variable.tagBits &= ~TagBits.AnnotationNullMASK; // avoid secondary problems - } - if ((tagBits & TagBits.AnnotationSuppressWarnings) != 0) { - LocalDeclaration localDeclaration = variable.declaration; - recordSuppressWarnings(scope, localDeclaration.declarationSourceStart, localDeclaration.declarationSourceEnd, compilerOptions.suppressWarnings); - } - // note: defaultNullness for local declarations has been already been handled earlier by handleNonNullByDefault() - break; - } - } - if (kind == Binding.TYPE) { - SourceTypeBinding sourceType = (SourceTypeBinding) this.recipient; - if (CharOperation.equals(sourceType.sourceName, TypeConstants.PACKAGE_INFO_NAME)) - kind = Binding.PACKAGE; - } - checkAnnotationTarget(this, scope, annotationType, kind, this.recipient, tagBits & TagBits.AnnotationNullMASK); - } - return this.resolvedType; - } - - public long handleNonNullByDefault(BlockScope scope) { - TypeBinding typeBinding = this.resolvedType; - if (typeBinding == null) { - typeBinding = this.type.resolveType(scope); - if (typeBinding == null) { - return 0; - } - this.resolvedType = typeBinding; - } - if (!typeBinding.isAnnotationType()) { - return 0; - } - - ReferenceBinding annotationType = (ReferenceBinding) typeBinding; - - if (!annotationType.hasNullBit(TypeIds.BitNonNullByDefaultAnnotation)) { - return 0; - } - - MethodBinding[] methods = annotationType.methods(); - // clone valuePairs to keep track of unused ones - MemberValuePair[] pairs = memberValuePairs(); - MemberValuePair valueAttribute = null; // remember the first 'value' pair - int pairsLength = pairs.length; - - for (int i = 0, requiredLength = methods.length; i < requiredLength; i++) { - MethodBinding method = methods[i]; - char[] selector = method.selector; - nextPair: for (int j = 0; j < pairsLength; j++) { - MemberValuePair pair = pairs[j]; - if (pair == null) continue nextPair; - char[] name = pair.name; - if (CharOperation.equals(name, selector)) { - if (valueAttribute == null && CharOperation.equals(name, TypeConstants.VALUE)) { - valueAttribute = pair; - pair.binding = method; - pair.resolveTypeExpecting(scope, method.returnType); - } - } - } - } - // recognize standard annotations ? - long tagBits = determineNonNullByDefaultTagBits(annotationType, valueAttribute); - return (int) (tagBits & Binding.NullnessDefaultMASK); - } - - public enum AnnotationTargetAllowed { - YES, NO_DUE_TO_LACKING_TARGET, TYPE_ANNOTATION_ON_QUALIFIED_NAME, NO/*_DUE_TO_MISMATCHED_TARGET*/; - } - - private static AnnotationTargetAllowed isAnnotationTargetAllowed(Binding recipient, BlockScope scope, TypeBinding annotationType, int kind, long metaTagBits) { - switch (kind) { - case Binding.PACKAGE : - if ((metaTagBits & TagBits.AnnotationForPackage) != 0) - return AnnotationTargetAllowed.YES; - else if (scope.compilerOptions().sourceLevel <= ClassFileConstants.JDK1_6) { - SourceTypeBinding sourceType = (SourceTypeBinding) recipient; - if (CharOperation.equals(sourceType.sourceName, TypeConstants.PACKAGE_INFO_NAME)) - return AnnotationTargetAllowed.YES; - } - break; - case Binding.TYPE_USE : - if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - // jsr 308 - return AnnotationTargetAllowed.YES; - } - if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) { - // already reported as syntax error; don't report secondary problems - return AnnotationTargetAllowed.YES; - } - break; - case Binding.TYPE : - case Binding.GENERIC_TYPE : - if (((ReferenceBinding)recipient).isAnnotationType()) { - if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) - return AnnotationTargetAllowed.YES; - } else if ((metaTagBits & (TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) { - return AnnotationTargetAllowed.YES; - } else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) { - if (CharOperation.equals(((ReferenceBinding) recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME)) - return AnnotationTargetAllowed.YES; - } - break; - case Binding.METHOD : - MethodBinding methodBinding = (MethodBinding) recipient; - if (methodBinding.isConstructor()) { - if ((metaTagBits & (TagBits.AnnotationForConstructor | TagBits.AnnotationForTypeUse)) != 0) - return AnnotationTargetAllowed.YES; - } else if ((metaTagBits & TagBits.AnnotationForMethod) != 0) { - return AnnotationTargetAllowed.YES; - } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - SourceTypeBinding sourceType = (SourceTypeBinding) methodBinding.declaringClass; - MethodDeclaration methodDecl = (MethodDeclaration) sourceType.scope.referenceContext.declarationOf(methodBinding); - if (isTypeUseCompatible(methodDecl.returnType, scope)) { - return AnnotationTargetAllowed.YES; - } else { - return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME; - } - } - break; - case Binding.FIELD : - if ((metaTagBits & TagBits.AnnotationForField) != 0) { - return AnnotationTargetAllowed.YES; - } else if (((FieldBinding) recipient).isRecordComponent()){ - long recordComponentMask = TagBits.AnnotationForRecordComponent | - TagBits.AnnotationForMethod | - TagBits.AnnotationForParameter | - TagBits.AnnotationForTypeUse; - return (metaTagBits & recordComponentMask) != 0 ? AnnotationTargetAllowed.YES : AnnotationTargetAllowed.NO; - } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - FieldBinding sourceField = (FieldBinding) recipient; - SourceTypeBinding sourceType = (SourceTypeBinding) sourceField.declaringClass; - FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField); - if (isTypeUseCompatible(fieldDeclaration.type, scope)) { - return AnnotationTargetAllowed.YES; - } else { - return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME; - } - } - break; - case Binding.RECORD_COMPONENT : - /* JLS 14 9.7.4 Record Preview - * It is a compile-time error if an annotation of type T is syntactically a modifier for: - * ... - * a record component but T is not applicable to record component declarations, field declarations, - * method declarations, or type contexts. - */ - long recordComponentMask = TagBits.AnnotationForRecordComponent | - TagBits.AnnotationForField | - TagBits.AnnotationForMethod | - TagBits.AnnotationForParameter | // See JLS 14 8.10.4 Records Preview - TODO revisit in J15 - TagBits.AnnotationForTypeUse; - return (metaTagBits & recordComponentMask) != 0 ? AnnotationTargetAllowed.YES : - AnnotationTargetAllowed.NO; - case Binding.LOCAL : - LocalVariableBinding localVariableBinding = (LocalVariableBinding) recipient; - if ((localVariableBinding.tagBits & TagBits.IsArgument) != 0) { - if ((metaTagBits & TagBits.AnnotationForParameter) != 0) { - return AnnotationTargetAllowed.YES; - } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) { - return AnnotationTargetAllowed.YES; - } else { - return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME; - } - } - } else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0) { - return AnnotationTargetAllowed.YES; - } else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - if (localVariableBinding.declaration.isTypeNameVar(scope)) { - return AnnotationTargetAllowed.NO; - } else if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) { - return AnnotationTargetAllowed.YES; - } else { - return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME; - } - } - break; - case Binding.TYPE_PARAMETER : // jsr308 - if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { - return AnnotationTargetAllowed.YES; - } - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391196 - if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) { - return AnnotationTargetAllowed.YES; - } - break; - case Binding.MODULE: - if ((metaTagBits & (TagBits.AnnotationForModule)) != 0) { - return AnnotationTargetAllowed.YES; - } - break; - } - return AnnotationTargetAllowed.NO; - } - - public static boolean isAnnotationTargetAllowed(BlockScope scope, TypeBinding annotationType, Binding recipient) { - long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference - if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { - return true; - } - return isAnnotationTargetAllowed(recipient, scope, annotationType, recipient.kind(), metaTagBits)==AnnotationTargetAllowed.YES; - } - - static AnnotationTargetAllowed isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) { - - long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference - if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) { - /* JLS 9.6.4.1: If an annotation of type java.lang.annotation.Target is not present on the - declaration of an annotation interface A, then A is applicable in all declaration - contexts and in no type contexts. - */ - return kind == Binding.TYPE_USE ? AnnotationTargetAllowed.NO_DUE_TO_LACKING_TARGET : AnnotationTargetAllowed.YES; - } - - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391201 - if ((metaTagBits & TagBits.AnnotationForDeclarationMASK) == 0 - && (metaTagBits & TagBits.AnnotationForTypeUse) != 0) { - if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) { - switch (kind) { - case Binding.PACKAGE : - case Binding.TYPE : - case Binding.GENERIC_TYPE : - case Binding.METHOD : - case Binding.FIELD : - case Binding.LOCAL : - case Binding.RECORD_COMPONENT : - scope.problemReporter().invalidUsageOfTypeAnnotations(annotation); - } - } - } - return isAnnotationTargetAllowed(annotation.recipient, scope, annotationType, kind, metaTagBits); - } - - static void checkAnnotationTarget(Annotation annotation, BlockScope scope, ReferenceBinding annotationType, int kind, Binding recipient, long tagBitsToRevert) { - // check (meta)target compatibility - if (!annotationType.isValidBinding()) { - // no need to check annotation usage if missing - return; - } - - AnnotationTargetAllowed annotationTargetAllowed = isAnnotationTargetAllowed(annotation, scope, annotationType, kind); - if (annotationTargetAllowed != AnnotationTargetAllowed.YES) { - if(annotationTargetAllowed == AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME) { - scope.problemReporter().typeAnnotationAtQualifiedName(annotation); - } else if (annotationTargetAllowed == AnnotationTargetAllowed.NO_DUE_TO_LACKING_TARGET) { - scope.problemReporter().explitAnnotationTargetRequired(annotation); - } else { - scope.problemReporter().disallowedTargetForAnnotation(annotation); - } - if (recipient instanceof TypeBinding) - ((TypeBinding)recipient).tagBits &= ~tagBitsToRevert; - } - } - - /** - * Check to see if a repeating annotation is in fact of a container annotation type for an annotation which is also present at the same target. - * @param scope The scope (for error reporting) - * @param repeatedAnnotationType Type of annotation which has been repeated (to check for possibly being a container for a repeatable annotation) - * @param sourceAnnotations The annotations to check - */ - public static void checkForInstancesOfRepeatableWithRepeatingContainerAnnotation(BlockScope scope, ReferenceBinding repeatedAnnotationType, Annotation[] sourceAnnotations) { - // Fail fast if the repeating annotation type can't be a container, anyway - MethodBinding[] valueMethods = repeatedAnnotationType.getMethods(TypeConstants.VALUE); - if (valueMethods.length != 1) return; // No violations possible - - TypeBinding methodReturnType = valueMethods[0].returnType; - // value must be an array - if (! methodReturnType.isArrayType() || methodReturnType.dimensions() != 1) return; - - ArrayBinding array = (ArrayBinding) methodReturnType; - TypeBinding elementsType = array.elementsType(); - if (! elementsType.isRepeatableAnnotationType()) return; // Can't be a problem, then - - for (int i= 0; i < sourceAnnotations.length; ++i) { - Annotation annotation = sourceAnnotations[i]; - if (TypeBinding.equalsEquals(elementsType, annotation.resolvedType)) { - scope.problemReporter().repeatableAnnotationWithRepeatingContainer(annotation, repeatedAnnotationType); - return; // One is enough for this annotation type - } - } - } - - // Check and answer if an attempt to annotate a package is being made. Error should be reported by caller. - public static boolean isTypeUseCompatible(TypeReference reference, Scope scope) { - if (reference != null && !(reference instanceof SingleTypeReference)) { - Binding binding = scope.getPackage(reference.getTypeName()); - // In case of ProblemReferenceBinding, don't report additional error - if (binding instanceof PackageBinding) { - return false; - } - } - return true; - } - - // Complain if an attempt to annotate the enclosing type of a static member type is being made. - public static void isTypeUseCompatible(TypeReference reference, Scope scope, Annotation[] annotations) { - if (annotations == null || reference == null || reference.getAnnotatableLevels() == 1) - return; - if (scope.environment().globalOptions.sourceLevel < ClassFileConstants.JDK1_8) - return; - - TypeBinding resolvedType = reference.resolvedType == null ? null : reference.resolvedType.leafComponentType(); - if (resolvedType == null || !resolvedType.isNestedType()) - return; - - nextAnnotation: - for (int i = 0, annotationsLength = annotations.length; i < annotationsLength; i++) { - Annotation annotation = annotations[i]; - long metaTagBits = annotation.resolvedType.getAnnotationTagBits(); - if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0 && (metaTagBits & TagBits.AnnotationForDeclarationMASK) == 0) { - ReferenceBinding currentType = (ReferenceBinding) resolvedType; - while (currentType.isNestedType()) { - if (currentType.isStatic()) { - QualifiedTypeReference.rejectAnnotationsOnStaticMemberQualififer(scope, currentType, new Annotation [] { annotation }); - continue nextAnnotation; - } else { - if (annotation.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) { - scope.problemReporter().nullAnnotationAtQualifyingType(annotation); - continue nextAnnotation; - } - } - currentType = currentType.enclosingType(); - } - } - } - } - - public boolean hasNullBit(int bit) { - return this.resolvedType instanceof ReferenceBinding && ((ReferenceBinding) this.resolvedType).hasNullBit(bit); - } - - @Override - public abstract void traverse(ASTVisitor visitor, BlockScope scope); - - @Override - public abstract void traverse(ASTVisitor visitor, ClassScope scope); - - public Annotation getPersistibleAnnotation() { - return this.persistibleAnnotation; // will be this for non-repeating annotation, the container for the first of the repeating ones and null for the followers. - } - - public void setPersistibleAnnotation(ContainerAnnotation container) { - this.persistibleAnnotation = container; // will be a legitimate container for the first of the repeating ones and null for the followers. - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AnnotationMethodDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AnnotationMethodDeclaration.java deleted file mode 100644 index 7644d64..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AnnotationMethodDeclaration.java +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ClassFile; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.parser.Parser; - -public class AnnotationMethodDeclaration extends MethodDeclaration { - - public Expression defaultValue; - public int extendedDimensions; - - /** - * MethodDeclaration constructor comment. - */ - public AnnotationMethodDeclaration(CompilationResult compilationResult) { - super(compilationResult); - } - - @Override - public void generateCode(ClassFile classFile) { - classFile.generateMethodInfoHeader(this.binding); - int methodAttributeOffset = classFile.contentsOffset; - int attributeNumber = classFile.generateMethodInfoAttributes(this.binding, this); - classFile.completeMethodInfo(this.binding, methodAttributeOffset, attributeNumber); - } - - @Override - public boolean isAnnotationMethod() { - - return true; - } - - @Override - public boolean isMethod() { - - return false; - } - - @Override - public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { - // nothing to do - // annotation type member declaration don't have any body - } - - @Override - public StringBuilder print(int tab, StringBuilder output) { - - printIndent(tab, output); - printModifiers(this.modifiers, output); - if (this.annotations != null) { - printAnnotations(this.annotations, output); - output.append(' '); - } - - TypeParameter[] typeParams = typeParameters(); - if (typeParams != null) { - output.append('<'); - int max = typeParams.length - 1; - for (int j = 0; j < max; j++) { - typeParams[j].print(0, output); - output.append(", ");//$NON-NLS-1$ - } - typeParams[max].print(0, output); - output.append('>'); - } - - printReturnType(0, output).append(this.selector).append('('); - if (this.arguments != null) { - for (int i = 0; i < this.arguments.length; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.arguments[i].print(0, output); - } - } - output.append(')'); - if (this.thrownExceptions != null) { - output.append(" throws "); //$NON-NLS-1$ - for (int i = 0; i < this.thrownExceptions.length; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.thrownExceptions[i].print(0, output); - } - } - - if (this.defaultValue != null) { - output.append(" default "); //$NON-NLS-1$ - this.defaultValue.print(0, output); - } - - printBody(tab + 1, output); - return output; - } - - @Override - public void resolveStatements() { - - super.resolveStatements(); - if (this.arguments != null || this.receiver != null) { - this.scope.problemReporter().annotationMembersCannotHaveParameters(this); - } - if (this.typeParameters != null) { - this.scope.problemReporter().annotationMembersCannotHaveTypeParameters(this); - } - if (this.extendedDimensions != 0) { - this.scope.problemReporter().illegalExtendedDimensions(this); - } - if (this.binding == null) return; - TypeBinding returnTypeBinding = this.binding.returnType; - if (returnTypeBinding != null) { - - // annotation methods can only return base types, String, Class, enum type, annotation types and arrays of these - checkAnnotationMethodType: { - TypeBinding leafReturnType = returnTypeBinding.leafComponentType(); - if (returnTypeBinding.dimensions() <= 1) { // only 1-dimensional array permitted - switch (leafReturnType.erasure().id) { - case T_byte : - case T_short : - case T_char : - case T_int : - case T_long : - case T_float : - case T_double : - case T_boolean : - case T_JavaLangString : - case T_JavaLangClass : - break checkAnnotationMethodType; - } - if (leafReturnType.isEnum() || leafReturnType.isAnnotationType()) - break checkAnnotationMethodType; - } - this.scope.problemReporter().invalidAnnotationMemberType(this); - } - if (this.defaultValue != null) { - MemberValuePair pair = new MemberValuePair(this.selector, this.sourceStart, this.sourceEnd, this.defaultValue); - pair.binding = this.binding; - if (pair.value.resolvedType == null) - pair.resolveTypeExpecting(this.scope, returnTypeBinding); - this.binding.setDefaultValue(org.eclipse.jdt.internal.compiler.lookup.ElementValuePair.getValue(this.defaultValue)); - } else { // let it know it does not have a default value so it won't try to find it - this.binding.setDefaultValue(null); - } - } - } - - @Override - public void traverse( - ASTVisitor visitor, - ClassScope classScope) { - - if (visitor.visit(this, classScope)) { - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, this.scope); - } - if (this.returnType != null) { - this.returnType.traverse(visitor, this.scope); - } - if (this.defaultValue != null) { - this.defaultValue.traverse(visitor, this.scope); - } - } - visitor.endVisit(this, classScope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Argument.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Argument.java deleted file mode 100644 index 6553347..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Argument.java +++ /dev/null @@ -1,298 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 365519 - editorial cleanup after bug 186342 and bug 365387 - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" - * Bug 438012 - [1.8][null] Bogus Warning: The nullness annotation is redundant with a default that applies to this location - * Bug 466713 - Null Annotations: NullPointerException using as Type Param - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 409246 - [1.8][compiler] Type annotations on catch parameters not handled properly - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class Argument extends LocalDeclaration { - - // prefix for setter method (to recognize special hiding argument) - private final static char[] SET = "set".toCharArray(); //$NON-NLS-1$ - - public Argument(char[] name, long posNom, TypeReference tr, int modifiers) { - - super(name, (int) (posNom >>> 32), (int) posNom); - this.declarationSourceEnd = (int) posNom; - this.modifiers = modifiers; - this.type = tr; - if (tr != null) { - this.bits |= (tr.bits & ASTNode.HasTypeAnnotations); - } - this.bits |= (IsLocalDeclarationReachable | IsArgument); - } - - public Argument(char[] name, long posNom, TypeReference tr, int modifiers, boolean typeElided) { - - super(name, (int) (posNom >>> 32), (int) posNom); - this.declarationSourceEnd = (int) posNom; - this.modifiers = modifiers; - this.type = tr; - if (tr != null) { - this.bits |= (tr.bits & ASTNode.HasTypeAnnotations); - } - this.bits |= (IsLocalDeclarationReachable | IsArgument | IsTypeElided); - } - - @Override - public boolean isRecoveredFromLoneIdentifier() { - return false; - } - - public TypeBinding createBinding(MethodScope scope, TypeBinding typeBinding) { - if (this.binding == null) { - // for default constructors and fake implementation of abstract methods - this.binding = new LocalVariableBinding(this, typeBinding, this.modifiers, scope); - } else if (!this.binding.type.isValidBinding()) { - AbstractMethodDeclaration methodDecl = scope.referenceMethod(); - if (methodDecl != null) { - MethodBinding methodBinding = methodDecl.binding; - if (methodBinding != null) { - methodBinding.tagBits |= TagBits.HasUnresolvedArguments; - } - } - } - if ((this.binding.tagBits & TagBits.AnnotationResolved) == 0) { - Annotation[] annots = this.annotations; - long sourceLevel = scope.compilerOptions().sourceLevel; - if (sourceLevel >= ClassFileConstants.JDK14 && annots == null) { - annots = getCorrespondingRecordComponentAnnotationsIfApplicable(scope.referenceMethod()); - annots = ASTNode.copyRecordComponentAnnotations(scope, - this.binding, annots); - } - if (annots != null) - resolveAnnotations(scope, annots, this.binding, true); - if (sourceLevel >= ClassFileConstants.JDK1_8) { - Annotation.isTypeUseCompatible(this.type, scope, annots); - scope.validateNullAnnotation(this.binding.tagBits, this.type, annots); - } - } - this.binding.declaration = this; - return this.binding.type; // might have been updated during resolveAnnotations (for typeAnnotations) - } - - private Annotation[] getCorrespondingRecordComponentAnnotationsIfApplicable(AbstractMethodDeclaration methodDecl) { - if (methodDecl != null && methodDecl.isConstructor() && - ((methodDecl.bits & (ASTNode.IsCanonicalConstructor )) != 0 && - ((methodDecl.bits & (ASTNode.IsImplicit)) != 0))) { - MethodBinding methodBinding = methodDecl.binding; - ReferenceBinding referenceBinding = methodBinding== null ? null : methodBinding.declaringClass; - if (referenceBinding instanceof SourceTypeBinding) { - SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) referenceBinding; - assert (sourceTypeBinding.isRecord()); // CHECK: Is this really necessary? - sourceTypeBinding.components(); - RecordComponentBinding recordComponentBinding = sourceTypeBinding.getRecordComponent(this.name); - if (recordComponentBinding != null) { - RecordComponent recordComponent = recordComponentBinding.sourceRecordComponent(); - return recordComponent.annotations; - } - } - } - return null; - } - public TypeBinding bind(MethodScope scope, TypeBinding typeBinding, boolean used) { - if (this.isUnnamed(scope) && !scope.isLambdaScope()) { - scope.problemReporter().illegalUseOfUnderscoreAsAnIdentifier(this.sourceStart, this.sourceEnd, scope.compilerOptions().sourceLevel > ClassFileConstants.JDK1_8, true); - } - - TypeBinding newTypeBinding = createBinding(scope, typeBinding); // basically a no-op if createBinding() was called before - - // record the resolved type into the type reference - Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/); - if (existingVariable != null && existingVariable.isValidBinding()){ - final boolean localExists = existingVariable instanceof LocalVariableBinding; - if (localExists && this.hiddenVariableDepth == 0) { - if (!this.isUnnamed(scope)) { - if ((this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope()) { - scope.problemReporter().lambdaRedeclaresArgument(this); - } else if (scope.referenceContext instanceof CompactConstructorDeclaration) { - // skip error reporting - hidden params - already reported in record components - } else { - scope.problemReporter().redefineArgument(this); - } - } - } else { - boolean isSpecialArgument = false; - if (existingVariable instanceof FieldBinding) { - if (scope.isInsideConstructor()) { - isSpecialArgument = true; // constructor argument - } else if (!((FieldBinding)existingVariable).isRecordComponent()){ - // there are no setter methods for record components - AbstractMethodDeclaration methodDecl = scope.referenceMethod(); - if (methodDecl != null && CharOperation.prefixEquals(SET, methodDecl.selector)) { - isSpecialArgument = true; // setter argument - } - } - } - scope.problemReporter().localVariableHiding(this, existingVariable, isSpecialArgument); - } - } - scope.addLocalVariable(this.binding); - this.binding.useFlag = used ? LocalVariableBinding.USED : LocalVariableBinding.UNUSED; - return newTypeBinding; - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind() - */ - @Override - public int getKind() { - return (this.bits & ASTNode.IsArgument) != 0 ? PARAMETER : LOCAL_VARIABLE; - } - - @Override - public boolean isArgument() { - return true; - } - - public boolean isVarArgs() { - return this.type != null && (this.type.bits & IsVarArgs) != 0; - } - - public boolean hasElidedType() { - return (this.bits & IsTypeElided) != 0; - } - - public boolean hasNullTypeAnnotation(AnnotationPosition position) { - // parser associates SE8 annotations to the declaration - return TypeReference.containsNullAnnotation(this.annotations) || - (this.type != null && this.type.hasNullTypeAnnotation(position)); // just in case - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - - printIndent(indent, output); - printModifiers(this.modifiers, output); - if (this.annotations != null) { - printAnnotations(this.annotations, output); - output.append(' '); - } - - if (this.type == null) { - output.append(" "); //$NON-NLS-1$ - } else { - this.type.print(0, output).append(' '); - } - return output.append(this.name); - } - - @Override - public StringBuilder printStatement(int indent, StringBuilder output) { - - return print(indent, output).append(';'); - } - - public TypeBinding resolveForCatch(BlockScope scope) { - // resolution on an argument of a catch clause - // provide the scope with a side effect : insertion of a LOCAL - // that represents the argument. The type must be from JavaThrowable - - TypeBinding exceptionType = this.type.resolveType(scope, true /* check bounds*/); - boolean hasError; - if (exceptionType == null) { - hasError = true; - } else { - hasError = false; - switch(exceptionType.kind()) { - case Binding.PARAMETERIZED_TYPE : - if (exceptionType.isBoundParameterizedType()) { - hasError = true; - scope.problemReporter().invalidParameterizedExceptionType(exceptionType, this); - // fall thru to create the variable - avoids additional errors because the variable is missing - } - break; - case Binding.TYPE_PARAMETER : - scope.problemReporter().invalidTypeVariableAsException(exceptionType, this); - hasError = true; - // fall thru to create the variable - avoids additional errors because the variable is missing - break; - } - if (exceptionType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) == null && exceptionType.isValidBinding()) { - scope.problemReporter().cannotThrowType(this.type, exceptionType); - hasError = true; - // fall thru to create the variable - avoids additional errors because the variable is missing - } - } - Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/); - if (existingVariable != null && existingVariable.isValidBinding() && !isUnnamed(scope)) { - if (existingVariable instanceof LocalVariableBinding && this.hiddenVariableDepth == 0) { - scope.problemReporter().redefineArgument(this); - } else { - scope.problemReporter().localVariableHiding(this, existingVariable, false); - } - } - - if ((this.type.bits & ASTNode.IsUnionType) != 0) { - this.binding = new CatchParameterBinding(this, exceptionType, this.modifiers | ClassFileConstants.AccFinal, false); // argument decl, but local var (where isArgument = false) - this.binding.tagBits |= TagBits.MultiCatchParameter; - } else { - this.binding = new CatchParameterBinding(this, exceptionType, this.modifiers, false); // argument decl, but local var (where isArgument = false) - } - resolveAnnotations(scope, this.annotations, this.binding, true); - Annotation.isTypeUseCompatible(this.type, scope, this.annotations); - if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled && - (this.type.hasNullTypeAnnotation(AnnotationPosition.ANY) || TypeReference.containsNullAnnotation(this.annotations))) - { - scope.problemReporter().nullAnnotationUnsupportedLocation(this.type); - } - - scope.addLocalVariable(this.binding); - this.binding.setConstant(Constant.NotAConstant); - if (hasError) return null; - return exceptionType; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, scope); - } - if (this.type != null) - this.type.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } - public void traverse(ASTVisitor visitor, ClassScope scope) { - - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, scope); - } - if (this.type != null) - this.type.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java deleted file mode 100644 index 3a810d1..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java +++ /dev/null @@ -1,275 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 417758 - [1.8][null] Null safety compromise during array creation. - * Bug 427163 - [1.8][null] bogus error "Contradictory null specification" on varags - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - * Bug 409247 - [1.8][compiler] Verify error with code allocating multidimensional array - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.List; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class ArrayAllocationExpression extends Expression { - - public TypeReference type; - - //dimensions.length gives the number of dimensions, but the - // last ones may be nulled as in new int[4][5][][] - public Expression[] dimensions; - public Annotation [][] annotationsOnDimensions; // jsr308 style annotations. - public ArrayInitializer initializer; - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - for (int i = 0, max = this.dimensions.length; i < max; i++) { - Expression dim; - if ((dim = this.dimensions[i]) != null) { - flowInfo = dim.analyseCode(currentScope, flowContext, flowInfo); - dim.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - } - } - // account for potential OutOfMemoryError: - flowContext.recordAbruptExit(); - if (this.initializer != null) { - return this.initializer.analyseCode(currentScope, flowContext, flowInfo); - } - return flowInfo; - } - - /** - * Code generation for a array allocation expression - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - - int pc = codeStream.position; - - if (this.initializer != null) { - this.initializer.generateCode(this.type, this, currentScope, codeStream, valueRequired); - return; - } - - int explicitDimCount = 0; - for (int i = 0, max = this.dimensions.length; i < max; i++) { - Expression dimExpression; - if ((dimExpression = this.dimensions[i]) == null) break; // implicit dim, no further explict after this point - dimExpression.generateCode(currentScope, codeStream, true); - explicitDimCount++; - } - - // array allocation - if (explicitDimCount == 1) { - // Mono-dimensional array - codeStream.newArray(this.type, this, (ArrayBinding)this.resolvedType); - } else { - // Multi-dimensional array - codeStream.multianewarray(this.type, this.resolvedType, explicitDimCount, this); - } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - codeStream.pop(); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - output.append("new "); //$NON-NLS-1$ - this.type.print(0, output); - for (int i = 0; i < this.dimensions.length; i++) { - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[i] != null) { - output.append(' '); - printAnnotations(this.annotationsOnDimensions[i], output); - output.append(' '); - } - if (this.dimensions[i] == null) - output.append("[]"); //$NON-NLS-1$ - else { - output.append('['); - this.dimensions[i].printExpression(0, output); - output.append(']'); - } - } - if (this.initializer != null) this.initializer.printExpression(0, output); - return output; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - // Build an array type reference using the current dimensions - // The parser does not check for the fact that dimension may be null - // only at the -end- like new int [4][][]. The parser allows new int[][4][] - // so this must be checked here......(this comes from a reduction to LL1 grammar) - - TypeBinding referenceType = this.type.resolveType(scope, true /* check bounds*/); - - // will check for null after dimensions are checked - this.constant = Constant.NotAConstant; - if (referenceType == TypeBinding.VOID) { - scope.problemReporter().cannotAllocateVoidArray(this); - referenceType = null; - } - - // check the validity of the dimension syntax (and test for all null dimensions) - int explicitDimIndex = -1; - loop: for (int i = this.dimensions.length; --i >= 0;) { - if (this.dimensions[i] != null) { - if (explicitDimIndex < 0) explicitDimIndex = i; - } else if (explicitDimIndex > 0) { - // should not have an empty dimension before an non-empty one - scope.problemReporter().incorrectLocationForNonEmptyDimension(this, explicitDimIndex); - break loop; - } - } - - // explicitDimIndex < 0 says if all dimensions are nulled - // when an initializer is given, no dimension must be specified - if (this.initializer == null) { - if (explicitDimIndex < 0) { - scope.problemReporter().mustDefineDimensionsOrInitializer(this); - } - // allow new List[5] - only check for generic array when no initializer, since also checked inside initializer resolution - if (referenceType != null && !referenceType.isReifiable()) { - scope.problemReporter().illegalGenericArray(referenceType, this); - } - } else if (explicitDimIndex >= 0) { - scope.problemReporter().cannotDefineDimensionsAndInitializer(this); - } - - // dimensions resolution - for (int i = 0; i <= explicitDimIndex; i++) { - Expression dimExpression; - if ((dimExpression = this.dimensions[i]) != null) { - TypeBinding dimensionType = dimExpression.resolveTypeExpecting(scope, TypeBinding.INT); - if (dimensionType != null) { - this.dimensions[i].computeConversion(scope, TypeBinding.INT, dimensionType); - } - } - } - - // building the array binding - if (referenceType != null) { - if (this.dimensions.length > 255) { - scope.problemReporter().tooManyDimensions(this); - } - if (this.type.annotations != null - && (referenceType.tagBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) - { - scope.problemReporter().contradictoryNullAnnotations(this.type.annotations[this.type.annotations.length-1]); - referenceType = referenceType.withoutToplevelNullAnnotation(); - } - this.resolvedType = scope.createArrayType(referenceType, this.dimensions.length); - - int lastInitializedDim = -1; - long[] nullTagBitsPerDimension = null; - if (this.annotationsOnDimensions != null) { - this.resolvedType = resolveAnnotations(scope, this.annotationsOnDimensions, this.resolvedType); - nullTagBitsPerDimension = ((ArrayBinding)this.resolvedType).nullTagBitsPerDimension; - if (nullTagBitsPerDimension != null) { - for (int i = 0; i < this.annotationsOnDimensions.length; i++) { - if ((nullTagBitsPerDimension[i] & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) { - scope.problemReporter().contradictoryNullAnnotations(this.annotationsOnDimensions[i]); - nullTagBitsPerDimension[i] = 0; - } - if (this.dimensions[i] != null) { - lastInitializedDim = i; - } - } - } - } - - if (this.initializer != null) { - this.resolvedType = ArrayTypeReference.maybeMarkArrayContentsNonNull(scope, this.resolvedType, this.sourceStart, this.dimensions.length, null); - if ((this.initializer.resolveTypeExpecting(scope, this.resolvedType)) != null) - this.initializer.binding = (ArrayBinding)this.resolvedType; - } else { - // check uninitialized cells declared @NonNull inside the last initialized dimension - if (lastInitializedDim != -1 && nullTagBitsPerDimension != null) { - checkUninitializedNonNullArrayContents(scope, nullTagBitsPerDimension[lastInitializedDim+1], lastInitializedDim); - } - } - if ((referenceType.tagBits & TagBits.HasMissingType) != 0) { - return null; - } - } - return this.resolvedType; - } - - protected void checkUninitializedNonNullArrayContents(BlockScope scope, long elementNullTagBits, int lastDim) { - if ((elementNullTagBits & TagBits.AnnotationNonNull) == 0) - return; // next element type admits 'null' entries - if (this.dimensions[lastDim] instanceof IntLiteral) { - Constant intConstant = ((IntLiteral) this.dimensions[lastDim]).constant; - if (intConstant.intValue() == 0) - return; // last dimension [0] implies no 'null' entries - } - TypeBinding elementType = this.resolvedType; - for (int i=0; i allTypeAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, info, allTypeAnnotationContexts); - this.type.traverse(collector, (BlockScope) null); - if (this.annotationsOnDimensions != null) { - int dimensionsLength = this.dimensions.length; - for (int i = 0; i < dimensionsLength; i++) { - Annotation [] annotations = this.annotationsOnDimensions[i]; - int annotationsLength = annotations == null ? 0 : annotations.length; - for (int j = 0; j < annotationsLength; j++) { - annotations[j].traverse(collector, (BlockScope) null); - } - } - } - } - - public Annotation[][] getAnnotationsOnDimensions() { - return this.annotationsOnDimensions; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java deleted file mode 100644 index abc8aa4..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayInitializer.java +++ /dev/null @@ -1,260 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK - * bug 370639 - [compiler][resource] restore the default for resource leak warnings - * bug 388996 - [compiler][resource] Incorrect 'potential resource leak' - * Bug 417758 - [1.8][null] Null safety compromise during array creation. - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.ASSIGNMENT_CONTEXT; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class ArrayInitializer extends Expression { - - public Expression[] expressions; - public ArrayBinding binding; //the type of the { , , , } - - /** - * ArrayInitializer constructor comment. - */ - public ArrayInitializer() { - - super(); - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - - if (this.expressions != null) { - CompilerOptions compilerOptions = currentScope.compilerOptions(); - boolean analyseResources = compilerOptions.analyseResourceLeaks; - boolean evalNullTypeAnnotations = currentScope.environment().usesNullTypeAnnotations(); - for (int i = 0, max = this.expressions.length; i < max; i++) { - flowInfo = this.expressions[i].analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - - if (analyseResources && FakedTrackingVariable.isAnyCloseable(this.expressions[i].resolvedType)) { - flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.expressions[i], flowInfo, flowContext, false); - } - if (evalNullTypeAnnotations) { - checkAgainstNullTypeAnnotation(currentScope, this.binding.elementsType(), this.expressions[i], flowContext, flowInfo); - } - } - } - return flowInfo; - } - - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - generateCode(null, null, currentScope, codeStream, valueRequired); - } - - /** - * Code generation for a array initializer - */ - public void generateCode(TypeReference typeReference, ArrayAllocationExpression allocationExpression, BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - - // Flatten the values and compute the dimensions, by iterating in depth into nested array initializers - int pc = codeStream.position; - int expressionLength = (this.expressions == null) ? 0: this.expressions.length; - codeStream.generateInlinedValue(expressionLength); - codeStream.newArray(typeReference, allocationExpression, this.binding); - if (this.expressions != null) { - // binding is an ArrayType, so I can just deal with the dimension - int elementsTypeID = this.binding.dimensions > 1 ? -1 : this.binding.leafComponentType.id; - for (int i = 0; i < expressionLength; i++) { - Expression expr; - if ((expr = this.expressions[i]).constant != Constant.NotAConstant) { - switch (elementsTypeID) { // filter out initializations to default values - case T_int : - case T_short : - case T_byte : - case T_char : - case T_long : - if (expr.constant.longValue() != 0) { - codeStream.dup(); - codeStream.generateInlinedValue(i); - expr.generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(elementsTypeID, false); - } - break; - case T_float : - case T_double : - double constantValue = expr.constant.doubleValue(); - if (constantValue == -0.0 || constantValue != 0) { - codeStream.dup(); - codeStream.generateInlinedValue(i); - expr.generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(elementsTypeID, false); - } - break; - case T_boolean : - if (expr.constant.booleanValue() != false) { - codeStream.dup(); - codeStream.generateInlinedValue(i); - expr.generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(elementsTypeID, false); - } - break; - default : - if (!(expr instanceof NullLiteral)) { - codeStream.dup(); - codeStream.generateInlinedValue(i); - expr.generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(elementsTypeID, false); - } - } - } else if (!(expr instanceof NullLiteral)) { - codeStream.dup(); - codeStream.generateInlinedValue(i); - expr.generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(elementsTypeID, false); - } - } - } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - codeStream.pop(); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - - output.append('{'); - if (this.expressions != null) { - int j = 20 ; - for (int i = 0 ; i < this.expressions.length ; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.expressions[i].printExpression(0, output); - j -- ; - if (j == 0) { - output.append('\n'); - printIndent(indent+1, output); - j = 20; - } - } - } - return output.append('}'); - } - - @Override - public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) { - // Array initializers can only occur on the right hand side of an assignment - // expression, therefore the expected type contains the valid information - // concerning the type that must be enforced by the elements of the array initializer. - - // this method is recursive... (the test on isArrayType is the stop case) - - this.constant = Constant.NotAConstant; - - if (expectedType instanceof ArrayBinding) { - // allow new List[5] - if ((this.bits & IsAnnotationDefaultValue) == 0) { // annotation default value need only to be commensurate JLS9.7 - // allow new List[5] - only check for generic array when no initializer, since also checked inside initializer resolution - TypeBinding leafComponentType = expectedType.leafComponentType(); - if (!leafComponentType.isReifiable()) { - scope.problemReporter().illegalGenericArray(leafComponentType, this); - } - } - this.resolvedType = this.binding = (ArrayBinding) expectedType; - if (this.expressions == null) - return this.binding; - TypeBinding elementType = this.binding.elementsType(); - for (int i = 0, length = this.expressions.length; i < length; i++) { - Expression expression = this.expressions[i]; - expression.setExpressionContext(ASSIGNMENT_CONTEXT); - expression.setExpectedType(elementType); - TypeBinding expressionType = expression instanceof ArrayInitializer - ? expression.resolveTypeExpecting(scope, elementType) - : expression.resolveType(scope); - if (expressionType == null) - continue; - - // Compile-time conversion required? - if (TypeBinding.notEquals(elementType, expressionType)) // must call before computeConversion() and typeMismatchError() - scope.compilationUnitScope().recordTypeConversion(elementType, expressionType); - - if (expression.isConstantValueOfTypeAssignableToType(expressionType, elementType) - || expressionType.isCompatibleWith(elementType)) { - expression.computeConversion(scope, elementType, expressionType); - } else if (isBoxingCompatible(expressionType, elementType, expression, scope)) { - expression.computeConversion(scope, elementType, expressionType); - } else { - scope.problemReporter().typeMismatchError(expressionType, elementType, expression, null); - } - } - return this.binding; - } - - // infer initializer type for error reporting based on first element - TypeBinding leafElementType = null; - int dim = 1; - if (this.expressions == null) { - leafElementType = scope.getJavaLangObject(); - } else { - Expression expression = this.expressions[0]; - while(expression != null && expression instanceof ArrayInitializer) { - dim++; - Expression[] subExprs = ((ArrayInitializer) expression).expressions; - if (subExprs == null){ - leafElementType = scope.getJavaLangObject(); - expression = null; - break; - } - expression = ((ArrayInitializer) expression).expressions[0]; - } - if (expression != null) { - leafElementType = expression.resolveType(scope); - } - // fault-tolerance - resolve other expressions as well - for (int i = 1, length = this.expressions.length; i < length; i++) { - expression = this.expressions[i]; - if (expression != null) { - expression.resolveType(scope) ; - } - } } - if (leafElementType != null) { - this.resolvedType = scope.createArrayType(leafElementType, dim); - if (expectedType != null) - scope.problemReporter().typeMismatchError(this.resolvedType, expectedType, this, null); - } - return null; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - - if (visitor.visit(this, scope)) { - if (this.expressions != null) { - int expressionsLength = this.expressions.length; - for (int i = 0; i < expressionsLength; i++) - this.expressions[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java deleted file mode 100644 index 4ff6b69..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayQualifiedTypeReference.java +++ /dev/null @@ -1,209 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; - -public class ArrayQualifiedTypeReference extends QualifiedTypeReference { - int dimensions; - private Annotation[][] annotationsOnDimensions; // jsr308 style type annotations on dimensions - public int extendedDimensions; - - public ArrayQualifiedTypeReference(char[][] sources , int dim, long[] poss) { - - super( sources , poss); - this.dimensions = dim ; - this.annotationsOnDimensions = null; - } - - public ArrayQualifiedTypeReference(char[][] sources, int dim, Annotation[][] annotationsOnDimensions, long[] poss) { - this(sources, dim, poss); - this.annotationsOnDimensions = annotationsOnDimensions; - if (annotationsOnDimensions != null) - this.bits |= ASTNode.HasTypeAnnotations; - } - - @Override - public int dimensions() { - - return this.dimensions; - } - - @Override - public int extraDimensions() { - return this.extendedDimensions; - } - - /** - @see org.eclipse.jdt.internal.compiler.ast.TypeReference#getAnnotationsOnDimensions(boolean) - */ - @Override - public Annotation[][] getAnnotationsOnDimensions(boolean useSourceOrder) { - if (useSourceOrder || this.annotationsOnDimensions == null || this.annotationsOnDimensions.length == 0 || this.extendedDimensions == 0 || this.extendedDimensions == this.dimensions) - return this.annotationsOnDimensions; - Annotation [][] externalAnnotations = new Annotation[this.dimensions][]; - final int baseDimensions = this.dimensions - this.extendedDimensions; - System.arraycopy(this.annotationsOnDimensions, baseDimensions, externalAnnotations, 0, this.extendedDimensions); - System.arraycopy(this.annotationsOnDimensions, 0, externalAnnotations, this.extendedDimensions, baseDimensions); - return externalAnnotations; - } - - @Override - public void setAnnotationsOnDimensions(Annotation [][] annotationsOnDimensions) { - this.annotationsOnDimensions = annotationsOnDimensions; - } - - @Override - public Annotation[] getTopAnnotations() { - if (this.annotationsOnDimensions != null) - return this.annotationsOnDimensions[0]; - return new Annotation[0]; - } - - /** - * @return char[][] - */ - @Override - public char [][] getParameterizedTypeName(){ - int dim = this.dimensions; - char[] dimChars = new char[dim*2]; - for (int i = 0; i < dim; i++) { - int index = i*2; - dimChars[index] = '['; - dimChars[index+1] = ']'; - } - int length = this.tokens.length; - char[][] qParamName = new char[length][]; - System.arraycopy(this.tokens, 0, qParamName, 0, length-1); - qParamName[length-1] = CharOperation.concat(this.tokens[length-1], dimChars); - return qParamName; - } - - @Override - protected TypeBinding getTypeBinding(Scope scope) { - - if (this.resolvedType != null) - return this.resolvedType; - if (this.dimensions > 255) { - scope.problemReporter().tooManyDimensions(this); - } - LookupEnvironment env = scope.environment(); - try { - env.missingClassFileLocation = this; - TypeBinding leafComponentType = super.getTypeBinding(scope); - if (leafComponentType != null) { - return this.resolvedType = scope.createArrayType(leafComponentType, this.dimensions); - } - return null; - } catch (AbortCompilation e) { - e.updateContext(this, scope.referenceCompilationUnit().compilationResult); - throw e; - } finally { - env.missingClassFileLocation = null; - } - } - - @Override - protected TypeBinding internalResolveType(Scope scope, int location) { - TypeBinding internalResolveType = super.internalResolveType(scope, location); - internalResolveType = ArrayTypeReference.maybeMarkArrayContentsNonNull(scope, internalResolveType, this.sourceStart, this.dimensions, null); - - return internalResolveType; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output){ - - super.printExpression(indent, output); - if ((this.bits & IsVarArgs) != 0) { - for (int i= 0 ; i < this.dimensions - 1; i++) { - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[i] != null) { - output.append(' '); - printAnnotations(this.annotationsOnDimensions[i], output); - output.append(' '); - } - output.append("[]"); //$NON-NLS-1$ - } - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[this.dimensions - 1] != null) { - output.append(' '); - printAnnotations(this.annotationsOnDimensions[this.dimensions - 1], output); - output.append(' '); - } - output.append("..."); //$NON-NLS-1$ - } else { - for (int i= 0 ; i < this.dimensions; i++) { - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[i] != null) { - output.append(" "); //$NON-NLS-1$ - printAnnotations(this.annotationsOnDimensions[i], output); - output.append(" "); //$NON-NLS-1$ - } - output.append("[]"); //$NON-NLS-1$ - } - } - return output; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLevels = this.annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - int annotationsLength = this.annotations[i] == null ? 0 : this.annotations[i].length; - for (int j = 0; j < annotationsLength; j++) - this.annotations[i][j].traverse(visitor, scope); - } - } - if (this.annotationsOnDimensions != null) { - for (int i = 0, max = this.annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = this.annotationsOnDimensions[i]; - for (int j = 0, max2 = annotations2 == null ? 0 : annotations2.length; j < max2; j++) { - Annotation annotation = annotations2[j]; - annotation.traverse(visitor, scope); - } - } - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLevels = this.annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - int annotationsLength = this.annotations[i] == null ? 0 : this.annotations[i].length; - for (int j = 0; j < annotationsLength; j++) - this.annotations[i][j].traverse(visitor, scope); - } - } - if (this.annotationsOnDimensions != null) { - for (int i = 0, max = this.annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = this.annotationsOnDimensions[i]; - for (int j = 0, max2 = annotations2 == null ? 0 : annotations2.length; j < max2; j++) { - Annotation annotation = annotations2[j]; - annotation.traverse(visitor, scope); - } - } - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java deleted file mode 100644 index a5470eb..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java +++ /dev/null @@ -1,244 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -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.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -public class ArrayReference extends Reference { - - public Expression receiver; - public Expression position; - -public ArrayReference(Expression rec, Expression pos) { - this.receiver = rec; - this.position = pos; - this.sourceStart = rec.sourceStart; -} - -@Override -public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean compoundAssignment) { - // TODO (maxime) optimization: unconditionalInits is applied to all existing calls - // account for potential ArrayIndexOutOfBoundsException: - flowContext.recordAbruptExit(); - if (assignment.expression == null) { - return analyseCode(currentScope, flowContext, flowInfo); - } - flowInfo = assignment - .expression - .analyseCode( - currentScope, - flowContext, - analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()); - if (currentScope.environment().usesNullTypeAnnotations()) { - checkAgainstNullTypeAnnotation(currentScope, this.resolvedType, assignment.expression, flowContext, flowInfo); - } - return flowInfo; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo); - this.receiver.checkNPE(currentScope, flowContext, flowInfo, 1); - flowInfo = this.position.analyseCode(currentScope, flowContext, flowInfo); - this.position.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - // account for potential ArrayIndexOutOfBoundsException: - flowContext.recordAbruptExit(); - return flowInfo; -} - -@Override -public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - if ((this.resolvedType.tagBits & TagBits.AnnotationNullable) != 0) { - scope.problemReporter().arrayReferencePotentialNullReference(this); - return true; - } else { - return super.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck); - } -} - -@Override -public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { - int pc = codeStream.position; - this.receiver.generateCode(currentScope, codeStream, true); - if (this.receiver instanceof CastExpression // ((type[])null)[0] - && ((CastExpression)this.receiver).innermostCastedExpression().resolvedType == TypeBinding.NULL){ - codeStream.checkcast(this.receiver.resolvedType); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - this.position.generateCode(currentScope, codeStream, true); - assignment.expression.generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(this.resolvedType.id, valueRequired); - if (valueRequired) { - codeStream.generateImplicitConversion(assignment.implicitConversion); - } -} - -/** - * Code generation for a array reference - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - this.receiver.generateCode(currentScope, codeStream, true); - if (this.receiver instanceof CastExpression // ((type[])null)[0] - && ((CastExpression)this.receiver).innermostCastedExpression().resolvedType == TypeBinding.NULL){ - codeStream.checkcast(this.receiver.resolvedType); - } - this.position.generateCode(currentScope, codeStream, true); - codeStream.arrayAt(this.resolvedType.id); - // Generating code for the potential runtime type checking - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; - // conversion only generated if unboxing - if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion); - switch (isUnboxing ? postConversionType(currentScope).id : this.resolvedType.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { - this.receiver.generateCode(currentScope, codeStream, true); - if (this.receiver instanceof CastExpression // ((type[])null)[0] - && ((CastExpression)this.receiver).innermostCastedExpression().resolvedType == TypeBinding.NULL){ - codeStream.checkcast(this.receiver.resolvedType); - } - this.position.generateCode(currentScope, codeStream, true); - codeStream.dup2(); - codeStream.arrayAt(this.resolvedType.id); - int operationTypeID; - switch(operationTypeID = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { - case T_JavaLangString : - case T_JavaLangObject : - case T_undefined : - codeStream.generateStringConcatenationAppend(currentScope, null, expression); - break; - default : - // promote the array reference to the suitable operation type - codeStream.generateImplicitConversion(this.implicitConversion); - // generate the increment value (will by itself be promoted to the operation value) - if (expression == IntLiteral.One) { // prefix operation - codeStream.generateConstant(expression.constant, this.implicitConversion); - } else { - expression.generateCode(currentScope, codeStream, true); - } - // perform the operation - codeStream.sendOperator(operator, operationTypeID); - // cast the value back to the array reference type - codeStream.generateImplicitConversion(assignmentImplicitConversion); - } - codeStream.arrayAtPut(this.resolvedType.id, valueRequired); -} - -@Override -public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { - this.receiver.generateCode(currentScope, codeStream, true); - if (this.receiver instanceof CastExpression // ((type[])null)[0] - && ((CastExpression)this.receiver).innermostCastedExpression().resolvedType == TypeBinding.NULL){ - codeStream.checkcast(this.receiver.resolvedType); - } - this.position.generateCode(currentScope, codeStream, true); - codeStream.dup2(); - codeStream.arrayAt(this.resolvedType.id); - if (valueRequired) { - switch(this.resolvedType.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2_x2(); - break; - default : - codeStream.dup_x2(); - break; - } - } - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateConstant( - postIncrement.expression.constant, - this.implicitConversion); - codeStream.sendOperator(postIncrement.operator, this.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.generateImplicitConversion( - postIncrement.preAssignImplicitConversion); - codeStream.arrayAtPut(this.resolvedType.id, false); -} - -@Override -public StringBuilder printExpression(int indent, StringBuilder output) { - this.receiver.printExpression(0, output).append('['); - return this.position.printExpression(0, output).append(']'); -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - this.constant = Constant.NotAConstant; - if (this.receiver instanceof CastExpression // no cast check for ((type[])null)[0] - && ((CastExpression)this.receiver).innermostCastedExpression() instanceof NullLiteral) { - this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - } - TypeBinding arrayType = this.receiver.resolveType(scope); - if (arrayType != null) { - this.receiver.computeConversion(scope, arrayType, arrayType); - if (arrayType.isArrayType()) { - TypeBinding elementType = ((ArrayBinding) arrayType).elementsType(); - this.resolvedType = ((this.bits & ASTNode.IsStrictlyAssigned) == 0) ? elementType.capture(scope, this.sourceStart, this.sourceEnd) : elementType; - } else { - scope.problemReporter().referenceMustBeArrayTypeAt(arrayType, this); - } - } - TypeBinding positionType = this.position.resolveTypeExpecting(scope, TypeBinding.INT); - if (positionType != null) { - this.position.computeConversion(scope, TypeBinding.INT, positionType); - } - return this.resolvedType; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.receiver.traverse(visitor, scope); - this.position.traverse(visitor, scope); - } - visitor.endVisit(this, scope); -} - -@Override -public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - if (this.resolvedType != null && (this.resolvedType.tagBits & TagBits.AnnotationNullMASK) == 0L && this.resolvedType.isFreeTypeVariable()) { - return FlowInfo.FREE_TYPEVARIABLE; - } - return super.nullStatus(flowInfo, flowContext); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java deleted file mode 100644 index 9535c41..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ArrayTypeReference.java +++ /dev/null @@ -1,307 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - * Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" - * Bug 466713 - Null Annotations: NullPointerException using as Type Param - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.function.Consumer; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -public class ArrayTypeReference extends SingleTypeReference { - public int dimensions; - private Annotation[][] annotationsOnDimensions; // jsr308 style type annotations on dimensions. - public int originalSourceEnd; - public int extendedDimensions; - public TypeBinding leafComponentTypeWithoutDefaultNullness; - - /** - * ArrayTypeReference constructor comment. - * @param source char[] - * @param dimensions int - * @param pos int - */ - public ArrayTypeReference(char[] source, int dimensions, long pos) { - - super(source, pos); - this.originalSourceEnd = this.sourceEnd; - this.dimensions = dimensions ; - this.annotationsOnDimensions = null; - } - - public ArrayTypeReference(char[] source, int dimensions, Annotation[][] annotationsOnDimensions, long pos) { - this(source, dimensions, pos); - if (annotationsOnDimensions != null) { - this.bits |= ASTNode.HasTypeAnnotations; - } - this.annotationsOnDimensions = annotationsOnDimensions; - } - - @Override - public int dimensions() { - - return this.dimensions; - } - - @Override - public int extraDimensions() { - return this.extendedDimensions; - } - - /** - @see org.eclipse.jdt.internal.compiler.ast.TypeReference#getAnnotationsOnDimensions(boolean) - */ - @Override - public Annotation[][] getAnnotationsOnDimensions(boolean useSourceOrder) { - if (useSourceOrder || this.annotationsOnDimensions == null || this.annotationsOnDimensions.length == 0 || this.extendedDimensions == 0 || this.extendedDimensions == this.dimensions) - return this.annotationsOnDimensions; - Annotation [][] externalAnnotations = new Annotation[this.dimensions][]; - final int baseDimensions = this.dimensions - this.extendedDimensions; - System.arraycopy(this.annotationsOnDimensions, baseDimensions, externalAnnotations, 0, this.extendedDimensions); - System.arraycopy(this.annotationsOnDimensions, 0, externalAnnotations, this.extendedDimensions, baseDimensions); - return externalAnnotations; - } - - @Override - public void setAnnotationsOnDimensions(Annotation [][] annotationsOnDimensions) { - this.annotationsOnDimensions = annotationsOnDimensions; - } - - @Override - public Annotation[] getTopAnnotations() { - if (this.annotationsOnDimensions != null) - return this.annotationsOnDimensions[0]; - return new Annotation[0]; - } - - /** - * @return char[][] - */ - @Override - public char [][] getParameterizedTypeName(){ - int dim = this.dimensions; - char[] dimChars = new char[dim*2]; - for (int i = 0; i < dim; i++) { - int index = i*2; - dimChars[index] = '['; - dimChars[index+1] = ']'; - } - return new char[][]{ CharOperation.concat(this.token, dimChars) }; - } - @Override - protected TypeBinding getTypeBinding(Scope scope) { - - if (this.resolvedType != null) { - return this.resolvedType; - } - if (this.dimensions > 255) { - scope.problemReporter().tooManyDimensions(this); - } - TypeBinding leafComponentType = scope.getType(this.token); - return scope.createArrayType(leafComponentType, this.dimensions); - - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output){ - - super.printExpression(indent, output); - if ((this.bits & IsVarArgs) != 0) { - for (int i= 0 ; i < this.dimensions - 1; i++) { - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[i] != null) { - output.append(' '); - printAnnotations(this.annotationsOnDimensions[i], output); - output.append(' '); - } - output.append("[]"); //$NON-NLS-1$ - } - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[this.dimensions - 1] != null) { - output.append(' '); - printAnnotations(this.annotationsOnDimensions[this.dimensions - 1], output); - output.append(' '); - } - output.append("..."); //$NON-NLS-1$ - } else { - for (int i= 0 ; i < this.dimensions; i++) { - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions[i] != null) { - output.append(" "); //$NON-NLS-1$ - printAnnotations(this.annotationsOnDimensions[i], output); - output.append(" "); //$NON-NLS-1$ - } - output.append("[]"); //$NON-NLS-1$ - } - } - return output; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - Annotation [] typeAnnotations = this.annotations[0]; - for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) { - typeAnnotations[i].traverse(visitor, scope); - } - } - if (this.annotationsOnDimensions != null) { - for (int i = 0, max = this.annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = this.annotationsOnDimensions[i]; - if (annotations2 != null) { - for (int j = 0, max2 = annotations2.length; j < max2; j++) { - Annotation annotation = annotations2[j]; - annotation.traverse(visitor, scope); - } - } - } - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - Annotation [] typeAnnotations = this.annotations[0]; - for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) { - typeAnnotations[i].traverse(visitor, scope); - } - } - if (this.annotationsOnDimensions != null) { - for (int i = 0, max = this.annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = this.annotationsOnDimensions[i]; - if (annotations2 != null) { - for (int j = 0, max2 = annotations2.length; j < max2; j++) { - Annotation annotation = annotations2[j]; - annotation.traverse(visitor, scope); - } - } - } - } - } - visitor.endVisit(this, scope); - } - - @Override - protected TypeBinding internalResolveType(Scope scope, int location) { - TypeBinding internalResolveType = super.internalResolveType(scope, location); - internalResolveType = maybeMarkArrayContentsNonNull(scope, internalResolveType, this.sourceStart, this.dimensions, - leafType -> this.leafComponentTypeWithoutDefaultNullness = leafType); - - return internalResolveType; - } - - static TypeBinding maybeMarkArrayContentsNonNull(Scope scope, TypeBinding typeBinding, int sourceStart, int dimensions, Consumer leafConsumer) { - LookupEnvironment environment = scope.environment(); - if (environment.usesNullTypeAnnotations() - && scope.hasDefaultNullnessFor(Binding.DefaultLocationArrayContents, sourceStart)) { - typeBinding = addNonNullToDimensions(scope, typeBinding, environment.getNonNullAnnotation(), dimensions); - - TypeBinding leafComponentType = typeBinding.leafComponentType(); - if ((leafComponentType.tagBits & TagBits.AnnotationNullMASK) == 0 && leafComponentType.acceptsNonNullDefault()) { - if (leafConsumer != null) - leafConsumer.accept(leafComponentType); - TypeBinding nonNullLeafComponentType = scope.environment().createNonNullAnnotatedType(leafComponentType); - typeBinding = scope.createArrayType(nonNullLeafComponentType, typeBinding.dimensions(), - typeBinding.getTypeAnnotations()); - } - } - return typeBinding; - } - - static TypeBinding addNonNullToDimensions(Scope scope, TypeBinding typeBinding, - AnnotationBinding nonNullAnnotation, int dimensions2) { - AnnotationBinding[][] newAnnots = new AnnotationBinding[dimensions2][]; - AnnotationBinding[] oldAnnots = typeBinding.getTypeAnnotations(); - if (oldAnnots == null) { - for (int i = 1; i < dimensions2; i++) { - newAnnots[i] = new AnnotationBinding[] { nonNullAnnotation }; - } - } else { - int j = 0; - for (int i = 0; i < dimensions2; i++) { - if (j >= oldAnnots.length || oldAnnots[j] == null) { - if (i != 0) { - newAnnots[i] = new AnnotationBinding[] { nonNullAnnotation }; - } - j++; - } else { - int k = j; - boolean seen = false; - while (oldAnnots[k] != null) { - seen |= oldAnnots[k].getAnnotationType() - .hasNullBit(TypeIds.BitNonNullAnnotation | TypeIds.BitNullableAnnotation); - k++; - } - if (seen || i == 0) { - if (k > j) { - AnnotationBinding[] annotationsForDimension = new AnnotationBinding[k - j]; - System.arraycopy(oldAnnots, j, annotationsForDimension, 0, k - j); - newAnnots[i] = annotationsForDimension; - } - } else { - AnnotationBinding[] annotationsForDimension = new AnnotationBinding[k - j + 1]; - annotationsForDimension[0] = nonNullAnnotation; - System.arraycopy(oldAnnots, j, annotationsForDimension, 1, k - j); - newAnnots[i] = annotationsForDimension; - } - j = k + 1; - } - } - } - return scope.environment().createAnnotatedType(typeBinding, newAnnots); - } - - @Override - public boolean hasNullTypeAnnotation(AnnotationPosition position) { - switch (position) { - case LEAF_TYPE: - // ignore annotationsOnDimensions: - return super.hasNullTypeAnnotation(position); - case MAIN_TYPE: - // outermost dimension only: - if (this.annotationsOnDimensions != null && this.annotationsOnDimensions.length > 0) { - Annotation[] innerAnnotations = this.annotationsOnDimensions[0]; - return containsNullAnnotation(innerAnnotations); - } - // e.g. subclass ParameterizedSingleTypeReference is not only used for arrays - return super.hasNullTypeAnnotation(position); - case ANY: - if (super.hasNullTypeAnnotation(position)) - return true; - if (this.resolvedType != null && !this.resolvedType.hasNullTypeAnnotations()) - return false; // shortcut - if (this.annotationsOnDimensions != null) { - for (int i = 0; i < this.annotationsOnDimensions.length; i++) { - Annotation[] innerAnnotations = this.annotationsOnDimensions[i]; - if (containsNullAnnotation(innerAnnotations)) - return true; - } - } - } - return false; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java deleted file mode 100644 index 6c830cb..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/AssertStatement.java +++ /dev/null @@ -1,224 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 403086 - [compiler][null] include the effect of 'assert' in syntactic null analysis for fields - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.ASTVisitor; - -public class AssertStatement extends Statement { - - public Expression assertExpression, exceptionArgument; - - // for local variable attribute - int preAssertInitStateIndex = -1; - private FieldBinding assertionSyntheticFieldBinding; - -public AssertStatement( Expression exceptionArgument, Expression assertExpression, int startPosition) { - this.assertExpression = assertExpression; - this.exceptionArgument = exceptionArgument; - this.sourceStart = startPosition; - this.sourceEnd = exceptionArgument.sourceEnd; -} - -public AssertStatement(Expression assertExpression, int startPosition) { - this.assertExpression = assertExpression; - this.sourceStart = startPosition; - this.sourceEnd = assertExpression.sourceEnd; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - this.preAssertInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); - - Constant cst = this.assertExpression.optimizedBooleanConstant(); - this.assertExpression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - boolean isOptimizedTrueAssertion = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false; - - flowContext.tagBits |= FlowContext.HIDE_NULL_COMPARISON_WARNING; - FlowInfo conditionFlowInfo = this.assertExpression.analyseCode(currentScope, flowContext, flowInfo.copy()); - flowContext.extendTimeToLiveForNullCheckedField(1); // survive this assert as a Statement - flowContext.tagBits &= ~FlowContext.HIDE_NULL_COMPARISON_WARNING; - UnconditionalFlowInfo assertWhenTrueInfo = conditionFlowInfo.initsWhenTrue().unconditionalInits(); - FlowInfo assertInfo = conditionFlowInfo.initsWhenFalse(); - if (isOptimizedTrueAssertion) { - assertInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - - if (this.exceptionArgument != null) { - // only gets evaluated when escaping - results are not taken into account - FlowInfo exceptionInfo = this.exceptionArgument.analyseCode(currentScope, flowContext, assertInfo.copy()); - - if (isOptimizedTrueAssertion){ - currentScope.problemReporter().fakeReachable(this.exceptionArgument); - } else { - flowContext.checkExceptionHandlers( - currentScope.getJavaLangAssertionError(), - this, - exceptionInfo, - currentScope); - } - } - - if (!isOptimizedTrueAssertion){ - // add the assert support in the clinit - manageSyntheticAccessIfNecessary(currentScope, flowInfo); - } - // account for potential AssertionError: - flowContext.recordAbruptExit(); - if (isOptimizedFalseAssertion) { - return flowInfo; // if assertions are enabled, the following code will be unreachable - // change this if we need to carry null analysis results of the assert - // expression downstream - } else { - CompilerOptions compilerOptions = currentScope.compilerOptions(); - if (!compilerOptions.includeNullInfoFromAsserts) { - // keep just the initializations info, don't include assert's null info - // merge initialization info's and then add back the null info from flowInfo to - // make sure that the empty null info of assertInfo doesnt change flowInfo's null info. - return ((flowInfo.nullInfoLessUnconditionalCopy()).mergedWith(assertInfo.nullInfoLessUnconditionalCopy())).addNullInfoFrom(flowInfo); - } - return flowInfo.mergedWith(assertInfo.nullInfoLessUnconditionalCopy()). - addInitializationsFrom(assertWhenTrueInfo.discardInitializationInfo()); - // keep the merge from the initial code for the definite assignment - // analysis, tweak the null part to influence nulls downstream - } -} - -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - - if (this.assertionSyntheticFieldBinding != null) { - BranchLabel assertionActivationLabel = new BranchLabel(codeStream); - codeStream.fieldAccess(Opcodes.OPC_getstatic, this.assertionSyntheticFieldBinding, null /* default declaringClass */); - codeStream.ifne(assertionActivationLabel); - - BranchLabel falseLabel; - this.assertExpression.generateOptimizedBoolean(currentScope, codeStream, (falseLabel = new BranchLabel(codeStream)), null , true); - codeStream.newJavaLangAssertionError(); - codeStream.dup(); - if (this.exceptionArgument != null) { - this.exceptionArgument.generateCode(currentScope, codeStream, true); - codeStream.invokeJavaLangAssertionErrorConstructor(this.exceptionArgument.implicitConversion & 0xF); - } else { - codeStream.invokeJavaLangAssertionErrorDefaultConstructor(); - } - codeStream.athrow(); - - // May loose some local variable initializations : affecting the local variable attributes - if (this.preAssertInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preAssertInitStateIndex); - } - falseLabel.place(); - assertionActivationLabel.place(); - } else { - // May loose some local variable initializations : affecting the local variable attributes - if (this.preAssertInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preAssertInitStateIndex); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public void resolve(BlockScope scope) { - this.assertExpression.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); - if (this.exceptionArgument != null) { - TypeBinding exceptionArgumentType = this.exceptionArgument.resolveType(scope); - if (exceptionArgumentType != null){ - int id = exceptionArgumentType.id; - switch(id) { - case T_void : - scope.problemReporter().illegalVoidExpression(this.exceptionArgument); - //$FALL-THROUGH$ - default: - id = T_JavaLangObject; - //$FALL-THROUGH$ - case T_boolean : - case T_byte : - case T_char : - case T_short : - case T_double : - case T_float : - case T_int : - case T_long : - case T_JavaLangString : - this.exceptionArgument.implicitConversion = (id << 4) + id; - } - } - } -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.assertExpression.traverse(visitor, scope); - if (this.exceptionArgument != null) { - this.exceptionArgument.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); -} - -public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - // need assertion flag: $assertionsDisabled on outer most source clas - // (in case of static member of interface, will use the outermost static member - bug 22334) - SourceTypeBinding outerMostClass = currentScope.enclosingSourceType(); - while (outerMostClass.isLocalType()) { - ReferenceBinding enclosing = outerMostClass.enclosingType(); - if (enclosing == null || enclosing.isInterface()) break; - outerMostClass = (SourceTypeBinding) enclosing; - } - this.assertionSyntheticFieldBinding = outerMostClass.addSyntheticFieldForAssert(currentScope); - - // find and enable assertion support - TypeDeclaration typeDeclaration = outerMostClass.scope.referenceType(); - AbstractMethodDeclaration[] methods = typeDeclaration.methods; - for (int i = 0, max = methods.length; i < max; i++) { - AbstractMethodDeclaration method = methods[i]; - if (method.isClinit()) { - ((Clinit) method).setAssertionSupport(this.assertionSyntheticFieldBinding, currentScope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_5); - break; - } - } - } -} - -@Override -public StringBuilder printStatement(int tab, StringBuilder output) { - printIndent(tab, output); - output.append("assert "); //$NON-NLS-1$ - this.assertExpression.printExpression(0, output); - if (this.exceptionArgument != null) { - output.append(": "); //$NON-NLS-1$ - this.exceptionArgument.printExpression(0, output); - } - return output.append(';'); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Assignment.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Assignment.java deleted file mode 100644 index bc4535a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Assignment.java +++ /dev/null @@ -1,299 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Genady Beriozkin - added support for reporting assignment with no effect - * Stephan Herrmann - Contributions for - * 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 - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 358903 - Filter practically unimportant resource leak warnings - * bug 370639 - [compiler][resource] restore the default for resource leak warnings - * bug 365859 - [compiler][null] distinguish warnings based on flow analysis vs. null annotations - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 388996 - [compiler][resource] Incorrect 'potential resource leak' - * bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional - * bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation. - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 453483 - [compiler][null][loop] Improve null analysis for loops - * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.ASSIGNMENT_CONTEXT; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class Assignment extends Expression { - - public Expression lhs; - public Expression expression; - -public Assignment(Expression lhs, Expression expression, int sourceEnd) { - this.lhs = lhs; - lhs.bits |= IsStrictlyAssigned; // tag lhs as assigned - this.expression = expression; - this.sourceStart = lhs.sourceStart; - this.sourceEnd = sourceEnd; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // record setting a variable: various scenarii are possible, setting an array reference, -// a field reference, a blank final field reference, a field of an enclosing instance or -// just a local variable. - LocalVariableBinding local = this.lhs.localVariableBinding(); - this.expression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - - FlowInfo preInitInfo = null; - CompilerOptions compilerOptions = currentScope.compilerOptions(); - boolean shouldAnalyseResource = false; - if (flowInfo.reachMode() == FlowInfo.REACHABLE - && compilerOptions.analyseResourceLeaks - && (FakedTrackingVariable.isAnyCloseable(this.expression.resolvedType) - || this.expression.resolvedType == TypeBinding.NULL)) - { - shouldAnalyseResource = local != null - || ((this.lhs.bits & Binding.FIELD) != 0 & compilerOptions.isAnnotationBasedResourceAnalysisEnabled); - } - - if (shouldAnalyseResource && local != null) { - preInitInfo = flowInfo.unconditionalCopy(); - // analysis of resource leaks needs additional context while analyzing the RHS of assignment to local: - FakedTrackingVariable.preConnectTrackerAcrossAssignment(this, local, this.expression, flowInfo, compilerOptions.isAnnotationBasedResourceAnalysisEnabled); - } - - flowInfo = ((Reference) this.lhs) - .analyseAssignment(currentScope, flowContext, flowInfo, this, false) - .unconditionalInits(); - - if (shouldAnalyseResource) { - if (local != null) { - // assignment to local - FakedTrackingVariable.handleResourceAssignment(currentScope, preInitInfo, flowInfo, flowContext, this, this.expression, local); - } else { - // assignment to field - FakedTrackingVariable.handleResourceFieldAssignment(currentScope, flowInfo, flowContext, this, this.expression); - FakedTrackingVariable.cleanUpAfterAssignment(currentScope, this.lhs.bits, this.expression); - } - } else { - FakedTrackingVariable.cleanUpAfterAssignment(currentScope, this.lhs.bits, this.expression); - } - - int nullStatus = this.expression.nullStatus(flowInfo, flowContext); - if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { - if (nullStatus == FlowInfo.NULL) { - flowContext.recordUsingNullReference(currentScope, local, this.lhs, - FlowContext.CAN_ONLY_NULL | FlowContext.IN_ASSIGNMENT, flowInfo); - } - } - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { - VariableBinding var = this.lhs.nullAnnotatedVariableBinding(compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8); - if (var != null) { - nullStatus = NullAnnotationMatching.checkAssignment(currentScope, flowContext, var, flowInfo, nullStatus, this.expression, this.expression.resolvedType); - if (nullStatus == FlowInfo.NON_NULL - && var instanceof FieldBinding - && this.lhs instanceof Reference - && compilerOptions.enableSyntacticNullAnalysisForFields) - { - int timeToLive = (this.bits & InsideExpressionStatement) != 0 - ? 2 // assignment is statement: make info survives the end of this statement - : 1; // assignment is expression: expire on next event. - flowContext.recordNullCheckedFieldReference((Reference) this.lhs, timeToLive); - } - } - } - if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { - flowInfo.markNullStatus(local, nullStatus); - flowContext.markFinallyNullStatus(local, nullStatus); - } - return flowInfo; -} - -void checkAssignment(BlockScope scope, TypeBinding lhsType, TypeBinding rhsType) { - FieldBinding leftField = getLastField(this.lhs); - if (leftField != null && rhsType != TypeBinding.NULL && (lhsType.kind() == Binding.WILDCARD_TYPE) && ((WildcardBinding)lhsType).boundKind != Wildcard.SUPER) { - scope.problemReporter().wildcardAssignment(lhsType, rhsType, this.expression); - } else if (leftField != null && !leftField.isStatic() && leftField.declaringClass != null /*length pseudo field*/&& leftField.declaringClass.isRawType()) { - scope.problemReporter().unsafeRawFieldAssignment(leftField, rhsType, this.lhs); - } else if (rhsType.needsUncheckedConversion(lhsType)) { - scope.problemReporter().unsafeTypeConversion(this.expression, rhsType, lhsType); - } -} - -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - // various scenarii are possible, setting an array reference, - // a field reference, a blank final field reference, a field of an enclosing instance or - // just a local variable. - - int pc = codeStream.position; - ((Reference) this.lhs).generateAssignment(currentScope, codeStream, this, valueRequired); - // variable may have been optimized out - // the lhs is responsible to perform the implicitConversion generation for the assignment since optimized for unused local assignment. - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -FieldBinding getLastField(Expression someExpression) { - if (someExpression instanceof SingleNameReference) { - if ((someExpression.bits & RestrictiveFlagMASK) == Binding.FIELD) { - return (FieldBinding) ((SingleNameReference)someExpression).binding; - } - } else if (someExpression instanceof FieldReference) { - return ((FieldReference)someExpression).binding; - } else if (someExpression instanceof QualifiedNameReference) { - QualifiedNameReference qName = (QualifiedNameReference) someExpression; - if (qName.otherBindings == null) { - if ((someExpression.bits & RestrictiveFlagMASK) == Binding.FIELD) { - return (FieldBinding)qName.binding; - } - } else { - return qName.otherBindings[qName.otherBindings.length - 1]; - } - } - return null; -} - -@Override -public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - if ((this.implicitConversion & TypeIds.BOXING) != 0) - return FlowInfo.NON_NULL; - return this.expression.nullStatus(flowInfo, flowContext); -} - -@Override -public StringBuilder print(int indent, StringBuilder output) { - //no () when used as a statement - printIndent(indent, output); - return printExpressionNoParenthesis(indent, output); -} -@Override -public StringBuilder printExpression(int indent, StringBuilder output) { - //subclass redefine printExpressionNoParenthesis() - output.append('('); - return printExpressionNoParenthesis(0, output).append(')'); -} - -public StringBuilder printExpressionNoParenthesis(int indent, StringBuilder output) { - this.lhs.printExpression(indent, output).append(" = "); //$NON-NLS-1$ - return this.expression.printExpression(0, output); -} - -@Override -public StringBuilder printStatement(int indent, StringBuilder output) { - //no () when used as a statement - return print(indent, output).append(';'); -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - // due to syntax lhs may be only a NameReference, a FieldReference or an ArrayReference - this.constant = Constant.NotAConstant; - if (!(this.lhs instanceof Reference) || this.lhs.isThis()) { - scope.problemReporter().expressionShouldBeAVariable(this.lhs); - return null; - } - TypeBinding lhsType = this.lhs.resolveType(scope); - this.expression.setExpressionContext(ASSIGNMENT_CONTEXT); - this.expression.setExpectedType(lhsType); // needed in case of generic method invocation - if (lhsType != null) { - this.resolvedType = lhsType.capture(scope, this.lhs.sourceStart, this.lhs.sourceEnd); // make it unique, `this' shares source end with 'this.expression'. - } - LocalVariableBinding localVariableBinding = this.lhs.localVariableBinding(); - if (localVariableBinding != null && (localVariableBinding.isCatchParameter() || localVariableBinding.isParameter())) { - localVariableBinding.tagBits &= ~TagBits.IsEffectivelyFinal; // as it is already definitely assigned, we can conclude already. Also note: catch parameter cannot be compound assigned. - } - TypeBinding rhsType = this.expression.resolveType(scope); - if (lhsType == null || rhsType == null) { - return null; - } - // check for assignment with no effect - Binding left = getDirectBinding(this.lhs); - if (left != null && !left.isVolatile() && left == getDirectBinding(this.expression)) { - scope.problemReporter().assignmentHasNoEffect(this, left.shortReadableName()); - } - - // Compile-time conversion of base-types : implicit narrowing integer into byte/short/character - // may require to widen the rhs expression at runtime - if (TypeBinding.notEquals(lhsType, rhsType)) { // must call before computeConversion() and typeMismatchError() - scope.compilationUnitScope().recordTypeConversion(lhsType, rhsType); - } - if (this.expression.isConstantValueOfTypeAssignableToType(rhsType, lhsType) - || rhsType.isCompatibleWith(lhsType, scope)) { - this.expression.computeConversion(scope, lhsType, rhsType); - checkAssignment(scope, lhsType, rhsType); - if (this.expression instanceof CastExpression - && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) { - CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression); - } - return this.resolvedType; - } else if (isBoxingCompatible(rhsType, lhsType, this.expression, scope)) { - this.expression.computeConversion(scope, lhsType, rhsType); - if (this.expression instanceof CastExpression - && (this.expression.bits & ASTNode.UnnecessaryCast) == 0) { - CastExpression.checkNeedForAssignedCast(scope, lhsType, (CastExpression) this.expression); - } - return this.resolvedType; - } - scope.problemReporter().typeMismatchError(rhsType, lhsType, this.expression, this.lhs); - return lhsType; -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#resolveTypeExpecting(org.eclipse.jdt.internal.compiler.lookup.BlockScope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) - */ -@Override -public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) { - - TypeBinding type = super.resolveTypeExpecting(scope, expectedType); - if (type == null) return null; - TypeBinding lhsType = this.resolvedType; - TypeBinding rhsType = this.expression.resolvedType; - // signal possible accidental boolean assignment (instead of using '==' operator) - if (TypeBinding.equalsEquals(expectedType, TypeBinding.BOOLEAN) - && TypeBinding.equalsEquals(lhsType, TypeBinding.BOOLEAN) - && (this.lhs.bits & IsStrictlyAssigned) != 0) { - scope.problemReporter().possibleAccidentalBooleanAssignment(this); - } - checkAssignment(scope, lhsType, rhsType); - return type; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.lhs.traverse(visitor, scope); - this.expression.traverse(visitor, scope); - } - visitor.endVisit(this, scope); -} -@Override -public LocalVariableBinding localVariableBinding() { - return this.lhs.localVariableBinding(); -} -@Override -public boolean statementExpression() { - return ((this.bits & ASTNode.ParenthesizedMASK) == 0); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java deleted file mode 100644 index 6edaeec..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java +++ /dev/null @@ -1,1994 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 383368 - [compiler][null] syntactic null analysis for field references - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.List; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class BinaryExpression extends OperatorExpression { - -/* Tracking helpers - * The following are used to elaborate realistic statistics about binary - * expressions. This must be neutralized in the released code. - * Search the keyword BE_INSTRUMENTATION to reenable. - * An external device must install a suitable probe so as to monitor the - * emission of events and publish the results. - public interface Probe { - public void ping(int depth); - } - public int depthTracker; - public static Probe probe; - */ - - public Expression left, right; - public Constant optimizedBooleanConstant; - -public BinaryExpression(Expression left, Expression right, int operator) { - this.left = left; - this.right = right; - this.bits |= operator << ASTNode.OperatorSHIFT; // encode operator - this.sourceStart = left.sourceStart; - this.sourceEnd = right.sourceEnd; - // BE_INSTRUMENTATION: neutralized in the released code -// if (left instanceof BinaryExpression && -// ((left.bits & OperatorMASK) ^ (this.bits & OperatorMASK)) == 0) { -// this.depthTracker = ((BinaryExpression)left).depthTracker + 1; -// } else { -// this.depthTracker = 1; -// } -} -public BinaryExpression(BinaryExpression expression) { - this.left = expression.left; - this.right = expression.right; - this.bits = expression.bits; - this.sourceStart = expression.sourceStart; - this.sourceEnd = expression.sourceEnd; -} -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // keep implementation in sync with CombinedBinaryExpression#analyseCode - try { - if (this.resolvedType.id == TypeIds.T_JavaLangString) { - return this.right.analyseCode( - currentScope, flowContext, - this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()) - .unconditionalInits(); - } else { - flowInfo = this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - this.left.checkNPE(currentScope, flowContext, flowInfo); - if (((this.bits & OperatorMASK) >> OperatorSHIFT) != AND) { - flowContext.expireNullCheckedFieldInfo(); - } - flowInfo = this.right.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - this.right.checkNPE(currentScope, flowContext, flowInfo); - if (((this.bits & OperatorMASK) >> OperatorSHIFT) != AND) { - flowContext.expireNullCheckedFieldInfo(); - } - return flowInfo; - } - } finally { - // account for exception possibly thrown by arithmetics - flowContext.recordAbruptExit(); - } -} - -@Override -protected void updateFlowOnBooleanResult(FlowInfo flowInfo, boolean result) { - int operator = (this.bits & OperatorMASK) >> OperatorSHIFT; - if (result ? operator == AND_AND : operator == OR_OR) { - this.left.updateFlowOnBooleanResult(flowInfo, result); - this.right.updateFlowOnBooleanResult(flowInfo, result); - } -} - -public void computeConstant(BlockScope scope, int leftId, int rightId) { - //compute the constant when valid - if ((this.left.constant != Constant.NotAConstant) - && (this.right.constant != Constant.NotAConstant)) { - try { - this.constant = - Constant.computeConstantOperation( - this.left.constant, - leftId, - (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT, - this.right.constant, - rightId); - } catch (ArithmeticException e) { - this.constant = Constant.NotAConstant; - // 1.2 no longer throws an exception at compile-time - //scope.problemReporter().compileTimeConstantThrowsArithmeticException(this); - } - } else { - this.constant = Constant.NotAConstant; - //add some work for the boolean operators & | - this.optimizedBooleanConstant( - leftId, - (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT, - rightId); - } -} - -@Override -public Constant optimizedBooleanConstant() { - return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant; -} - -/** - * Code generation for a binary operation - */ -// given the current focus of CombinedBinaryExpression on strings concatenation, -// we do not provide a general, non-recursive implementation of generateCode, -// but rely upon generateOptimizedStringConcatenationCreation instead -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (this.constant != Constant.NotAConstant) { - if (valueRequired) - codeStream.generateConstant(this.constant, this.implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - switch ((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) { - case PLUS : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_JavaLangString : - // BE_INSTRUMENTATION: neutralized in the released code -// if (probe != null) { -// probe.ping(this.depthTracker); -// } - codeStream.generateStringConcatenationAppend(currentScope, this.left, this.right); - if (!valueRequired) - codeStream.pop(); - break; - case T_int : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.iadd(); - break; - case T_long : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.ladd(); - break; - case T_double : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.dadd(); - break; - case T_float : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.fadd(); - break; - } - break; - case MINUS : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.isub(); - break; - case T_long : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.lsub(); - break; - case T_double : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.dsub(); - break; - case T_float : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.fsub(); - break; - } - break; - case MULTIPLY : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.imul(); - break; - case T_long : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.lmul(); - break; - case T_double : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.dmul(); - break; - case T_float : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.fmul(); - break; - } - break; - case DIVIDE : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - this.left.generateCode(currentScope, codeStream, true); - this.right.generateCode(currentScope, codeStream, true); - codeStream.idiv(); - if (!valueRequired) - codeStream.pop(); - break; - case T_long : - this.left.generateCode(currentScope, codeStream, true); - this.right.generateCode(currentScope, codeStream, true); - codeStream.ldiv(); - if (!valueRequired) - codeStream.pop2(); - break; - case T_double : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.ddiv(); - break; - case T_float : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.fdiv(); - break; - } - break; - case REMAINDER : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - this.left.generateCode(currentScope, codeStream, true); - this.right.generateCode(currentScope, codeStream, true); - codeStream.irem(); - if (!valueRequired) - codeStream.pop(); - break; - case T_long : - this.left.generateCode(currentScope, codeStream, true); - this.right.generateCode(currentScope, codeStream, true); - codeStream.lrem(); - if (!valueRequired) - codeStream.pop2(); - break; - case T_double : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.drem(); - break; - case T_float : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.frem(); - break; - } - break; - case AND : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - // 0 & x - if ((this.left.constant != Constant.NotAConstant) - && (this.left.constant.typeID() == TypeIds.T_int) - && (this.left.constant.intValue() == 0)) { - this.right.generateCode(currentScope, codeStream, false); - if (valueRequired) - codeStream.iconst_0(); - } else { - // x & 0 - if ((this.right.constant != Constant.NotAConstant) - && (this.right.constant.typeID() == TypeIds.T_int) - && (this.right.constant.intValue() == 0)) { - this.left.generateCode(currentScope, codeStream, false); - if (valueRequired) - codeStream.iconst_0(); - } else { - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.iand(); - } - } - break; - case T_long : - // 0 & x - if ((this.left.constant != Constant.NotAConstant) - && (this.left.constant.typeID() == TypeIds.T_long) - && (this.left.constant.longValue() == 0L)) { - this.right.generateCode(currentScope, codeStream, false); - if (valueRequired) - codeStream.lconst_0(); - } else { - // x & 0 - if ((this.right.constant != Constant.NotAConstant) - && (this.right.constant.typeID() == TypeIds.T_long) - && (this.right.constant.longValue() == 0L)) { - this.left.generateCode(currentScope, codeStream, false); - if (valueRequired) - codeStream.lconst_0(); - } else { - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.land(); - } - } - break; - case T_boolean : // logical and - generateLogicalAnd(currentScope, codeStream, valueRequired); - break; - } - break; - case OR : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - // 0 | x - if ((this.left.constant != Constant.NotAConstant) - && (this.left.constant.typeID() == TypeIds.T_int) - && (this.left.constant.intValue() == 0)) { - this.right.generateCode(currentScope, codeStream, valueRequired); - } else { - // x | 0 - if ((this.right.constant != Constant.NotAConstant) - && (this.right.constant.typeID() == TypeIds.T_int) - && (this.right.constant.intValue() == 0)) { - this.left.generateCode(currentScope, codeStream, valueRequired); - } else { - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.ior(); - } - } - break; - case T_long : - // 0 | x - if ((this.left.constant != Constant.NotAConstant) - && (this.left.constant.typeID() == TypeIds.T_long) - && (this.left.constant.longValue() == 0L)) { - this.right.generateCode(currentScope, codeStream, valueRequired); - } else { - // x | 0 - if ((this.right.constant != Constant.NotAConstant) - && (this.right.constant.typeID() == TypeIds.T_long) - && (this.right.constant.longValue() == 0L)) { - this.left.generateCode(currentScope, codeStream, valueRequired); - } else { - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.lor(); - } - } - break; - case T_boolean : // logical or - generateLogicalOr(currentScope, codeStream, valueRequired); - break; - } - break; - case XOR : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - // 0 ^ x - if ((this.left.constant != Constant.NotAConstant) - && (this.left.constant.typeID() == TypeIds.T_int) - && (this.left.constant.intValue() == 0)) { - this.right.generateCode(currentScope, codeStream, valueRequired); - } else { - // x ^ 0 - if ((this.right.constant != Constant.NotAConstant) - && (this.right.constant.typeID() == TypeIds.T_int) - && (this.right.constant.intValue() == 0)) { - this.left.generateCode(currentScope, codeStream, valueRequired); - } else { - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.ixor(); - } - } - break; - case T_long : - // 0 ^ x - if ((this.left.constant != Constant.NotAConstant) - && (this.left.constant.typeID() == TypeIds.T_long) - && (this.left.constant.longValue() == 0L)) { - this.right.generateCode(currentScope, codeStream, valueRequired); - } else { - // x ^ 0 - if ((this.right.constant != Constant.NotAConstant) - && (this.right.constant.typeID() == TypeIds.T_long) - && (this.right.constant.longValue() == 0L)) { - this.left.generateCode(currentScope, codeStream, valueRequired); - } else { - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.lxor(); - } - } - break; - case T_boolean : - generateLogicalXor(currentScope, codeStream, valueRequired); - break; - } - break; - case LEFT_SHIFT : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.ishl(); - break; - case T_long : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.lshl(); - } - break; - case RIGHT_SHIFT : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.ishr(); - break; - case T_long : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.lshr(); - } - break; - case UNSIGNED_RIGHT_SHIFT : - switch (this.bits & ASTNode.ReturnTypeIDMASK) { - case T_int : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.iushr(); - break; - case T_long : - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) - codeStream.lushr(); - } - break; - case GREATER : - BranchLabel falseLabel, endLabel; - generateOptimizedGreaterThan( - currentScope, - codeStream, - null, - (falseLabel = new BranchLabel(codeStream)), - valueRequired); - if (valueRequired) { - codeStream.iconst_1(); - if ((this.bits & ASTNode.IsReturnedValue) != 0) { - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - falseLabel.place(); - codeStream.iconst_0(); - } else { - codeStream.goto_(endLabel = new BranchLabel(codeStream)); - codeStream.decrStackSize(1); - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } - break; - case GREATER_EQUAL : - generateOptimizedGreaterThanOrEqual( - currentScope, - codeStream, - null, - (falseLabel = new BranchLabel(codeStream)), - valueRequired); - if (valueRequired) { - codeStream.iconst_1(); - if ((this.bits & ASTNode.IsReturnedValue) != 0) { - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - falseLabel.place(); - codeStream.iconst_0(); - } else { - codeStream.goto_(endLabel = new BranchLabel(codeStream)); - codeStream.decrStackSize(1); - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } - break; - case LESS : - generateOptimizedLessThan( - currentScope, - codeStream, - null, - (falseLabel = new BranchLabel(codeStream)), - valueRequired); - if (valueRequired) { - codeStream.iconst_1(); - if ((this.bits & ASTNode.IsReturnedValue) != 0) { - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - falseLabel.place(); - codeStream.iconst_0(); - } else { - codeStream.goto_(endLabel = new BranchLabel(codeStream)); - codeStream.decrStackSize(1); - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } - break; - case LESS_EQUAL : - generateOptimizedLessThanOrEqual( - currentScope, - codeStream, - null, - (falseLabel = new BranchLabel(codeStream)), - valueRequired); - if (valueRequired) { - codeStream.iconst_1(); - if ((this.bits & ASTNode.IsReturnedValue) != 0) { - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - falseLabel.place(); - codeStream.iconst_0(); - } else { - codeStream.goto_(endLabel = new BranchLabel(codeStream)); - codeStream.decrStackSize(1); - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } - } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -/** - * Boolean operator code generation. Optimized operations are: {@code <, <=, >, >=, &, |, ^} - */ -@Override -public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == TypeIds.T_boolean)) { - super.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - return; - } - switch ((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) { - case LESS : - generateOptimizedLessThan( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - return; - case LESS_EQUAL : - generateOptimizedLessThanOrEqual( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - return; - case GREATER : - generateOptimizedGreaterThan( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - return; - case GREATER_EQUAL : - generateOptimizedGreaterThanOrEqual( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - return; - case AND : - generateOptimizedLogicalAnd( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - return; - case OR : - generateOptimizedLogicalOr( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - return; - case XOR : - generateOptimizedLogicalXor( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - return; - } - super.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); -} - -/** - * Boolean generation for > - */ -public void generateOptimizedGreaterThan(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; - // both sides got promoted in the same way - if (promotedTypeID == TypeIds.T_int) { - // 0 > x - if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) { - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicitly falling through the FALSE case - codeStream.iflt(trueLabel); - } - } else { - if (trueLabel == null) { - // implicitly falling through the TRUE case - codeStream.ifge(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - // x > 0 - if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) { - this.left.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicitly falling through the FALSE case - codeStream.ifgt(trueLabel); - } - } else { - if (trueLabel == null) { - // implicitly falling through the TRUE case - codeStream.ifle(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - } - // default comparison - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - switch (promotedTypeID) { - case T_int : - codeStream.if_icmpgt(trueLabel); - break; - case T_float : - codeStream.fcmpl(); - codeStream.ifgt(trueLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifgt(trueLabel); - break; - case T_double : - codeStream.dcmpl(); - codeStream.ifgt(trueLabel); - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - } else { - if (trueLabel == null) { - // implicit falling through the TRUE case - switch (promotedTypeID) { - case T_int : - codeStream.if_icmple(falseLabel); - break; - case T_float : - codeStream.fcmpl(); - codeStream.ifle(falseLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifle(falseLabel); - break; - case T_double : - codeStream.dcmpl(); - codeStream.ifle(falseLabel); - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } -} - -/** - * Boolean generation for >= - */ -public void generateOptimizedGreaterThanOrEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; - // both sides got promoted in the same way - if (promotedTypeID == TypeIds.T_int) { - // 0 >= x - if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) { - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicitly falling through the FALSE case - codeStream.ifle(trueLabel); - } - } else { - if (trueLabel == null) { - // implicitly falling through the TRUE case - codeStream.ifgt(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - // x >= 0 - if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) { - this.left.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicitly falling through the FALSE case - codeStream.ifge(trueLabel); - } - } else { - if (trueLabel == null) { - // implicitly falling through the TRUE case - codeStream.iflt(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - } - // default comparison - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - switch (promotedTypeID) { - case T_int : - codeStream.if_icmpge(trueLabel); - break; - case T_float : - codeStream.fcmpl(); - codeStream.ifge(trueLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifge(trueLabel); - break; - case T_double : - codeStream.dcmpl(); - codeStream.ifge(trueLabel); - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - } else { - if (trueLabel == null) { - // implicit falling through the TRUE case - switch (promotedTypeID) { - case T_int : - codeStream.if_icmplt(falseLabel); - break; - case T_float : - codeStream.fcmpl(); - codeStream.iflt(falseLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.iflt(falseLabel); - break; - case T_double : - codeStream.dcmpl(); - codeStream.iflt(falseLabel); - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } -} - -/** - * Boolean generation for {@code <} - */ -public void generateOptimizedLessThan(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; - // both sides got promoted in the same way - if (promotedTypeID == TypeIds.T_int) { - // 0 < x - if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) { - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicitly falling through the FALSE case - codeStream.ifgt(trueLabel); - } - } else { - if (trueLabel == null) { - // implicitly falling through the TRUE case - codeStream.ifle(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - // x < 0 - if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) { - this.left.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicitly falling through the FALSE case - codeStream.iflt(trueLabel); - } - } else { - if (trueLabel == null) { - // implicitly falling through the TRUE case - codeStream.ifge(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - } - // default comparison - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - switch (promotedTypeID) { - case T_int : - codeStream.if_icmplt(trueLabel); - break; - case T_float : - codeStream.fcmpg(); - codeStream.iflt(trueLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.iflt(trueLabel); - break; - case T_double : - codeStream.dcmpg(); - codeStream.iflt(trueLabel); - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - } else { - if (trueLabel == null) { - // implicit falling through the TRUE case - switch (promotedTypeID) { - case T_int : - codeStream.if_icmpge(falseLabel); - break; - case T_float : - codeStream.fcmpg(); - codeStream.ifge(falseLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifge(falseLabel); - break; - case T_double : - codeStream.dcmpg(); - codeStream.ifge(falseLabel); - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } -} - -/** - * Boolean generation for {@code <=} - */ -public void generateOptimizedLessThanOrEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; - // both sides got promoted in the same way - if (promotedTypeID == TypeIds.T_int) { - // 0 <= x - if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) { - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicitly falling through the FALSE case - codeStream.ifge(trueLabel); - } - } else { - if (trueLabel == null) { - // implicitly falling through the TRUE case - codeStream.iflt(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - // x <= 0 - if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) { - this.left.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicitly falling through the FALSE case - codeStream.ifle(trueLabel); - } - } else { - if (trueLabel == null) { - // implicitly falling through the TRUE case - codeStream.ifgt(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - } - // default comparison - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - switch (promotedTypeID) { - case T_int : - codeStream.if_icmple(trueLabel); - break; - case T_float : - codeStream.fcmpg(); - codeStream.ifle(trueLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifle(trueLabel); - break; - case T_double : - codeStream.dcmpg(); - codeStream.ifle(trueLabel); - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } - } else { - if (trueLabel == null) { - // implicit falling through the TRUE case - switch (promotedTypeID) { - case T_int : - codeStream.if_icmpgt(falseLabel); - break; - case T_float : - codeStream.fcmpg(); - codeStream.ifgt(falseLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifgt(falseLabel); - break; - case T_double : - codeStream.dcmpg(); - codeStream.ifgt(falseLabel); - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - return; - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } -} - -/** - * Boolean generation for {@code &} - */ -public void generateLogicalAnd(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - Constant condConst; - if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) { - if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // & x - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, valueRequired); - } else { - // & x - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, false); - if (valueRequired) { - codeStream.iconst_0(); - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } - return; - } - if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // x & - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, false); - } else { - // x & - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, false); - if (valueRequired) { - codeStream.iconst_0(); - } - // reposition the endPC - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } - return; - } - } - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.iand(); - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); -} - -/** - * Boolean generation for | - */ -public void generateLogicalOr(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - Constant condConst; - if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) { - if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // | x - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, false); - if (valueRequired) { - codeStream.iconst_1(); - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } else { - // | x - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, valueRequired); - } - return; - } - if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // x | - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, false); - if (valueRequired) { - codeStream.iconst_1(); - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } else { - // x | - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, false); - } - return; - } - } - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.ior(); - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); -} - -/** - * Boolean generation for ^ - */ -public void generateLogicalXor(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - Constant condConst; - if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) { - if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // ^ x - this.left.generateCode(currentScope, codeStream, false); - if (valueRequired) { - codeStream.iconst_1(); - } - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.ixor(); // negate - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } - } else { - // ^ x - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, valueRequired); - } - return; - } - if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // x ^ - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, false); - if (valueRequired) { - codeStream.iconst_1(); - codeStream.ixor(); // negate - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } - } else { - // x ^ - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, false); - } - return; - } - } - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.ixor(); - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); -} - -/** - * Boolean generation for {@code &} - */ -public void generateOptimizedLogicalAnd(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - Constant condConst; - if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) { - if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // & x - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - } else { - // & x - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - if (valueRequired) { - if (falseLabel != null) { - // implicit falling through the TRUE case - codeStream.goto_(falseLabel); - } - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } - return; - } - if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // x & - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - } else { - // x & - BranchLabel internalTrueLabel = new BranchLabel(codeStream); - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - internalTrueLabel, - falseLabel, - false); - internalTrueLabel.place(); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - if (valueRequired) { - if (falseLabel != null) { - // implicit falling through the TRUE case - codeStream.goto_(falseLabel); - } - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } - return; - } - } - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.iand(); - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - codeStream.ifne(trueLabel); - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.ifeq(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); -} - -/** - * Boolean generation for | - */ -public void generateOptimizedLogicalOr(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - Constant condConst; - if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) { - if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // | x - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - BranchLabel internalFalseLabel = new BranchLabel(codeStream); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - internalFalseLabel, - false); - internalFalseLabel.place(); - if (valueRequired) { - if (trueLabel != null) { - codeStream.goto_(trueLabel); - } - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } else { - // | x - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - } - return; - } - if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // x | - BranchLabel internalFalseLabel = new BranchLabel(codeStream); - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - internalFalseLabel, - false); - internalFalseLabel.place(); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - if (valueRequired) { - if (trueLabel != null) { - codeStream.goto_(trueLabel); - } - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } else { - // x | - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - } - return; - } - } - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.ior(); - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - codeStream.ifne(trueLabel); - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.ifeq(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); -} - -/** - * Boolean generation for ^ - */ -public void generateOptimizedLogicalXor(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - Constant condConst; - if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) { - if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // ^ x - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - falseLabel, // negating - trueLabel, - valueRequired); - } else { - // ^ x - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - } - return; - } - if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (condConst.booleanValue() == true) { - // x ^ - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - falseLabel, // negating - trueLabel, - valueRequired); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - } else { - // x ^ - this.left.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - this.right.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - false); - } - return; - } - } - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.ixor(); - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - codeStream.ifne(trueLabel); - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.ifeq(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); -} -@Override -public void buildStringForConcatation(BlockScope blockScope, CodeStream codeStream, int typeID, StringBuilder recipe, List argTypes) { - if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) - && ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) { - if (this.constant != Constant.NotAConstant) { - super.buildStringForConcatation(blockScope, codeStream, typeID, recipe, argTypes); - } else { - this.left.buildStringForConcatation(blockScope, codeStream, this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK, recipe, argTypes); - this.right.buildStringForConcatation(blockScope, codeStream, this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK, recipe, argTypes); - } - } else { - super.buildStringForConcatation(blockScope, codeStream, typeID, recipe, argTypes); - } -} -@Override -public void generateOptimizedStringConcatenation(BlockScope blockScope, CodeStream codeStream, int typeID) { - // keep implementation in sync with CombinedBinaryExpression - // #generateOptimizedStringConcatenation - /* In the case trying to make a string concatenation, there is no need to create a new - * string buffer, thus use a lower-level API for code generation involving only the - * appending of arguments to the existing StringBuffer - */ - - if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) - && ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) { - if (this.constant != Constant.NotAConstant) { - codeStream.generateConstant(this.constant, this.implicitConversion); - codeStream.invokeStringConcatenationAppendForType(this.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - } else { - int pc = codeStream.position; - this.left.generateOptimizedStringConcatenation( - blockScope, - codeStream, - this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.recordPositionsFrom(pc, this.left.sourceStart); - pc = codeStream.position; - this.right.generateOptimizedStringConcatenation( - blockScope, - codeStream, - this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.recordPositionsFrom(pc, this.right.sourceStart); - } - } else { - super.generateOptimizedStringConcatenation(blockScope, codeStream, typeID); - } -} - -@Override -public void generateOptimizedStringConcatenationCreation(BlockScope blockScope, CodeStream codeStream, int typeID) { - // keep implementation in sync with CombinedBinaryExpression - // #generateOptimizedStringConcatenationCreation - /* In the case trying to make a string concatenation, there is no need to create a new - * string buffer, thus use a lower-level API for code generation involving only the - * appending of arguments to the existing StringBuffer - */ - if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) - && ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) { - if (this.constant != Constant.NotAConstant) { - codeStream.newStringContatenation(); // new: java.lang.StringBuffer - codeStream.dup(); - codeStream.ldc(this.constant.stringValue()); - codeStream.invokeStringConcatenationStringConstructor(); - // invokespecial: java.lang.StringBuffer.(Ljava.lang.String;)V - } else { - int pc = codeStream.position; - this.left.generateOptimizedStringConcatenationCreation( - blockScope, - codeStream, - this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.recordPositionsFrom(pc, this.left.sourceStart); - pc = codeStream.position; - this.right.generateOptimizedStringConcatenation( - blockScope, - codeStream, - this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.recordPositionsFrom(pc, this.right.sourceStart); - } - } else { - super.generateOptimizedStringConcatenationCreation(blockScope, codeStream, typeID); - } -} - -@Override -public boolean isCompactableOperation() { - return true; -} - -/** - * Separates into a reusable method the subpart of {@link - * #resolveType(BlockScope)} that needs to be executed while climbing up the - * chain of expressions of this' leftmost branch. For use by {@link - * CombinedBinaryExpression#resolveType(BlockScope)}. - * @param scope the scope within which the resolution occurs - */ -void nonRecursiveResolveTypeUpwards(BlockScope scope) { - // keep implementation in sync with BinaryExpression#resolveType - boolean leftIsCast, rightIsCast; - TypeBinding leftType = this.left.resolvedType; - - if ((rightIsCast = this.right instanceof CastExpression) == true) { - this.right.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - } - TypeBinding rightType = this.right.resolveType(scope); - - // use the id of the type to navigate into the table - if (leftType == null || rightType == null) { - this.constant = Constant.NotAConstant; - return; - } - - int leftTypeID = leftType.id; - int rightTypeID = rightType.id; - - // autoboxing support - boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; - if (use15specifics) { - if (!leftType.isBaseType() && rightTypeID != TypeIds.T_JavaLangString && rightTypeID != TypeIds.T_null) { - leftTypeID = scope.environment().computeBoxingType(leftType).id; - } - if (!rightType.isBaseType() && leftTypeID != TypeIds.T_JavaLangString && leftTypeID != TypeIds.T_null) { - rightTypeID = scope.environment().computeBoxingType(rightType).id; - } - } - if (leftTypeID > 15 - || rightTypeID > 15) { // must convert String + Object || Object + String - if (leftTypeID == TypeIds.T_JavaLangString) { - rightTypeID = TypeIds.T_JavaLangObject; - } else if (rightTypeID == TypeIds.T_JavaLangString) { - leftTypeID = TypeIds.T_JavaLangObject; - } else { - this.constant = Constant.NotAConstant; - scope.problemReporter().invalidOperator(this, leftType, rightType); - return; - } - } - if (((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) { - if (leftTypeID == TypeIds.T_JavaLangString) { - this.left.computeConversion(scope, leftType, leftType); - if (rightType.isArrayType() && TypeBinding.equalsEquals(((ArrayBinding) rightType).elementsType(), TypeBinding.CHAR)) { - scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.right); - } - } - if (rightTypeID == TypeIds.T_JavaLangString) { - this.right.computeConversion(scope, rightType, rightType); - if (leftType.isArrayType() && TypeBinding.equalsEquals(((ArrayBinding) leftType).elementsType(), TypeBinding.CHAR)) { - scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.left); - } - } - } - - // the code is an int - // (cast) left Op (cast) right --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 <<0 - - // Don't test for result = 0. If it is zero, some more work is done. - // On the one hand when it is not zero (correct code) we avoid doing the test - int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT; - int operatorSignature = OperatorExpression.OperatorSignatures[operator][(leftTypeID << 4) + rightTypeID]; - - this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType); - this.right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), rightType); - this.bits |= operatorSignature & 0xF; - switch (operatorSignature & 0xF) { // record the current ReturnTypeID - // only switch on possible result type..... - case T_boolean : - this.resolvedType = TypeBinding.BOOLEAN; - break; - case T_byte : - this.resolvedType = TypeBinding.BYTE; - break; - case T_char : - this.resolvedType = TypeBinding.CHAR; - break; - case T_double : - this.resolvedType = TypeBinding.DOUBLE; - break; - case T_float : - this.resolvedType = TypeBinding.FLOAT; - break; - case T_int : - this.resolvedType = TypeBinding.INT; - break; - case T_long : - this.resolvedType = TypeBinding.LONG; - break; - case T_JavaLangString : - this.resolvedType = scope.getJavaLangString(); - break; - default : //error........ - this.constant = Constant.NotAConstant; - scope.problemReporter().invalidOperator(this, leftType, rightType); - return; - } - - // check need for operand cast - if ((leftIsCast = (this.left instanceof CastExpression)) == true || - rightIsCast) { - CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, this.left, leftTypeID, leftIsCast, this.right, rightTypeID, rightIsCast); - } - // compute the constant when valid - computeConstant(scope, leftTypeID, rightTypeID); -} - -public void optimizedBooleanConstant(int leftId, int operator, int rightId) { - switch (operator) { - case AND : - if ((leftId != TypeIds.T_boolean) || (rightId != TypeIds.T_boolean)) - return; - //$FALL-THROUGH$ - case AND_AND : - Constant cst; - if ((cst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (cst.booleanValue() == false) { // left is equivalent to false - this.optimizedBooleanConstant = cst; // constant(false) - return; - } else { //left is equivalent to true - if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - this.optimizedBooleanConstant = cst; - // the conditional result is equivalent to the right conditional value - } - return; - } - } - if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (cst.booleanValue() == false) { // right is equivalent to false - this.optimizedBooleanConstant = cst; // constant(false) - } - } - return; - case OR : - if ((leftId != TypeIds.T_boolean) || (rightId != TypeIds.T_boolean)) - return; - //$FALL-THROUGH$ - case OR_OR : - if ((cst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (cst.booleanValue() == true) { // left is equivalent to true - this.optimizedBooleanConstant = cst; // constant(true) - return; - } else { //left is equivalent to false - if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - this.optimizedBooleanConstant = cst; - } - return; - } - } - if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) { - if (cst.booleanValue() == true) { // right is equivalent to true - this.optimizedBooleanConstant = cst; // constant(true) - } - } - } -} - -@Override -public StringBuilder printExpressionNoParenthesis(int indent, StringBuilder output) { - // keep implementation in sync with - // CombinedBinaryExpression#printExpressionNoParenthesis - this.left.printExpression(indent, output).append(' ').append(operatorToString()).append(' '); - return this.right.printExpression(0, output); -} - -@Override -public void addPatternVariables(BlockScope scope, CodeStream codeStream) { - this.left.addPatternVariables(scope, codeStream); // Srikanth - this.right.addPatternVariables(scope, codeStream); -} -@Override -public boolean containsPatternVariable() { - return this.left.containsPatternVariable() || this.right.containsPatternVariable(); -} -@Override -public TypeBinding resolveType(BlockScope scope) { - // keep implementation in sync with CombinedBinaryExpression#resolveType - // and nonRecursiveResolveTypeUpwards - boolean leftIsCast, rightIsCast; - if ((leftIsCast = this.left instanceof CastExpression) == true) this.left.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - TypeBinding leftType = this.left.resolveType(scope); - - if ((rightIsCast = this.right instanceof CastExpression) == true) this.right.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - - LocalVariableBinding [] patternVars = switch ((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) { - case AND_AND -> this.left.bindingsWhenTrue(); - case OR_OR -> this.left.bindingsWhenFalse(); - default -> NO_VARIABLES; - }; - - TypeBinding rightType = this.right.resolveTypeWithBindings(patternVars, scope); - - /* - * 6.3.1 Scope for Pattern Variables in Expressions - * 6.3.1.1 Conditional-And Operator && - * - * It is a compile-time error if any of the following conditions hold: - • A pattern variable is both (i) introduced by a when true and (ii) introduced by - b when true. - • A pattern variable is both (i) introduced by a when false and (ii) introduced by - b when false. - - ... - - * 6.3.1.2 Conditional-Or Operator || - * - * It is a compile-time error if any of the following conditions hold: - • A pattern variable is both (i) introduced by a when true and (ii) introduced by - b when true. - • A pattern variable is both (i) introduced by a when false and (ii) introduced by - b when false. - */ - - // We handle only the cases NOT already diagnosed in due course to avoid double jeopardy - switch ((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) { - case AND_AND -> { - scope.reportClashingDeclarations(this.left.bindingsWhenFalse(), this.right.bindingsWhenFalse()); - } - case OR_OR -> { - scope.reportClashingDeclarations(this.left.bindingsWhenTrue(), this.right.bindingsWhenTrue()); - } - } - - // use the id of the type to navigate into the table - if (leftType == null || rightType == null) { - this.constant = Constant.NotAConstant; - return null; - } - - int leftTypeID = leftType.id; - int rightTypeID = rightType.id; - - // autoboxing support - boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; - if (use15specifics) { - if (!leftType.isBaseType() && rightTypeID != TypeIds.T_JavaLangString && rightTypeID != TypeIds.T_null) { - leftTypeID = scope.environment().computeBoxingType(leftType).id; - } - if (!rightType.isBaseType() && leftTypeID != TypeIds.T_JavaLangString && leftTypeID != TypeIds.T_null) { - rightTypeID = scope.environment().computeBoxingType(rightType).id; - } - } - if (leftTypeID > 15 - || rightTypeID > 15) { // must convert String + Object || Object + String - if (leftTypeID == TypeIds.T_JavaLangString) { - rightTypeID = TypeIds.T_JavaLangObject; - } else if (rightTypeID == TypeIds.T_JavaLangString) { - leftTypeID = TypeIds.T_JavaLangObject; - } else { - this.constant = Constant.NotAConstant; - scope.problemReporter().invalidOperator(this, leftType, rightType); - return null; - } - } - if (((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) { - if (leftTypeID == TypeIds.T_JavaLangString) { - this.left.computeConversion(scope, leftType, leftType); - if (rightType.isArrayType() && TypeBinding.equalsEquals(((ArrayBinding) rightType).elementsType(), TypeBinding.CHAR)) { - scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.right); - } - } - if (rightTypeID == TypeIds.T_JavaLangString) { - this.right.computeConversion(scope, rightType, rightType); - if (leftType.isArrayType() && TypeBinding.equalsEquals(((ArrayBinding) leftType).elementsType(), TypeBinding.CHAR)) { - scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.left); - } - } - } - - // the code is an int - // (cast) left Op (cast) right --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 <<0 - - // Don't test for result = 0. If it is zero, some more work is done. - // On the one hand when it is not zero (correct code) we avoid doing the test - int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT; - int operatorSignature = OperatorExpression.OperatorSignatures[operator][(leftTypeID << 4) + rightTypeID]; - - this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType); - this.right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), rightType); - this.bits |= operatorSignature & 0xF; - switch (operatorSignature & 0xF) { // record the current ReturnTypeID - // only switch on possible result type..... - case T_boolean : - this.resolvedType = TypeBinding.BOOLEAN; - break; - case T_byte : - this.resolvedType = TypeBinding.BYTE; - break; - case T_char : - this.resolvedType = TypeBinding.CHAR; - break; - case T_double : - this.resolvedType = TypeBinding.DOUBLE; - break; - case T_float : - this.resolvedType = TypeBinding.FLOAT; - break; - case T_int : - this.resolvedType = TypeBinding.INT; - break; - case T_long : - this.resolvedType = TypeBinding.LONG; - break; - case T_JavaLangString : - this.resolvedType = scope.getJavaLangString(); - break; - default : //error........ - this.constant = Constant.NotAConstant; - scope.problemReporter().invalidOperator(this, leftType, rightType); - return null; - } - - // check need for operand cast - if (leftIsCast || rightIsCast) { - CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, this.left, leftTypeID, leftIsCast, this.right, rightTypeID, rightIsCast); - } - // compute the constant when valid - computeConstant(scope, leftTypeID, rightTypeID); - return this.resolvedType; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.left.traverse(visitor, scope); - this.right.traverse(visitor, scope); - } - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Block.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Block.java deleted file mode 100644 index 3e3db4a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Block.java +++ /dev/null @@ -1,190 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 349326 - [1.7] new warning for missing try-with-resources - * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check - * Bug 440282 - [resource] Resource leak detection false negative with empty finally block - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class Block extends Statement { - - public Statement[] statements; - public int explicitDeclarations; - // the number of explicit declaration , used to create scope - public BlockScope scope; - -public Block(int explicitDeclarations) { - this.explicitDeclarations = explicitDeclarations; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // empty block - if (this.statements == null) return flowInfo; - int complaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; - CompilerOptions compilerOptions = currentScope.compilerOptions(); - boolean enableSyntacticNullAnalysisForFields = compilerOptions.enableSyntacticNullAnalysisForFields; - for (int i = 0, max = this.statements.length; i < max; i++) { - Statement stat = this.statements[i]; - if ((complaintLevel = stat.complainIfUnreachable(flowInfo, this.scope, complaintLevel, true)) < Statement.COMPLAINED_UNREACHABLE) { - flowInfo = stat.analyseCode(this.scope, flowContext, flowInfo); - } - // record the effect of stat on the finally block of an enclosing try-finally, if any: - flowContext.mergeFinallyNullInfo(flowInfo); - if (enableSyntacticNullAnalysisForFields) { - flowContext.expireNullCheckedFieldInfo(); - } - if (compilerOptions.analyseResourceLeaks) { - FakedTrackingVariable.cleanUpUnassigned(this.scope, stat, flowInfo, false); - } - } - if (this.scope != currentScope) { - // if block is tracking any resources other than the enclosing 'currentScope', analyse them now: - this.scope.checkUnclosedCloseables(flowInfo, flowContext, null, null); - } - if (this.explicitDeclarations > 0) { - // cleanup assignment info for locals that are scoped to this block: - LocalVariableBinding[] locals = this.scope.locals; - if (locals != null) { - int numLocals = this.scope.localIndex; - for (int i = 0; i < numLocals; i++) { - flowInfo.resetAssignmentInfo(locals[i]); - } - } - } - return flowInfo; -} -/** - * Code generation for a block - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - if (this.statements != null) { - for (Statement stmt : this.statements) { - stmt.generateCode(this.scope, codeStream); - } - } // for local variable debug attributes - if (this.scope != currentScope) { // was really associated with its own scope - codeStream.exitUserScope(this.scope); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public boolean isEmptyBlock() { - return this.statements == null; -} - -public StringBuilder printBody(int indent, StringBuilder output) { - if (this.statements == null) return output; - for (int i = 0; i < this.statements.length; i++) { - this.statements[i].printStatement(indent + 1, output); - output.append('\n'); - } - return output; -} - -@Override -public StringBuilder printStatement(int indent, StringBuilder output) { - printIndent(indent, output); - output.append("{\n"); //$NON-NLS-1$ - printBody(indent, output); - return printIndent(indent, output).append('}'); -} - -@Override -public void resolve(BlockScope upperScope) { - if ((this.bits & UndocumentedEmptyBlock) != 0) { - upperScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd); - } - if (this.statements != null) { - this.scope = - this.explicitDeclarations == 0 - ? upperScope - : new BlockScope(upperScope, this.explicitDeclarations); - resolveStatements(this.statements, this.scope); - } -} - -public void resolveUsing(BlockScope givenScope) { - if ((this.bits & UndocumentedEmptyBlock) != 0) { - givenScope.problemReporter().undocumentedEmptyBlock(this.sourceStart, this.sourceEnd); - } - // this optimized resolve(...) is sent only on none empty blocks - this.scope = givenScope; - if (this.statements != null) { - resolveStatements(this.statements, this.scope); - } -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) { - if (this.statements != null) { - for (int i = 0, length = this.statements.length; i < length; i++) - this.statements[i].traverse(visitor, this.scope); - } - } - visitor.endVisit(this, blockScope); -} - -/** - * Dispatch the call on its last statement. - */ -@Override -public void branchChainTo(BranchLabel label) { - if (this.statements != null) { - this.statements[this.statements.length - 1].branchChainTo(label); - } -} - -// A block does not complete normally if the last statement which we presume is reachable does not complete normally. -@Override -public boolean doesNotCompleteNormally() { - int length = this.statements == null ? 0 : this.statements.length; - return length > 0 && this.statements[length - 1].doesNotCompleteNormally(); -} - -@Override -public boolean completesByContinue() { - int length = this.statements == null ? 0 : this.statements.length; - return length > 0 && this.statements[length - 1].completesByContinue(); -} - -@Override -public boolean canCompleteNormally() { - int length = this.statements == null ? 0 : this.statements.length; - return length == 0 || this.statements[length - 1].canCompleteNormally(); -} - -@Override -public boolean continueCompletes() { - int length = this.statements == null ? 0 : this.statements.length; - return length > 0 && this.statements[length - 1].continueCompletes(); -} - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java deleted file mode 100644 index 59522df..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/BranchStatement.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public abstract class BranchStatement extends Statement { - - public char[] label; - public BranchLabel targetLabel; - public SubRoutineStatement[] subroutines; - public int initStateIndex = -1; - -/** - * BranchStatement constructor comment. - */ -public BranchStatement(char[] label, int sourceStart,int sourceEnd) { - this.label = label ; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; -} - -protected void setSubroutineSwitchExpression(SubRoutineStatement sub) { - // Do nothing -} -protected void restartExceptionLabels(CodeStream codeStream) { - // do nothing -} -/** - * Branch code generation - * - * generate the finallyInvocationSequence. - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) { - return; - } - int pc = codeStream.position; - - // generation of code responsible for invoking the finally - // blocks in sequence - if (this.subroutines != null){ - for (int i = 0, max = this.subroutines.length; i < max; i++){ - SubRoutineStatement sub = this.subroutines[i]; - SwitchExpression se = sub.getSwitchExpression(); - setSubroutineSwitchExpression(sub); - boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); - sub.setSwitchExpression(se); - if (didEscape) { - codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); - if (this.initStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); - } - restartExceptionLabels(codeStream); - return; - } - } - } -// checkAndLoadSyntheticVars(codeStream); - codeStream.goto_(this.targetLabel); - codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); - if (this.initStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); - } -} - -@Override -public void resolve(BlockScope scope) { - // nothing to do during name resolution -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java deleted file mode 100644 index 7ae2388..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/BreakStatement.java +++ /dev/null @@ -1,123 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class BreakStatement extends BranchStatement { - - public boolean isSynthetic; -public BreakStatement(char[] label, int sourceStart, int e) { - super(label, sourceStart, e); -} -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - - // here requires to generate a sequence of finally blocks invocations depending corresponding - // to each of the traversed try statements, so that execution will terminate properly. - - // lookup the label, this should answer the returnContext - FlowContext targetContext = (this.label == null) - ? flowContext.getTargetContextForDefaultBreak() - : flowContext.getTargetContextForBreakLabel(this.label); - - if (targetContext == null) { - if (this.label == null) { - currentScope.problemReporter().invalidBreak(this); - } else { - currentScope.problemReporter().undefinedLabel(this); - } - return flowInfo; // pretend it did not break since no actual target - } else if (targetContext == FlowContext.NonLocalGotoThroughSwitchContext) { // JLS 13 14.15 - currentScope.problemReporter().switchExpressionsBreakOutOfSwitchExpression(this); - return flowInfo; // pretend it did not break since no actual target - } - - targetContext.recordAbruptExit(); - targetContext.expireNullCheckedFieldInfo(); - - this.initStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); - - this.targetLabel = targetContext.breakLabel(); - FlowContext traversedContext = flowContext; - int subCount = 0; - this.subroutines = new SubRoutineStatement[5]; - - do { - SubRoutineStatement sub; - if ((sub = traversedContext.subroutine()) != null) { - if (subCount == this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount*2]), 0, subCount); // grow - } - this.subroutines[subCount++] = sub; - if (sub.isSubRoutineEscaping()) { - break; - } - } - traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); - traversedContext.recordBreakTo(targetContext); - - if (traversedContext instanceof InsideSubRoutineFlowContext) { - ASTNode node = traversedContext.associatedNode; - if (node instanceof TryStatement) { - TryStatement tryStatement = (TryStatement) node; - flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits - } - } else if (traversedContext == targetContext) { - // only record break info once accumulated through subroutines, and only against target context - targetContext.recordBreakFrom(flowInfo); - break; - } - } while ((traversedContext = traversedContext.getLocalParent()) != null); - - // resize subroutines - if (subCount != this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount); - } - return FlowInfo.DEAD_END; -} - -@Override -public StringBuilder printStatement(int tab, StringBuilder output) { - printIndent(tab, output).append("break"); //$NON-NLS-1$ - if (this.label != null) output.append(' ').append(this.label); - return output.append(';'); -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockscope) { - visitor.visit(this, blockscope); - visitor.endVisit(this, blockscope); -} -@Override -public boolean doesNotCompleteNormally() { - return true; -} - -@Override -public boolean canCompleteNormally() { - return false; -} - - -@Override -protected boolean doNotReportUnreachable() { - return this.isSynthetic; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java deleted file mode 100644 index 7fd247f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CaseStatement.java +++ /dev/null @@ -1,546 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -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.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.IntConstant; -import org.eclipse.jdt.internal.compiler.impl.JavaFeature; -import org.eclipse.jdt.internal.compiler.impl.StringConstant; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -public class CaseStatement extends Statement { - - static final int CASE_CONSTANT = 1; - static final int CASE_PATTERN = 2; - - public BranchLabel targetLabel; - public Expression[] constantExpressions; // case with multiple expressions - public BranchLabel[] targetLabels; // for multiple expressions - public boolean isExpr = false; - /* package */ int patternIndex = -1; // points to first pattern var index [only one pattern variable allowed now - should be 0] - -public CaseStatement(Expression constantExpression, int sourceEnd, int sourceStart) { - this(sourceEnd, sourceStart, constantExpression != null ? new Expression[] {constantExpression} : null); -} - -public CaseStatement(int sourceEnd, int sourceStart, Expression[] constantExpressions) { - this.constantExpressions = constantExpressions; - this.sourceEnd = sourceEnd; - this.sourceStart = sourceStart; - initPatterns(); -} - -private void initPatterns() { - int l = this.constantExpressions == null ? 0 : this.constantExpressions.length; - for (int i = 0; i < l; ++i) { - Expression e = this.constantExpressions[i]; - if (e instanceof Pattern) { - this.patternIndex = i; - break; - } - } -} - -@Override -public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - if (this.constantExpressions != null) { - int nullPatternCount = 0; - for(int i=0; i < this.constantExpressions.length; i++) { - Expression e = this.constantExpressions[i]; - for (LocalVariableBinding local : e.bindingsWhenTrue()) { - local.useFlag = LocalVariableBinding.USED; // these are structurally required even if not touched - } - nullPatternCount += e instanceof NullLiteral ? 1 : 0; - if (i > 0 && (e instanceof Pattern)) { - if (!(i == nullPatternCount && e instanceof TypePattern)) - currentScope.problemReporter().IllegalFallThroughToPattern(e); - } - flowInfo = analyseConstantExpression(currentScope, flowContext, flowInfo, e); - if (nullPatternCount > 0 && e instanceof TypePattern) { - LocalVariableBinding binding = ((TypePattern) e).local.binding; - if (binding != null) - flowInfo.markNullStatus(binding, FlowInfo.POTENTIALLY_NULL); - } - } - } - return flowInfo; -} -private FlowInfo analyseConstantExpression( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo, - Expression e) { - if (e.constant == Constant.NotAConstant - && !e.resolvedType.isEnum()) { - boolean caseNullorDefaultAllowed = - JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(currentScope.compilerOptions()) - && (e instanceof NullLiteral || e instanceof FakeDefaultLiteral); - if (!caseNullorDefaultAllowed) - currentScope.problemReporter().caseExpressionMustBeConstant(e); - if (e instanceof NullLiteral && flowContext.associatedNode instanceof SwitchStatement) { - Expression switchValue = ((SwitchStatement) flowContext.associatedNode).expression; - if (switchValue != null && switchValue.nullStatus(flowInfo, flowContext) == FlowInfo.NON_NULL) { - currentScope.problemReporter().unnecessaryNullCaseInSwitchOverNonNull(this); - } - } - } - return e.analyseCode(currentScope, flowContext, flowInfo); -} - -@Override -public boolean containsPatternVariable() { - if (this.patternIndex == -1 - || this.constantExpressions.length <= this.patternIndex - || !(this.constantExpressions[this.patternIndex] instanceof Pattern)) { - return false; - } - for (int i = 0, l = this.constantExpressions.length; i < l; ++i) { - if (this.constantExpressions[i] instanceof Pattern) { - Pattern pattern = (Pattern) this.constantExpressions[i]; - if (pattern.containsPatternVariable()) - return true; - } - } - return false; -} -@Override -public StringBuilder printStatement(int tab, StringBuilder output) { - printIndent(tab, output); - if (this.constantExpressions == null) { - output.append("default "); //$NON-NLS-1$ - output.append(this.isExpr ? "->" : ":"); //$NON-NLS-1$ //$NON-NLS-2$ - } else { - output.append("case "); //$NON-NLS-1$ - for (int i = 0, l = this.constantExpressions.length; i < l; ++i) { - this.constantExpressions[i].printExpression(0, output); - if (i < l -1) output.append(','); - } - output.append(this.isExpr ? " ->" : " :"); //$NON-NLS-1$ //$NON-NLS-2$ - } - return output; -} - -/** - * Case code generation - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) { - return; - } - int pc = codeStream.position; - if (this.targetLabels != null) { - for (int i = 0, l = this.targetLabels.length; i < l; ++i) { - this.targetLabels[i].place(); - } - } - if (this.targetLabel != null) - this.targetLabel.place(); - casePatternExpressionGenerateCode(currentScope, codeStream); - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -private void casePatternExpressionGenerateCode(BlockScope currentScope, CodeStream codeStream) { - if (this.patternIndex != -1) { - Pattern pattern = ((Pattern) this.constantExpressions[this.patternIndex]); - if (containsPatternVariable()) { - LocalVariableBinding local = currentScope.findVariable(SwitchStatement.SecretPatternVariableName, null); - codeStream.load(local); - pattern.generateCode(currentScope, codeStream); - } else { - pattern.setTargets(codeStream); - } - - if (!(pattern instanceof GuardedPattern)) - codeStream.goto_(pattern.thenTarget); - } -} - -/** - * No-op : should use resolveCase(...) instead. - */ -@Override -public void resolve(BlockScope scope) { - // no-op : should use resolveCase(...) instead. -} -public static class ResolvedCase { - static final ResolvedCase[] UnresolvedCase = new ResolvedCase[0]; - public Constant c; - public Expression e; - public TypeBinding t; // For ease of access. This.e contains the type binding anyway. - public int index; - private int intValue; - private final boolean isPattern; - private final boolean isQualifiedEnum; - public int enumDescIdx; - public int classDescIdx; - ResolvedCase(Constant c, Expression e, TypeBinding t, int index, boolean isQualifiedEnum) { - this.c = c; - this.e = e; - this.t= t; - this.index = index; - if (c.typeID() == TypeIds.T_JavaLangString) { - this.intValue = c.stringValue().hashCode(); - } else { - this.intValue = c.intValue(); - } - this.isPattern = e instanceof Pattern; - this.isQualifiedEnum = isQualifiedEnum; - } - public int intValue() { - return this.intValue; - } - public boolean isPattern() { - return this.isPattern; - } - public boolean isQualifiedEnum() { - return this.isQualifiedEnum; - } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("case "); //$NON-NLS-1$ - builder.append(this.e); - builder.append(" [CONSTANT="); //$NON-NLS-1$ - builder.append(this.c); - builder.append("]"); //$NON-NLS-1$ - return builder.toString(); - } -} -private Expression getFirstValidExpression(BlockScope scope, SwitchStatement switchStatement) { - assert this.constantExpressions != null; - Expression ret = null; - int nullCaseLabelCount = 0; - - boolean patternSwitchAllowed = JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(scope.compilerOptions()); - if (patternSwitchAllowed) { - int exprCount = 0; - for (Expression e : this.constantExpressions) { - ++exprCount; - if (e instanceof FakeDefaultLiteral) { - scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH, - e.sourceStart, e.sourceEnd); - flagDuplicateDefault(scope, switchStatement, - this.constantExpressions.length > 1 ? e : this); - if (exprCount != 2 || nullCaseLabelCount < 1) { - scope.problemReporter().patternSwitchCaseDefaultOnlyAsSecond(e); - } - continue; - } - if (e instanceof Pattern) { - scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH, - e.sourceStart, e.sourceEnd); - if (this.constantExpressions.length > 1) { - scope.problemReporter().illegalCaseConstantCombination(e); - return e; - } - } else if (e instanceof NullLiteral) { - scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH, - e.sourceStart, e.sourceEnd); - if (switchStatement.nullCase == null) { - switchStatement.nullCase = this; - } - - nullCaseLabelCount++; - // note: case null or case null, default are the only constructs allowed with null - // second condition added since duplicate case label will anyway be flagged - if (exprCount > 1 && nullCaseLabelCount < 2) { - scope.problemReporter().patternSwitchNullOnlyOrFirstWithDefault(e); - return e; // Return and avoid secondary errors - } - } - if (ret == null) ret = e; - } - } else { - for (Expression e : this.constantExpressions) { - if (e instanceof Pattern - || e instanceof NullLiteral - || e instanceof FakeDefaultLiteral) { - scope.problemReporter().validateJavaFeatureSupport(JavaFeature.PATTERN_MATCHING_IN_SWITCH, - e.sourceStart, e.sourceEnd); - continue; - } - if (ret == null) ret = e; - } - } - return ret; -} -/** - * Returns the constant intValue or ordinal for enum constants. If constant is NotAConstant, then answers Float.MIN_VALUE - */ -public ResolvedCase[] resolveCase(BlockScope scope, TypeBinding switchExpressionType, SwitchStatement switchStatement) { - // switchExpressionType maybe null in error case - scope.enclosingCase = this; // record entering in a switch case block - if (this.constantExpressions == null) { - flagDuplicateDefault(scope, switchStatement, this); - return ResolvedCase.UnresolvedCase; - } - Expression constExpr = getFirstValidExpression(scope, switchStatement); - if (constExpr == null) { - return ResolvedCase.UnresolvedCase; - } - - // add into the collection of cases of the associated switch statement - switchStatement.cases[switchStatement.caseCount++] = this; - if (switchExpressionType != null && switchExpressionType.isEnum() && (constExpr instanceof SingleNameReference)) { - ((SingleNameReference) constExpr).setActualReceiverType((ReferenceBinding)switchExpressionType); - } - - constExpr.setExpressionContext(ExpressionContext.INSTANCEOF_CONTEXT); - constExpr.setExpectedType(switchExpressionType); - - TypeBinding caseType = constExpr.resolveType(scope); - if (caseType == null || switchExpressionType == null) return ResolvedCase.UnresolvedCase; - // tag constant name with enum type for privileged access to its members - - List cases = new ArrayList<>(); - for (Expression e : this.constantExpressions) { - if (e != constExpr) { - if (switchExpressionType.isEnum() && (e instanceof SingleNameReference)) { - ((SingleNameReference) e).setActualReceiverType((ReferenceBinding)switchExpressionType); - } else if (e instanceof FakeDefaultLiteral) { - continue; // already processed - } - caseType = e.resolveType(scope); - } - if (caseType == null) - return ResolvedCase.UnresolvedCase; - // Avoid further resolution and secondary errors - if (caseType.isValidBinding()) { - Constant con = resolveConstantExpression(scope, caseType, switchExpressionType, switchStatement, e, cases); - if (con != Constant.NotAConstant) { - int index = this == switchStatement.nullCase && e instanceof NullLiteral ? - -1 : switchStatement.constantIndex++; - cases.add(new ResolvedCase(con, e, caseType, index, false)); - } - } - } - this.resolveWithBindings(this.bindingsWhenTrue(), scope); - if (cases.size() > 0) { - return cases.toArray(new ResolvedCase[cases.size()]); - } - - return ResolvedCase.UnresolvedCase; -} - -private void flagDuplicateDefault(BlockScope scope, SwitchStatement switchStatement, ASTNode node) { - // remember the default case into the associated switch statement - if (switchStatement.defaultCase != null) - scope.problemReporter().duplicateDefaultCase(node); - - // on error the last default will be the selected one ... - switchStatement.defaultCase = this; - if ((switchStatement.switchBits & SwitchStatement.TotalPattern) != 0) { - scope.problemReporter().illegalTotalPatternWithDefault(this); - } -} -@Override -public LocalVariableBinding[] bindingsWhenTrue() { - LocalVariableBinding [] variables = NO_VARIABLES; - if (this.constantExpressions != null) { - for (Expression e : this.constantExpressions) { - variables = LocalVariableBinding.merge(variables, e.bindingsWhenTrue()); - } - } - return variables; -} -public Constant resolveConstantExpression(BlockScope scope, - TypeBinding caseType, - TypeBinding switchType, - SwitchStatement switchStatement, - Expression expression, - List cases) { - - CompilerOptions options = scope.compilerOptions(); - boolean patternSwitchAllowed = JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(options); - if (patternSwitchAllowed) { - if (expression instanceof Pattern) { - return resolveConstantExpression(scope, caseType, switchType, - switchStatement,(Pattern) expression); - } else if (expression instanceof NullLiteral) { - if (!(switchType instanceof ReferenceBinding)) { - scope.problemReporter().typeMismatchError(TypeBinding.NULL, switchType, expression, null); - } - switchStatement.switchBits |= SwitchStatement.NullCase; - return IntConstant.fromValue(-1); - } else if (expression instanceof FakeDefaultLiteral) { - // do nothing - } else { - if (switchStatement.isNonTraditional) { - if (switchType.isBaseType() && !expression.isConstantValueOfTypeAssignableToType(caseType, switchType)) { - scope.problemReporter().typeMismatchError(caseType, switchType, expression, null); - return Constant.NotAConstant; - } - } - } - } - boolean boxing = !patternSwitchAllowed || - switchStatement.isAllowedType(switchType); - - if (expression.isConstantValueOfTypeAssignableToType(caseType, switchType) - ||(caseType.isCompatibleWith(switchType) - && !(expression instanceof StringLiteral))) { - if (caseType.isEnum()) { - if (((expression.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) { - scope.problemReporter().enumConstantsCannotBeSurroundedByParenthesis(expression); - } - - if (expression instanceof NameReference - && (expression.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) { - NameReference reference = (NameReference) expression; - FieldBinding field = reference.fieldBinding(); - if ((field.modifiers & ClassFileConstants.AccEnum) == 0) { - scope.problemReporter().enumSwitchCannotTargetField(reference, field); - } else if (reference instanceof QualifiedNameReference) { - if (options.complianceLevel < ClassFileConstants.JDK21) { - scope.problemReporter().cannotUseQualifiedEnumConstantInCaseLabel(reference, field); - } else if (!TypeBinding.equalsEquals(caseType, switchType)) { - switchStatement.switchBits |= SwitchStatement.QualifiedEnum; - StringConstant constant = (StringConstant) StringConstant.fromValue(new String(field.name)); - cases.add(new ResolvedCase(constant, expression, caseType, -1, true)); - return Constant.NotAConstant; - } - } - return IntConstant.fromValue(field.original().id + 1); // (ordinal value + 1) zero should not be returned see bug 141810 - } - } else { - return expression.constant; - } - } else if (boxing && isBoxingCompatible(caseType, switchType, expression, scope)) { - // constantExpression.computeConversion(scope, caseType, switchExpressionType); - do not report boxing/unboxing conversion - return expression.constant; - } - scope.problemReporter().typeMismatchError(expression.resolvedType, switchType, expression, switchStatement.expression); - return Constant.NotAConstant; -} - -private Constant resolveConstantExpression(BlockScope scope, - TypeBinding caseType, - TypeBinding switchExpressionType, - SwitchStatement switchStatement, - Pattern e) { - Constant constant = Constant.NotAConstant; - TypeBinding type = e.resolveType(scope); - if (type != null) { - constant = IntConstant.fromValue(switchStatement.constantIndex); - switchStatement.caseLabelElements.add(e); - if (e.resolvedType != null) { - // 14.30.2 at compile-time we "resolve" the pattern with respect to the (compile-time) type - // of the expression being pattern matched - e.setExpressionContext(ExpressionContext.INSTANCEOF_CONTEXT); - e.setExpectedType(switchStatement.expression.resolvedType); - TypeBinding pb = e.resolveType(scope); - if (pb != null) switchStatement.caseLabelElementTypes.add(pb); - TypeBinding expressionType = switchStatement.expression.resolvedType; - // The following code is copied from InstanceOfExpression#resolve() - // But there are enough differences to warrant a copy - if (!pb.isReifiable()) { - if (expressionType != TypeBinding.NULL && !(e instanceof RecordPattern)) { - boolean isLegal = e.checkCastTypesCompatibility(scope, pb, expressionType, e, false); - if (!isLegal || (e.bits & ASTNode.UnsafeCast) != 0) { - scope.problemReporter().unsafeCastInInstanceof(e, pb, expressionType); - } - } - } else if (pb.isValidBinding()) { - // if not a valid binding, an error has already been reported for unresolved type - if (pb.isPrimitiveType()) { - scope.problemReporter().unexpectedTypeinSwitchPattern(pb, e); - return Constant.NotAConstant; - } - if (pb.isBaseType() - || !e.checkCastTypesCompatibility(scope, pb, expressionType, null, false)) { - scope.problemReporter().typeMismatchError(expressionType, pb, e, null); - return Constant.NotAConstant; - } - } - if (e.coversType(expressionType)) { - if ((switchStatement.switchBits & SwitchStatement.TotalPattern) != 0) { - scope.problemReporter().duplicateTotalPattern(e); - return IntConstant.fromValue(-1); - } - switchStatement.switchBits |= SwitchStatement.Exhaustive; - if (e.isAlwaysTrue()) { - switchStatement.switchBits |= SwitchStatement.TotalPattern; - if (switchStatement.defaultCase != null && !(e instanceof RecordPattern)) - scope.problemReporter().illegalTotalPatternWithDefault(this); - switchStatement.totalPattern = e; - } - e.isTotalTypeNode = true; - if (switchStatement.nullCase == null) - constant = IntConstant.fromValue(-1); - } - } - - } - return constant; -} - -/* package */ void patternCaseRemovePatternLocals(CodeStream codeStream) { - for (Expression e : this.constantExpressions) { - if (e instanceof Pattern) { - e.traverse(new ASTVisitor() { - @Override - public boolean visit(TypePattern typePattern, BlockScope scope) { - LocalDeclaration local = typePattern.getPatternVariable(); - if (local != null && local.binding != null) - codeStream.removeVariable(local.binding); - return false; // No deeper than this on this node - } - }, (BlockScope) null); - } - } -} -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) { - if (this.constantExpressions != null) { - for (Expression e : this.constantExpressions) { - e.traverse(visitor, blockScope); - } - } - - } - visitor.endVisit(this, blockScope); -} -/** - * @noreference This method is not intended to be referenced by clients. - * To be used in SelectionParser/AssistParser only if containsPatternVariable is positive - * @return local declaration in the type pattern if any else null - */ -public LocalDeclaration getLocalDeclaration() { - Expression cexp = this.constantExpressions[this.patternIndex]; - LocalDeclaration patternVariableIntroduced = cexp.getPatternVariable(); - return patternVariableIntroduced; -} - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CastExpression.java deleted file mode 100644 index d425e13..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CastExpression.java +++ /dev/null @@ -1,751 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752) - * Stephan Herrmann - Contributions for - * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation. - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 401017 - [compiler][null] casted reference to @Nullable field lacks a warning - * bug 400761 - [compiler][null] null may be return as boolean without a diagnostic - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 430150 - [1.8][null] stricter checking against type variables - * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations - * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 415541 - [1.8][compiler] Type annotations in the body of static initializer get dropped - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.CASTING_CONTEXT; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -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.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.IrritantSet; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolymorphicMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; - -public class CastExpression extends Expression { - - public Expression expression; - public TypeReference type; - public TypeBinding expectedType; // when assignment conversion to a given expected type: String s = (String) t; - public TypeBinding instanceofType; // set by InstanceofExpression to ensure we don't flag a necessary cast unnecessary - public boolean isVarTypeDeclaration; // set by LocalDeclaration to indicate we are initializing a var type declaration - -//expression.implicitConversion holds the cast for baseType casting -public CastExpression(Expression expression, TypeReference type) { - this.expression = expression; - this.type = type; - type.bits |= ASTNode.IgnoreRawTypeCheck; // no need to worry about raw type usage -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - FlowInfo result = this.expression - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - this.expression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - // account for pot. CCE: - flowContext.recordAbruptExit(); - return result; -} - -/** - * Complain if assigned expression is cast, but not actually used as such, e.g. Object o = (List) object; - */ -public static void checkNeedForAssignedCast(BlockScope scope, TypeBinding expectedType, CastExpression rhs) { - CompilerOptions compilerOptions = scope.compilerOptions(); - if (compilerOptions.getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; - - TypeBinding castedExpressionType = rhs.expression.resolvedType; - // int i = (byte) n; // cast still had side effect - // double d = (float) n; // cast to float is unnecessary - if (castedExpressionType == null || rhs.resolvedType.isBaseType()) return; - //if (castedExpressionType.id == T_null) return; // tolerate null expression cast - if (castedExpressionType.isCompatibleWith(expectedType, scope)) { - if (scope.environment().usesNullTypeAnnotations()) { - // are null annotations compatible, too? - if (NullAnnotationMatching.analyse(expectedType, castedExpressionType, -1).isAnyMismatch()) - return; // already reported unchecked cast (nullness), say no more. - } - scope.problemReporter().unnecessaryCast(rhs); - } -} - - -/** - * Complain if cast expression is cast, but not actually needed, int i = (int)(Integer) 12; - * Note that this (int) cast is however needed: Integer i = 0; char c = (char)((int) i); - */ -public static void checkNeedForCastCast(BlockScope scope, CastExpression enclosingCast) { - if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; - - CastExpression nestedCast = (CastExpression) enclosingCast.expression; - if ((nestedCast.bits & ASTNode.UnnecessaryCast) == 0) return; - if (nestedCast.losesPrecision(scope)) return; - // check if could cast directly to enclosing cast type, without intermediate type cast - CastExpression alternateCast = new CastExpression(null, enclosingCast.type); - alternateCast.resolvedType = enclosingCast.resolvedType; - if (!alternateCast.checkCastTypesCompatibility(scope, enclosingCast.resolvedType, nestedCast.expression.resolvedType, null /* no expr to avoid side-effects*/, true)) return; - scope.problemReporter().unnecessaryCast(nestedCast); -} - -private boolean losesPrecision(Scope scope) { - // implements the following from JLS §5.1.2: - // "A widening primitive conversion from int to float, or from long to float, or from long to double, may result in loss of precision [...]" - // (extended to boxed types) - TypeBinding exprType = this.expression.resolvedType; - if (exprType.isBoxedPrimitiveType()) - exprType = scope.environment().computeBoxingType(exprType); - switch (this.resolvedType.id) { - case TypeIds.T_JavaLangFloat: - case TypeIds.T_float: // (float)myInt , (float)myLong need rounding - return exprType.id == TypeIds.T_int || exprType.id == TypeIds.T_long; - case TypeIds.T_JavaLangDouble: - case TypeIds.T_double: // (double)myLong needs rounding - return exprType.id == TypeIds.T_long; - } - return false; -} - -/** - * Casting an enclosing instance will considered as useful if removing it would actually bind to a different type - */ -public static void checkNeedForEnclosingInstanceCast(BlockScope scope, Expression enclosingInstance, TypeBinding enclosingInstanceType, TypeBinding memberType) { - if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; - - TypeBinding castedExpressionType = ((CastExpression)enclosingInstance).expression.resolvedType; - if (castedExpressionType == null) return; // cannot do better - // obvious identity cast - if (TypeBinding.equalsEquals(castedExpressionType, enclosingInstanceType)) { - scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance); - } else if (castedExpressionType == TypeBinding.NULL){ - return; // tolerate null enclosing instance cast - } else { - TypeBinding alternateEnclosingInstanceType = castedExpressionType; - if (castedExpressionType.isBaseType() || castedExpressionType.isArrayType()) return; // error case - if (TypeBinding.equalsEquals(memberType, scope.getMemberType(memberType.sourceName(), (ReferenceBinding) alternateEnclosingInstanceType))) { - scope.problemReporter().unnecessaryCast((CastExpression)enclosingInstance); - } - } -} - -/** - * Only complain for identity cast, since other type of casts may be useful: e.g. {@code ~((~(long) 0) << 32)} is different from: {@code ~((~0) << 32)} - */ -public static void checkNeedForArgumentCast(BlockScope scope, int operator, int operatorSignature, Expression expression, int expressionTypeId) { - if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; - - // check need for left operand cast - if ((expression.bits & ASTNode.UnnecessaryCast) == 0 && expression.resolvedType.isBaseType()) { - // narrowing conversion on base type may change value, thus necessary - return; - } else { - TypeBinding alternateLeftType = ((CastExpression)expression).expression.resolvedType; - if (alternateLeftType == null) return; // cannot do better - if (alternateLeftType.id == expressionTypeId) { // obvious identity cast - scope.problemReporter().unnecessaryCast((CastExpression)expression); - return; - } - } -} - -/** - * Cast expressions will considered as useful if removing them all would actually bind to a different method - * (no fine grain analysis on per casted argument basis, simply separate widening cast from narrowing ones) - */ -public static void checkNeedForArgumentCasts(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] argumentTypes, final InvocationSite invocationSite) { - if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; - - int length = argumentTypes.length; - - // iterate over arguments, and retrieve original argument types (before cast) - TypeBinding[] rawArgumentTypes = argumentTypes; - for (int i = 0; i < length; i++) { - Expression argument = arguments[i]; - if (argument instanceof CastExpression) { - // narrowing conversion on base type may change value, thus necessary - if ((argument.bits & ASTNode.UnnecessaryCast) == 0 && argument.resolvedType.isBaseType()) { - continue; - } - TypeBinding castedExpressionType = ((CastExpression)argument).expression.resolvedType; - if (castedExpressionType == null) return; // cannot do better - // obvious identity cast - if (TypeBinding.equalsEquals(castedExpressionType, argumentTypes[i])) { - scope.problemReporter().unnecessaryCast((CastExpression)argument); - } else if (castedExpressionType == TypeBinding.NULL){ - continue; // tolerate null argument cast - } else if ((argument.implicitConversion & TypeIds.BOXING) != 0) { - continue; // boxing has a side effect: (int) char is not boxed as simple char - } else { - if (rawArgumentTypes == argumentTypes) { - System.arraycopy(rawArgumentTypes, 0, rawArgumentTypes = new TypeBinding[length], 0, length); - } - // retain original argument type - rawArgumentTypes[i] = castedExpressionType; - } - } - } - // perform alternate lookup with original types - if (rawArgumentTypes != argumentTypes) { - checkAlternateBinding(scope, receiver, receiverType, binding, arguments, argumentTypes, rawArgumentTypes, invocationSite); - } -} - -/** - * Check binary operator casted arguments - */ -public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int operatorSignature, Expression left, int leftTypeId, boolean leftIsCast, Expression right, int rightTypeId, boolean rightIsCast) { - if (scope.compilerOptions().getSeverity(CompilerOptions.UnnecessaryTypeCheck) == ProblemSeverities.Ignore) return; - - boolean useAutoBoxing = operator != OperatorIds.EQUAL_EQUAL && operator != OperatorIds.NOT_EQUAL; - // check need for left operand cast - int alternateLeftTypeId = leftTypeId; - if (leftIsCast) { - if ((left.bits & ASTNode.UnnecessaryCast) == 0 && left.resolvedType.isBaseType()) { - // narrowing conversion on base type may change value, thus necessary - leftIsCast = false; - } else { - TypeBinding alternateLeftType = ((CastExpression)left).expression.resolvedType; - if (alternateLeftType == null) return; // cannot do better - if ((alternateLeftTypeId = alternateLeftType.id) == leftTypeId - || (useAutoBoxing - ? scope.environment().computeBoxingType(alternateLeftType).id == leftTypeId - : TypeBinding.equalsEquals(alternateLeftType, left.resolvedType))) { // obvious identity cast - scope.problemReporter().unnecessaryCast((CastExpression)left); - leftIsCast = false; - } else if (alternateLeftTypeId == TypeIds.T_null) { - alternateLeftTypeId = leftTypeId; // tolerate null argument cast - leftIsCast = false; - } - } - } - // check need for right operand cast - int alternateRightTypeId = rightTypeId; - if (rightIsCast) { - if ((right.bits & ASTNode.UnnecessaryCast) == 0 && right.resolvedType.isBaseType()) { - // narrowing conversion on base type may change value, thus necessary - rightIsCast = false; - } else { - TypeBinding alternateRightType = ((CastExpression)right).expression.resolvedType; - if (alternateRightType == null) return; // cannot do better - if ((alternateRightTypeId = alternateRightType.id) == rightTypeId - || (useAutoBoxing - ? scope.environment().computeBoxingType(alternateRightType).id == rightTypeId - : TypeBinding.equalsEquals(alternateRightType, right.resolvedType))) { // obvious identity cast - scope.problemReporter().unnecessaryCast((CastExpression)right); - rightIsCast = false; - } else if (alternateRightTypeId == TypeIds.T_null) { - alternateRightTypeId = rightTypeId; // tolerate null argument cast - rightIsCast = false; - } - } - } - if (leftIsCast || rightIsCast) { - if (alternateLeftTypeId > 15 || alternateRightTypeId > 15) { // must convert String + Object || Object + String - if (alternateLeftTypeId == TypeIds.T_JavaLangString) { - alternateRightTypeId = TypeIds.T_JavaLangObject; - } else if (alternateRightTypeId == TypeIds.T_JavaLangString) { - alternateLeftTypeId = TypeIds.T_JavaLangObject; - } else { - return; // invalid operator - } - } - int alternateOperatorSignature = OperatorExpression.OperatorSignatures[operator][(alternateLeftTypeId << 4) + alternateRightTypeId]; - // (cast) left Op (cast) right --> result - // 1111 0000 1111 0000 1111 - // <<16 <<12 <<8 <<4 <<0 - final int CompareMASK = (0xF<<16) + (0xF<<8) + 0xF; // mask hiding compile-time types - if ((operatorSignature & CompareMASK) == (alternateOperatorSignature & CompareMASK)) { // same promotions and result - if (leftIsCast) scope.problemReporter().unnecessaryCast((CastExpression)left); - if (rightIsCast) scope.problemReporter().unnecessaryCast((CastExpression)right); - } - } -} - -@Override -public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - if((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0) { - return true; - } - checkNPEbyUnboxing(scope, flowContext, flowInfo); - return this.expression.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck); -} - -private static void checkAlternateBinding(BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding binding, Expression[] arguments, TypeBinding[] originalArgumentTypes, TypeBinding[] alternateArgumentTypes, final InvocationSite invocationSite) { - InvocationSite fakeInvocationSite = new InvocationSite(){ - @Override - public TypeBinding[] genericTypeArguments() { return null; } - @Override - public boolean isSuperAccess(){ return invocationSite.isSuperAccess(); } - @Override - public boolean isTypeAccess() { return invocationSite.isTypeAccess(); } - @Override - public void setActualReceiverType(ReferenceBinding actualReceiverType) { /* ignore */} - @Override - public void setDepth(int depth) { /* ignore */} - @Override - public void setFieldIndex(int depth){ /* ignore */} - @Override - public int sourceStart() { return 0; } - @Override - public int sourceEnd() { return 0; } - @Override - public TypeBinding invocationTargetType() { return invocationSite.invocationTargetType(); } - @Override - public boolean receiverIsImplicitThis() { return invocationSite.receiverIsImplicitThis();} - @Override - public InferenceContext18 freshInferenceContext(Scope someScope) { return invocationSite.freshInferenceContext(someScope); } - @Override - public ExpressionContext getExpressionContext() { return invocationSite.getExpressionContext(); } - @Override - public boolean isQualifiedSuper() { return invocationSite.isQualifiedSuper(); } - @Override - public boolean checkingPotentialCompatibility() { return false; } - @Override - public void acceptPotentiallyCompatibleMethods(MethodBinding[] methods) {/* ignore */} - }; - MethodBinding bindingIfNoCast; - if (binding.isConstructor()) { - bindingIfNoCast = scope.getConstructor((ReferenceBinding)receiverType, alternateArgumentTypes, fakeInvocationSite); - } else { - bindingIfNoCast = receiver.isImplicitThis() - ? scope.getImplicitMethod(binding.selector, alternateArgumentTypes, fakeInvocationSite) - : scope.getMethod(receiverType, binding.selector, alternateArgumentTypes, fakeInvocationSite); - } - if (bindingIfNoCast == binding) { - int argumentLength = originalArgumentTypes.length; - if (binding.isVarargs()) { - int paramLength = binding.parameters.length; - if (paramLength == argumentLength) { - int varargsIndex = paramLength - 1; - ArrayBinding varargsType = (ArrayBinding) binding.parameters[varargsIndex]; - TypeBinding lastArgType = alternateArgumentTypes[varargsIndex]; - // originalType may be compatible already, but cast mandated - // to clarify between varargs/non-varargs call - if (varargsType.dimensions != lastArgType.dimensions()) { - return; - } - if (lastArgType.isCompatibleWith(varargsType.elementsType()) - && lastArgType.isCompatibleWith(varargsType)) { - return; - } - } - } - for (int i = 0; i < argumentLength; i++) { - if (TypeBinding.notEquals(originalArgumentTypes[i], alternateArgumentTypes[i]) - /*&& !originalArgumentTypes[i].needsUncheckedConversion(alternateArgumentTypes[i])*/) { - if (!preventsUnlikelyTypeWarning(originalArgumentTypes[i], alternateArgumentTypes[i], receiverType, binding, scope)) - scope.problemReporter().unnecessaryCast((CastExpression)arguments[i]); - } - } - } -} - -private static boolean preventsUnlikelyTypeWarning(TypeBinding castedType, TypeBinding uncastedType, TypeBinding receiverType, MethodBinding binding, BlockScope scope) { - if (!scope.compilerOptions().isAnyEnabled(IrritantSet.UNLIKELY_ARGUMENT_TYPE)) - return false; - if (binding.isStatic() || binding.parameters.length != 1) - return false; - // would using the uncastedType be considered as dangerous? - UnlikelyArgumentCheck argumentChecks = UnlikelyArgumentCheck.determineCheckForNonStaticSingleArgumentMethod( - uncastedType, scope, binding.selector, receiverType, binding.parameters); - if (argumentChecks != null && argumentChecks.isDangerous(scope)) { - // does the cast help? - argumentChecks = UnlikelyArgumentCheck.determineCheckForNonStaticSingleArgumentMethod( - castedType, scope, binding.selector, receiverType, binding.parameters); - if (argumentChecks == null || !argumentChecks.isDangerous(scope)) - return true; - } - return false; -} - -@Override -public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { - return CastExpression.checkUnsafeCast(this, scope, castType, expressionType, match, isNarrowing); -} -public static boolean checkUnsafeCast(Expression expression, Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { - // In case of expression being a InstanceOfExpression, this.resolvedType is null - // hence use the type of RHS of the instanceof operator - TypeBinding resolvedType = expression.resolvedType != null ? expression.resolvedType : castType; - if (TypeBinding.equalsEquals(match, castType)) { - if (!isNarrowing && TypeBinding.equalsEquals(match, resolvedType.leafComponentType()) // do not tag as unnecessary when recursing through upper bounds - && !(expressionType.isParameterizedType() && expressionType.isProvablyDistinct(castType))) { - expression.tagAsUnnecessaryCast(scope, castType); - } - return true; - } - if (match != null) { - if (isNarrowing - ? match.isProvablyDistinct(expressionType) - : castType.isProvablyDistinct(match)) { - return false; - } - } - switch (castType.kind()) { - case Binding.PARAMETERIZED_TYPE : - if (!castType.isReifiable()) { - - // [JLS 5.1.6.2] T <: S - // [JLS 5.1.5] S <: T - if (match == null) { // unrelated types - expression.bits |= ASTNode.UnsafeCast; - return true; - } - switch (match.kind()) { - case Binding.PARAMETERIZED_TYPE : - if (isNarrowing) { - // [JLS 5.1.6.2] T <: S - - // [JLS 5.1.6.2] S has no subtype X other than T where the type arguments of X are not contained in the type arguments of T - // S will have all the type arguments that were specified in S - // If T2 extends T1 then a cast from T1> to T2> is checked while a cast from T1> to T2> is unchecked - if (expressionType.isRawType() || !expressionType.isEquivalentTo(match)) { - expression.bits |= ASTNode.UnsafeCast; - return true; - } - - // T will have all the type arguments that were introduced in subtypes of S so the type arguments of T need to be unbound wildcards since the type arguments couldn't have been specified by S - // If T2 extends T1 then a cast from T1> to T2, ? extends List> is unchecked - ParameterizedTypeBinding paramCastType = (ParameterizedTypeBinding) castType; - TypeBinding[] castArguments = paramCastType.arguments; - int length = castArguments == null ? 0 : castArguments.length; - if ((paramCastType.tagBits & (TagBits.HasDirectWildcard|TagBits.HasTypeVariable)) != 0) { - // verify alternate cast type, substituting different type arguments - for (int i = 0; i < length; i++) { - if (castArguments[i].isUnboundWildcard()) - continue; - TypeBinding[] alternateArguments; - // need to clone for each iteration to avoid env paramtype cache interference - System.arraycopy(paramCastType.arguments, 0, alternateArguments = new TypeBinding[length], 0, length); - alternateArguments[i] = TypeBinding.equalsEquals(paramCastType.arguments[i], scope.getJavaLangObject()) ? scope.getJavaLangBoolean() : scope.getJavaLangObject(); - LookupEnvironment environment = scope.environment(); - ParameterizedTypeBinding alternateCastType = environment.createParameterizedType((ReferenceBinding)castType.erasure(), alternateArguments, castType.enclosingType()); - if (TypeBinding.equalsEquals(alternateCastType.findSuperTypeOriginatingFrom(expressionType), match)) { - expression.bits |= ASTNode.UnsafeCast; - break; - } - } - } - - // Type arguments added by subtypes of S and removed by supertypes of T don't need to be checked since the type arguments aren't specified by either S or T - return true; - } else { - // [JLS 5.1.5] S <: T - if (!match.isEquivalentTo(castType)) { - expression.bits |= ASTNode.UnsafeCast; - return true; - } - } - break; - case Binding.RAW_TYPE : - expression.bits |= ASTNode.UnsafeCast; // upcast since castType is known to be bound paramType - return true; - default : - if (isNarrowing){ - // match is not parameterized or raw, then any other subtype of match will erase to |T| - expression.bits |= ASTNode.UnsafeCast; - return true; - } - break; - } - } - break; - case Binding.ARRAY_TYPE : - TypeBinding leafType = castType.leafComponentType(); - if (isNarrowing && (!leafType.isReifiable() || leafType.isTypeVariable())) { - expression.bits |= ASTNode.UnsafeCast; - return true; - } - break; - case Binding.TYPE_PARAMETER : - expression.bits |= ASTNode.UnsafeCast; - return true; -// (disabled) https://bugs.eclipse.org/bugs/show_bug.cgi?id=240807 -// case Binding.TYPE : -// if (isNarrowing && match == null && expressionType.isParameterizedType()) { -// this.bits |= ASTNode.UnsafeCast; -// return true; -// } -// break; - } - if (!isNarrowing && TypeBinding.equalsEquals(match, resolvedType.leafComponentType())) { // do not tag as unnecessary when recursing through upper bounds - expression.tagAsUnnecessaryCast(scope, castType); - } - return true; -} - -/** - * Cast expression code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - boolean annotatedCast = (this.type.bits & ASTNode.HasTypeAnnotations) != 0; - boolean needRuntimeCheckcast = (this.bits & ASTNode.GenerateCheckcast) != 0; - if (this.constant != Constant.NotAConstant) { - if (valueRequired || needRuntimeCheckcast || annotatedCast) { // Added for: 1F1W9IG: IVJCOM:WINNT - Compiler omits casting check - codeStream.generateConstant(this.constant, this.implicitConversion); - if (needRuntimeCheckcast || annotatedCast) { - codeStream.checkcast(this.type, this.resolvedType, pc); - } - if (!valueRequired) { - // the resolveType cannot be double or long - codeStream.pop(); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - this.expression.generateCode(currentScope, codeStream, annotatedCast || valueRequired || needRuntimeCheckcast); - if (annotatedCast || (needRuntimeCheckcast && TypeBinding.notEquals(this.expression.postConversionType(currentScope), this.resolvedType.erasure()))) { // no need to issue a checkcast if already done as genericCast - codeStream.checkcast(this.type, this.resolvedType, pc); - } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else if (annotatedCast || needRuntimeCheckcast) { - switch (this.resolvedType.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - break; - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -public Expression innermostCastedExpression(){ - Expression current = this.expression; - while (current instanceof CastExpression) { - current = ((CastExpression) current).expression; - } - return current; -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#localVariableBinding() - */ -@Override -public LocalVariableBinding localVariableBinding() { - return this.expression.localVariableBinding(); -} - -@Override -public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - if ((this.implicitConversion & TypeIds.BOXING) != 0) - return FlowInfo.NON_NULL; - return this.expression.nullStatus(flowInfo, flowContext); -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#optimizedBooleanConstant() - */ -@Override -public Constant optimizedBooleanConstant() { - switch(this.resolvedType.id) { - case T_boolean : - case T_JavaLangBoolean : - return this.expression.optimizedBooleanConstant(); - } - return Constant.NotAConstant; -} - -@Override -public StringBuilder printExpression(int indent, StringBuilder output) { - int parenthesesCount = (this.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT; - String suffix = ""; //$NON-NLS-1$ - for(int i = 0; i < parenthesesCount; i++) { - output.append('('); - suffix += ')'; - } - output.append('('); - this.type.print(0, output).append(") "); //$NON-NLS-1$ - return this.expression.printExpression(0, output).append(suffix); -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - // compute a new constant if the cast is effective - - this.constant = Constant.NotAConstant; - this.implicitConversion = TypeIds.T_undefined; - - boolean exprContainCast = false; - - TypeBinding castType = this.resolvedType = this.type.resolveType(scope); - if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8) { - this.expression.setExpressionContext(CASTING_CONTEXT); - if (this.expression instanceof FunctionalExpression) { - this.expression.setExpectedType(this.resolvedType); - this.bits |= ASTNode.DisableUnnecessaryCastCheck; - } - } - if (this.expression instanceof CastExpression) { - this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck; - exprContainCast = true; - } - TypeBinding expressionType = this.expression.resolveType(scope); - if (this.expression instanceof MessageSend) { - MessageSend messageSend = (MessageSend) this.expression; - MethodBinding methodBinding = messageSend.binding; - if (methodBinding != null && methodBinding.isPolymorphic()) { - messageSend.binding = scope.environment().updatePolymorphicMethodReturnType((PolymorphicMethodBinding) methodBinding, castType); - if (TypeBinding.notEquals(expressionType, castType)) { - expressionType = castType; - this.bits |= ASTNode.DisableUnnecessaryCastCheck; - } - } - } - if (castType != null) { - if (expressionType != null) { - - boolean nullAnnotationMismatch = scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled - && NullAnnotationMatching.analyse(castType, expressionType, -1).isAnyMismatch(); - - if (this.instanceofType != null && expressionType.isParameterizedType() - && expressionType.isProvablyDistinct(this.instanceofType)) { - this.bits |= ASTNode.DisableUnnecessaryCastCheck; - } - if (this.isVarTypeDeclaration && TypeBinding.notEquals(expressionType, castType)) { - this.bits |= ASTNode.DisableUnnecessaryCastCheck; - } - boolean isLegal = checkCastTypesCompatibility(scope, castType, expressionType, this.expression, true); - if (isLegal) { - this.expression.computeConversion(scope, castType, expressionType); - if ((this.bits & ASTNode.UnsafeCast) != 0) { // unsafe cast - if (scope.compilerOptions().reportUnavoidableGenericTypeProblems - || !(expressionType.isRawType() && this.expression.forcedToBeRaw(scope.referenceContext()))) { - scope.problemReporter().unsafeCast(this, scope); - } - } else if (nullAnnotationMismatch) { - // report null annotation issue at medium priority - scope.problemReporter().unsafeNullnessCast(this, scope); - } else { - if (castType.isRawType() && scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore){ - scope.problemReporter().rawTypeReference(this.type, castType); - } - if ((this.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == ASTNode.UnnecessaryCast) { // unnecessary cast - if (!isIndirectlyUsed()) // used for generic type inference or boxing ? - scope.problemReporter().unnecessaryCast(this); - } - } - } else { // illegal cast - if ((castType.tagBits & TagBits.HasMissingType) == 0) { // no complaint if secondary error - scope.problemReporter().typeCastError(this, castType, expressionType); - } - this.bits |= ASTNode.DisableUnnecessaryCastCheck; // disable further secondary diagnosis - } - } - this.resolvedType = castType.capture(scope, this.type.sourceStart, this.type.sourceEnd); // make it unique, a cast expression shares source end with the expression. - if (exprContainCast) { - checkNeedForCastCast(scope, this); - } - } - return this.resolvedType; -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#setExpectedType(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) - */ -@Override -public void setExpectedType(TypeBinding expectedType) { - this.expectedType = expectedType; -} - -/** - * Determines whether apparent unnecessary cast wasn't actually used to - * perform return type inference of generic method invocation or boxing. - */ -private boolean isIndirectlyUsed() { - if (this.expression instanceof MessageSend) { - MethodBinding method = ((MessageSend)this.expression).binding; - if (method instanceof ParameterizedGenericMethodBinding - && ((ParameterizedGenericMethodBinding)method).inferredReturnType) { - if (this.expectedType == null) - return true; - if (TypeBinding.notEquals(this.resolvedType, this.expectedType)) - return true; - } - } - if (this.expectedType != null && this.resolvedType.isBaseType() && !this.resolvedType.isCompatibleWith(this.expectedType)) { - // boxing: Short s = (short) _byte - return true; - } - return false; -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsNeedCheckCast() - */ -@Override -public void tagAsNeedCheckCast() { - this.bits |= ASTNode.GenerateCheckcast; -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsUnnecessaryCast(Scope, TypeBinding) - */ -@Override -public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) { - this.bits |= ASTNode.UnnecessaryCast; -} - -public void setInstanceofType(TypeBinding instanceofTypeBinding) { - this.instanceofType = instanceofTypeBinding; -} - -public void setVarTypeDeclaration(boolean value) { - this.isVarTypeDeclaration = value; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) { - this.type.traverse(visitor, blockScope); - this.expression.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java deleted file mode 100644 index 6d1846b..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CharLiteral.java +++ /dev/null @@ -1,115 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; - -public class CharLiteral extends NumberLiteral { - - char value; - -public CharLiteral(char[] token, int s, int e) { - super(token, s, e); - computeValue(); -} - -@Override -public void computeConstant() { - //The source is a char[3] first and last char are ' - //This is true for both regular char AND unicode char - //BUT not for escape char like '\b' which are char[4].... - this.constant = CharConstant.fromValue(this.value); -} - -private void computeValue() { - //The source is a char[3] first and last char are ' - //This is true for both regular char AND unicode char - //BUT not for escape char like '\b' which are char[4].... - if ((this.value = this.source[1]) != '\\') - return; - char digit; - switch (digit = this.source[2]) { - case 's' : - this.value = ' '; - break; - case 'b' : - this.value = '\b'; - break; - case 't' : - this.value = '\t'; - break; - case 'n' : - this.value = '\n'; - break; - case 'f' : - this.value = '\f'; - break; - case 'r' : - this.value = '\r'; - break; - case '\"' : - this.value = '\"'; - break; - case '\'' : - this.value = '\''; - break; - case '\\' : - this.value = '\\'; - break; - default : //octal (well-formed: ended by a ' ) - int number = ScannerHelper.getNumericValue(digit); - if ((digit = this.source[3]) != '\'') - number = (number * 8) + ScannerHelper.getNumericValue(digit); - else { - this.constant = CharConstant.fromValue(this.value = (char) number); - break; - } - if ((digit = this.source[4]) != '\'') - number = (number * 8) + ScannerHelper.getNumericValue(digit); - this.value = (char) number; - break; - } -} - -/** - * CharLiteral code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public TypeBinding literalType(BlockScope scope) { - return TypeBinding.CHAR; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - visitor.visit(this, blockScope); - visitor.endVisit(this, blockScope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java deleted file mode 100644 index a51c5e2..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java +++ /dev/null @@ -1,140 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class ClassLiteralAccess extends Expression { - - public TypeReference type; - public TypeBinding targetType; - FieldBinding syntheticField; - - public ClassLiteralAccess(int sourceEnd, TypeReference type) { - this.type = type; - type.bits |= IgnoreRawTypeCheck; // no need to worry about raw type usage - this.sourceStart = type.sourceStart; - this.sourceEnd = sourceEnd; - } - - @Override - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - // if reachable, request the addition of a synthetic field for caching the class descriptor - SourceTypeBinding sourceType = currentScope.outerMostClassScope().enclosingSourceType(); - // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=22334 - if (!sourceType.isInterface() - && !this.targetType.isBaseType() - && currentScope.compilerOptions().targetJDK < ClassFileConstants.JDK1_5) { - this.syntheticField = sourceType.addSyntheticFieldForClassLiteral(this.targetType, currentScope); - } - return flowInfo; - } - - /** - * MessageSendDotClass code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ - @Override - public void generateCode( - BlockScope currentScope, - CodeStream codeStream, - boolean valueRequired) { - int pc = codeStream.position; - - // in interface case, no caching occurs, since cannot make a cache field for interface - if (valueRequired) { - codeStream.generateClassLiteralAccessForType(currentScope, this.type.resolvedType, this.syntheticField); - codeStream.generateImplicitConversion(this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - - return this.type.print(0, output).append(".class"); //$NON-NLS-1$ - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - - this.constant = Constant.NotAConstant; - if ((this.targetType = this.type.resolveType(scope, true /* check bounds*/)) == null) - return null; - - /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=320463 - https://bugs.eclipse.org/bugs/show_bug.cgi?id=312076 - JLS3 15.8.2 forbids the type named in the class literal expression from being a parameterized type. - And the grammar in 18.1 disallows (where X and Y are some concrete types) constructs of the form - Outer.class, Outer.Inner.class, Outer.Inner.class, Outer.Inner.class etc. - Corollary wise, we should resolve the type of the class literal expression to be a raw type as - class literals exist only for the raw underlying type. - */ - LookupEnvironment environment = scope.environment(); - this.targetType = environment.convertToRawType(this.targetType, true /* force conversion of enclosing types*/); - - if (this.targetType.isArrayType()) { - ArrayBinding arrayBinding = (ArrayBinding) this.targetType; - TypeBinding leafComponentType = arrayBinding.leafComponentType; - if (leafComponentType == TypeBinding.VOID) { - scope.problemReporter().cannotAllocateVoidArray(this); - return null; - } else if (leafComponentType.isTypeVariable()) { - scope.problemReporter().illegalClassLiteralForTypeVariable((TypeVariableBinding)leafComponentType, this); - } - } else if (this.targetType.isTypeVariable()) { - scope.problemReporter().illegalClassLiteralForTypeVariable((TypeVariableBinding)this.targetType, this); - } - ReferenceBinding classType = scope.getJavaLangClass(); - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328689 - if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { - // Integer.class --> Class, perform boxing of base types (int.class --> Class) - TypeBinding boxedType = null; - if (this.targetType.id == T_void) { - boxedType = environment.getResolvedJavaBaseType(JAVA_LANG_VOID, scope); - } else { - boxedType = scope.boxing(this.targetType); - } - if (environment.usesNullTypeAnnotations()) - boxedType = environment.createNonNullAnnotatedType(boxedType); - this.resolvedType = environment.createParameterizedType(classType, new TypeBinding[]{ boxedType }, null/*not a member*/); - } else { - this.resolvedType = classType; - } - return this.resolvedType; - } - - @Override - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.type.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Clinit.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Clinit.java deleted file mode 100644 index ff59204..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Clinit.java +++ /dev/null @@ -1,426 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Patrick Wienands - Contribution for bug 393749 - * Stephan Herrmann - Contribution for - * bug 331649 - [compiler][null] consider null annotations for fields - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ClassFile; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; -import org.eclipse.jdt.internal.compiler.codegen.Opcodes; -import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext; -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.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.parser.Parser; -import org.eclipse.jdt.internal.compiler.problem.AbortMethod; - -public class Clinit extends AbstractMethodDeclaration { - private static int ENUM_CONSTANTS_THRESHOLD = 2000; - - private FieldBinding assertionSyntheticFieldBinding = null; - private FieldBinding classLiteralSyntheticField = null; - - public Clinit(CompilationResult compilationResult) { - super(compilationResult); - this.modifiers = 0; - this.selector = TypeConstants.CLINIT; - } - - public void analyseCode( - ClassScope classScope, - InitializationFlowContext staticInitializerFlowContext, - FlowInfo flowInfo) { - - if (this.ignoreFurtherInvestigation) - return; - try { - ExceptionHandlingFlowContext clinitContext = - new ExceptionHandlingFlowContext( - staticInitializerFlowContext.parent, - this, - Binding.NO_EXCEPTIONS, - staticInitializerFlowContext, - this.scope, - FlowInfo.DEAD_END); - - // check for missing returning path - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - this.bits |= ASTNode.NeedFreeReturn; - } - - // check missing blank final field initializations - flowInfo = flowInfo.mergedWith(staticInitializerFlowContext.initsOnReturn); - FieldBinding[] fields = this.scope.enclosingSourceType().fields(); - for (int i = 0, count = fields.length; i < count; i++) { - FieldBinding field = fields[i]; - if (field.isStatic()) { - if (!flowInfo.isDefinitelyAssigned(field)) { - if (field.isFinal()) { - this.scope.problemReporter().uninitializedBlankFinalField( - field, - this.scope.referenceType().declarationOf(field.original())); - // can complain against the field decl, since only one - } else if (field.isNonNull()) { - this.scope.problemReporter().uninitializedNonNullField( - field, - this.scope.referenceType().declarationOf(field.original())); - } - } - } - } - // check static initializers thrown exceptions - staticInitializerFlowContext.checkInitializerExceptions( - this.scope, - clinitContext, - flowInfo); - } catch (AbortMethod e) { - this.ignoreFurtherInvestigation = true; - } - } - - /** - * Bytecode generation for a {@code } method - * - * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope - * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile - */ - @Override - public void generateCode(ClassScope classScope, ClassFile classFile) { - - int clinitOffset = 0; - if (this.ignoreFurtherInvestigation) { - // should never have to add any problem method - return; - } - CompilationResult unitResult = null; - int problemCount = 0; - if (classScope != null) { - TypeDeclaration referenceContext = classScope.referenceContext; - if (referenceContext != null) { - unitResult = referenceContext.compilationResult(); - problemCount = unitResult.problemCount; - } - } - boolean restart = false; - do { - try { - clinitOffset = classFile.contentsOffset; - this.generateCode(classScope, classFile, clinitOffset); - restart = false; - } catch (AbortMethod e) { - // should never occur - // the clinit referenceContext is the type declaration - // All clinit problems will be reported against the type: AbortType instead of AbortMethod - // reset the contentsOffset to the value before generating the clinit code - // decrement the number of method info as well. - // This is done in the addProblemMethod and addProblemConstructor for other - // cases. - if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { - // a branch target required a goto_w, restart code gen in wide mode. - classFile.contentsOffset = clinitOffset; - classFile.methodCount--; - classFile.codeStream.resetInWideMode(); // request wide mode - // reset the problem count to prevent reporting the same warning twice - if (unitResult != null) { - unitResult.problemCount = problemCount; - } - // restart method generation - restart = true; - } else if (e.compilationResult == CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE) { - classFile.contentsOffset = clinitOffset; - classFile.methodCount--; - classFile.codeStream.resetForCodeGenUnusedLocals(); - // reset the problem count to prevent reporting the same warning twice - if (unitResult != null) { - unitResult.problemCount = problemCount; - } - // restart method generation - restart = true; - } else { - // produce a problem method accounting for this fatal error - classFile.contentsOffset = clinitOffset; - classFile.methodCount--; - restart = false; - } - } - } while (restart); - } - - /** - * Bytecode generation for a method - * - * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope - * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile - */ - private void generateCode( - ClassScope classScope, - ClassFile classFile, - int clinitOffset) { - - ConstantPool constantPool = classFile.constantPool; - int constantPoolOffset = constantPool.currentOffset; - int constantPoolIndex = constantPool.currentIndex; - classFile.generateMethodInfoHeaderForClinit(); - int codeAttributeOffset = classFile.contentsOffset; - classFile.generateCodeAttributeHeader(); - CodeStream codeStream = classFile.codeStream; - resolve(classScope); - - codeStream.reset(this, classFile); - TypeDeclaration declaringType = classScope.referenceContext; - codeStream.pushPatternAccessTrapScope(this.scope); - - // initialize local positions - including initializer scope. - MethodScope staticInitializerScope = declaringType.staticInitializerScope; - staticInitializerScope.computeLocalVariablePositions(0, codeStream); - - // 1.4 feature - // This has to be done before any other initialization - if (this.assertionSyntheticFieldBinding != null) { - // generate code related to the activation of assertion for this class - codeStream.generateClassLiteralAccessForType( - classScope, - classScope.outerMostClassScope().enclosingSourceType(), - this.classLiteralSyntheticField); - codeStream.invokeJavaLangClassDesiredAssertionStatus(); - BranchLabel falseLabel = new BranchLabel(codeStream); - codeStream.ifne(falseLabel); - codeStream.iconst_1(); - BranchLabel jumpLabel = new BranchLabel(codeStream); - codeStream.decrStackSize(1); - codeStream.goto_(jumpLabel); - falseLabel.place(); - codeStream.iconst_0(); - jumpLabel.place(); - codeStream.fieldAccess(Opcodes.OPC_putstatic, this.assertionSyntheticFieldBinding, null /* default declaringClass */); - } - boolean isJava9 = classScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK9; - // generate static fields/initializers/enum constants - final FieldDeclaration[] fieldDeclarations = declaringType.fields; - int sourcePosition = -1; - int remainingFieldCount = 0; - if (TypeDeclaration.kind(declaringType.modifiers) == TypeDeclaration.ENUM_DECL) { - int enumCount = declaringType.enumConstantsCounter; - if (!isJava9 && enumCount > ENUM_CONSTANTS_THRESHOLD) { - // generate synthetic methods to initialize all the enum constants - int begin = -1; - int count = 0; - if (fieldDeclarations != null) { - int max = fieldDeclarations.length; - for (int i = 0; i < max; i++) { - FieldDeclaration fieldDecl = fieldDeclarations[i]; - if (fieldDecl.isStatic()) { - if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { - if (begin == -1) { - begin = i; - } - count++; - if (count > ENUM_CONSTANTS_THRESHOLD) { - SyntheticMethodBinding syntheticMethod = declaringType.binding.addSyntheticMethodForEnumInitialization(begin, i); - codeStream.invoke(Opcodes.OPC_invokestatic, syntheticMethod, null /* default declaringClass */); - begin = i; - count = 1; - } - } else { - remainingFieldCount++; - } - } - } - if (count != 0) { - // add last synthetic method - SyntheticMethodBinding syntheticMethod = declaringType.binding.addSyntheticMethodForEnumInitialization(begin, max); - codeStream.invoke(Opcodes.OPC_invokestatic, syntheticMethod, null /* default declaringClass */); - } - } - } else if (fieldDeclarations != null) { - for (int i = 0, max = fieldDeclarations.length; i < max; i++) { - FieldDeclaration fieldDecl = fieldDeclarations[i]; - if (fieldDecl.isStatic()) { - if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { - fieldDecl.generateCode(staticInitializerScope, codeStream); - } else { - remainingFieldCount++; - } - } - } - } - // enum need to initialize $VALUES synthetic cache of enum constants - // $VALUES := new [] - codeStream.generateInlinedValue(enumCount); - codeStream.anewarray(declaringType.binding); - if (enumCount > 0) { - if (fieldDeclarations != null) { - for (int i = 0, max = fieldDeclarations.length; i < max; i++) { - FieldDeclaration fieldDecl = fieldDeclarations[i]; - // $VALUES[i] = - if (fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT) { - codeStream.dup(); - codeStream.generateInlinedValue(fieldDecl.binding.id); - codeStream.fieldAccess(Opcodes.OPC_getstatic, fieldDecl.binding, null /* default declaringClass */); - codeStream.aastore(); - } - } - } - } - codeStream.fieldAccess(Opcodes.OPC_putstatic, declaringType.enumValuesSyntheticfield, null /* default declaringClass */); - if (remainingFieldCount != 0) { - // if fields that are not enum constants need to be generated (static initializer/static field) - for (int i = 0, max = fieldDeclarations.length; i < max && remainingFieldCount >= 0; i++) { - FieldDeclaration fieldDecl = fieldDeclarations[i]; - switch (fieldDecl.getKind()) { - case AbstractVariableDeclaration.ENUM_CONSTANT : - break; - case AbstractVariableDeclaration.INITIALIZER : - if (!fieldDecl.isStatic()) { - break; - } - remainingFieldCount--; - sourcePosition = ((Initializer) fieldDecl).block.sourceEnd; - fieldDecl.generateCode(staticInitializerScope, codeStream); - break; - case AbstractVariableDeclaration.FIELD : - if (!fieldDecl.binding.isStatic()) { - break; - } - remainingFieldCount--; - sourcePosition = fieldDecl.declarationEnd; - fieldDecl.generateCode(staticInitializerScope, codeStream); - break; - } - } - } - } else { - if (fieldDeclarations != null) { - for (int i = 0, max = fieldDeclarations.length; i < max; i++) { - FieldDeclaration fieldDecl = fieldDeclarations[i]; - switch (fieldDecl.getKind()) { - case AbstractVariableDeclaration.INITIALIZER : - if (!fieldDecl.isStatic()) - break; - sourcePosition = ((Initializer) fieldDecl).block.sourceEnd; - fieldDecl.generateCode(staticInitializerScope, codeStream); - break; - case AbstractVariableDeclaration.FIELD : - if (!fieldDecl.binding.isStatic()) - break; - sourcePosition = fieldDecl.declarationEnd; - fieldDecl.generateCode(staticInitializerScope, codeStream); - break; - } - } - } - if (isJava9) { - declaringType.binding.generateSyntheticFinalFieldInitialization(codeStream); - } - } - - if (codeStream.position == 0) { - // do not need to output a Clinit if no bytecodes - // so we reset the offset inside the byte array contents. - classFile.contentsOffset = clinitOffset; - // like we don't addd a method we need to undo the increment on the method count - classFile.methodCount--; - // reset the constant pool to its state before the clinit - constantPool.resetForClinit(constantPoolIndex, constantPoolOffset); - } else { - if ((this.bits & ASTNode.NeedFreeReturn) != 0) { - int before = codeStream.position; - codeStream.return_(); - if (sourcePosition != -1) { - // expand the last initializer variables to include the trailing return - codeStream.recordPositionsFrom(before, sourcePosition); - } - } - // See https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1796#issuecomment-1933458054 - codeStream.handleRecordAccessorExceptions(this.scope); - // Record the end of the clinit: point to the declaration of the class - codeStream.recordPositionsFrom(0, declaringType.sourceStart); - classFile.completeCodeAttributeForClinit(codeAttributeOffset, classScope); - } - } - - @Override - public boolean isClinit() { - - return true; - } - - @Override - public boolean isInitializationMethod() { - - return true; - } - - @Override - public boolean isStatic() { - - return true; - } - - @Override - public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { - //the clinit is filled by hand .... - } - - @Override - public StringBuilder print(int tab, StringBuilder output) { - - printIndent(tab, output).append("()"); //$NON-NLS-1$ - printBody(tab + 1, output); - return output; - } - - @Override - public void resolve(ClassScope classScope) { - - this.scope = new MethodScope(classScope, classScope.referenceContext, true); - } - - @Override - public void traverse( - ASTVisitor visitor, - ClassScope classScope) { - - visitor.visit(this, classScope); - visitor.endVisit(this, classScope); - } - - public void setAssertionSupport(FieldBinding assertionSyntheticFieldBinding, boolean needClassLiteralField) { - - this.assertionSyntheticFieldBinding = assertionSyntheticFieldBinding; - - // we need to add the field right now, because the field infos are generated before the methods - if (needClassLiteralField) { - SourceTypeBinding sourceType = - this.scope.outerMostClassScope().enclosingSourceType(); - // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=22334 - if (!sourceType.isInterface() && !sourceType.isBaseType()) { - this.classLiteralSyntheticField = sourceType.addSyntheticFieldForClassLiteral(sourceType, this.scope); - } - } - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java deleted file mode 100644 index 5431c0e..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CombinedBinaryExpression.java +++ /dev/null @@ -1,461 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.List; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -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.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -/** - * CombinedBinaryExpression is an implementation of BinaryExpression that - * specifically attempts to mitigate the issues raised by expressions which - * have a very deep leftmost branch. It does so by maintaining a table of - * direct references to its subexpressions, and implementing non-recursive - * variants of the most significant recursive algorithms of its ancestors. - * The subexpressions table only holds intermediate binary expressions. Its - * role is to provide the reversed navigation through the left relationship - * of BinaryExpression to Expression. To cope with potentially very deep - * left branches, an instance of CombinedBinaryExpression is created once in - * a while, using variable thresholds held by {@link #arityMax}. - * As a specific case, the topmost node of all binary expressions that are - * deeper than one is a CombinedBinaryExpression, but it has no references - * table.
    - * Notes: - *
      - *
    • CombinedBinaryExpression is not meant to behave in other ways than - * BinaryExpression in any observable respect;
    • - *
    • visitors that implement their own traversal upon binary expressions - * should consider taking advantage of combined binary expressions, or - * else face a risk of StackOverflowError upon deep instances;
    • - *
    • callers that need to change the operator should rebuild the expression - * from scratch, or else amend the references table as needed to cope with - * the resulting, separated expressions.
    • - *
    - */ -public class CombinedBinaryExpression extends BinaryExpression { - - /** - * The number of consecutive binary expressions of this' left branch that - * bear the same operator as this.
    - * Notes: - *
    • the presence of a CombinedBinaryExpression instance resets - * arity, even when its operator is compatible;
    • - *
    • this property is maintained by the parser.
    • - *
    - */ - public int arity; - - /** - * The threshold that will trigger the creation of the next full-fledged - * CombinedBinaryExpression. This field is only maintained for the - * topmost binary expression (it is 0 otherwise). It enables a variable - * policy, which scales better with very large expressions. - */ - public int arityMax; - - /** - * Upper limit for {@link #arityMax}. - */ - public static final int ARITY_MAX_MAX = 160; - - /** - * Default lower limit for {@link #arityMax}. - */ - public static final int ARITY_MAX_MIN = 20; - - /** - * Default value for the first term of the series of {@link #arityMax} - * values. Changing this allows for experimentation. Not meant to be - * changed during a parse operation. - */ - public static int defaultArityMaxStartingValue = ARITY_MAX_MIN; - - /** - * A table of references to the binary expressions of this' left branch. - * Instances of CombinedBinaryExpression are not repeated here. Instead, - * the left subexpression of referencesTable[0] may be a combined binary - * expression, if appropriate. Null when this only cares about tracking - * the expression's arity. - */ - public BinaryExpression referencesTable[]; - -/** - * Make a new CombinedBinaryExpression. If arity is strictly greater than one, - * a references table is built and initialized with the reverse relationship of - * the one defined by {@link BinaryExpression#left}. arity and left must be - * compatible with each other (that is, there must be at least arity - 1 - * consecutive compatible binary expressions into the leftmost branch of left, - * the topmost of which being left's immediate left expression). - * @param left the left branch expression - * @param right the right branch expression - * @param operator the operator for this binary expression - only PLUS for now - * @param arity the number of binary expressions of a compatible operator that - * already exist into the leftmost branch of left (including left); must - * be strictly greater than 0 - */ -public CombinedBinaryExpression(Expression left, Expression right, int operator, int arity) { - super(left, right, operator); - initArity(left, arity); -} -public CombinedBinaryExpression(CombinedBinaryExpression expression) { - super(expression); - initArity(expression.left, expression.arity); -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, - FlowInfo flowInfo) { - // keep implementation in sync with BinaryExpression#analyseCode - if (this.referencesTable == null) { - return super.analyseCode(currentScope, flowContext, flowInfo); - } - try { - BinaryExpression cursor; - cursor = this.referencesTable[0]; - flowInfo = cursor.left.analyseCode(currentScope, flowContext, flowInfo). - unconditionalInits(); - if (cursor.resolvedType.id != TypeIds.T_JavaLangString) { - cursor.left.checkNPE(currentScope, flowContext, flowInfo); - } - for (int i = 0, end = this.arity; i < end; i ++) { - cursor = this.referencesTable[i]; - flowInfo = cursor.right. - analyseCode(currentScope, flowContext, flowInfo). - unconditionalInits(); - if (cursor.resolvedType.id != TypeIds.T_JavaLangString) { - cursor.right.checkNPE(currentScope, flowContext, flowInfo); - } - } - flowInfo = this.right.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - if (this.resolvedType.id != TypeIds.T_JavaLangString) { - this.right.checkNPE(currentScope, flowContext, flowInfo); - } - return flowInfo; - } finally { - // account for exception possibly thrown by arithmetics - flowContext.recordAbruptExit(); - } -} - -@Override -public void generateOptimizedStringConcatenation(BlockScope blockScope, - CodeStream codeStream, int typeID) { - // keep implementation in sync with BinaryExpression and Expression - // #generateOptimizedStringConcatenation - if (this.referencesTable == null) { - super.generateOptimizedStringConcatenation(blockScope, codeStream, - typeID); - } else { - if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == - OperatorIds.PLUS) - && ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) { - if (this.constant != Constant.NotAConstant) { - codeStream.generateConstant(this.constant, this.implicitConversion); - codeStream.invokeStringConcatenationAppendForType( - this.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - } else { - BinaryExpression cursor = this.referencesTable[0]; - - int restart = 0; - // int cursorTypeID; - int pc = codeStream.position; - for (restart = this.arity - 1; restart >= 0; restart--) { - if ((cursor = this.referencesTable[restart]).constant != - Constant.NotAConstant) { - codeStream.generateConstant(cursor.constant, - cursor.implicitConversion); - codeStream.invokeStringConcatenationAppendForType( - cursor.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - break; - } - // never happens for now - may reconsider if we decide to - // cover more than string concatenation - // if (!((((cursor = this.referencesTable[restart]).bits & - // ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == - // OperatorIds.PLUS) & - // ((cursorTypeID = cursor.bits & ASTNode.ReturnTypeIDMASK) == - // TypeIds.T_JavaLangString)) { - // if (cursorTypeID == T_JavaLangString && - // cursor.constant != Constant.NotAConstant && - // cursor.constant.stringValue().length() == 0) { - // break; // optimize str + "" - // } - // cursor.generateCode(blockScope, codeStream, true); - // codeStream.invokeStringConcatenationAppendForType( - // cursorTypeID); - // break; - // } - } - restart++; - if (restart == 0) { // reached the leftmost expression - cursor.left.generateOptimizedStringConcatenation( - blockScope, - codeStream, - cursor.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - } - int pcAux; - for (int i = restart; i < this.arity; i++) { - codeStream.recordPositionsFrom(pc, - (cursor = this.referencesTable[i]).left.sourceStart); - pcAux = codeStream.position; - cursor.right.generateOptimizedStringConcatenation(blockScope, - codeStream, cursor.right.implicitConversion & - TypeIds.COMPILE_TYPE_MASK); - codeStream.recordPositionsFrom(pcAux, cursor.right.sourceStart); - } - codeStream.recordPositionsFrom(pc, this.left.sourceStart); - pc = codeStream.position; - this.right.generateOptimizedStringConcatenation( - blockScope, - codeStream, - this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.recordPositionsFrom(pc, this.right.sourceStart); - } - } else { - super.generateOptimizedStringConcatenation(blockScope, codeStream, - typeID); - } - } -} - -@Override -public void buildStringForConcatation(BlockScope blockScope, CodeStream codeStream, int typeID, StringBuilder recipe, List argTypes) { - if (this.referencesTable == null) { - super.buildStringForConcatation(blockScope, codeStream, typeID, recipe, argTypes); - } else { - // copied from below method generateOptimizedStringConcatenationCreation(BlockScope, CodeStream, int) - if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == - OperatorIds.PLUS) && - ((this.bits & ASTNode.ReturnTypeIDMASK) == - TypeIds.T_JavaLangString) && - this.constant == Constant.NotAConstant) { - BinaryExpression cursor = this.referencesTable[this.arity - 1]; - int restart = 0; - for (restart = this.arity - 1; restart >= 0; restart--) { - if (((((cursor = this.referencesTable[restart]).bits & - ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == - OperatorIds.PLUS) && - ((cursor.bits & ASTNode.ReturnTypeIDMASK) == - TypeIds.T_JavaLangString)) { - if (cursor.constant != Constant.NotAConstant) { - cursor.buildStringForConcatation(blockScope, codeStream, typeID, recipe, argTypes); - break; - } - } else { - cursor.buildStringForConcatation(blockScope, codeStream, cursor.implicitConversion & - TypeIds.COMPILE_TYPE_MASK, recipe, argTypes); - break; - } - } - restart++; - if (restart == 0) { // reached the leftmost expression - cursor.left.buildStringForConcatation(blockScope, codeStream, cursor.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK, recipe, argTypes); - } - for (int i = restart; i < this.arity; i++) { - cursor = this.referencesTable[i]; - cursor.right.buildStringForConcatation(blockScope, codeStream, cursor.right.implicitConversion & - TypeIds.COMPILE_TYPE_MASK, recipe, argTypes); - } - this.right.buildStringForConcatation(blockScope, codeStream, this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK, recipe, argTypes); - } else { - super.buildStringForConcatation(blockScope, codeStream, typeID, recipe, argTypes); - } - } -} -@Override -public void generateOptimizedStringConcatenationCreation(BlockScope blockScope, - CodeStream codeStream, int typeID) { - // keep implementation in sync with BinaryExpression - // #generateOptimizedStringConcatenationCreation - if (this.referencesTable == null) { - super.generateOptimizedStringConcatenationCreation(blockScope, - codeStream, typeID); - } else { - if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == - OperatorIds.PLUS) && - ((this.bits & ASTNode.ReturnTypeIDMASK) == - TypeIds.T_JavaLangString) && - this.constant == Constant.NotAConstant) { - int pc = codeStream.position; - BinaryExpression cursor = this.referencesTable[this.arity - 1]; - // silence warnings - int restart = 0; - for (restart = this.arity - 1; restart >= 0; restart--) { - if (((((cursor = this.referencesTable[restart]).bits & - ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == - OperatorIds.PLUS) && - ((cursor.bits & ASTNode.ReturnTypeIDMASK) == - TypeIds.T_JavaLangString)) { - if (cursor.constant != Constant.NotAConstant) { - codeStream.newStringContatenation(); // new: java.lang.StringBuffer - codeStream.dup(); - codeStream.ldc(cursor.constant.stringValue()); - codeStream.invokeStringConcatenationStringConstructor(); - // invokespecial: java.lang.StringBuffer.(Ljava.lang.String;)V - break; - } - } else { - cursor.generateOptimizedStringConcatenationCreation(blockScope, - codeStream, cursor.implicitConversion & - TypeIds.COMPILE_TYPE_MASK); - break; - } - } - restart++; - if (restart == 0) { // reached the leftmost expression - cursor.left.generateOptimizedStringConcatenationCreation( - blockScope, - codeStream, - cursor.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - } - int pcAux; - for (int i = restart; i < this.arity; i++) { - codeStream.recordPositionsFrom(pc, - (cursor = this.referencesTable[i]).left.sourceStart); - pcAux = codeStream.position; - cursor.right.generateOptimizedStringConcatenation(blockScope, - codeStream, cursor.right.implicitConversion & - TypeIds.COMPILE_TYPE_MASK); - codeStream.recordPositionsFrom(pcAux, cursor.right.sourceStart); - } - codeStream.recordPositionsFrom(pc, this.left.sourceStart); - pc = codeStream.position; - this.right.generateOptimizedStringConcatenation( - blockScope, - codeStream, - this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.recordPositionsFrom(pc, this.right.sourceStart); - } else { - super.generateOptimizedStringConcatenationCreation(blockScope, - codeStream, typeID); - } - } -} -private void initArity(Expression expression, int value) { - this.arity = value; - if (value > 1) { - this.referencesTable = new BinaryExpression[value]; - this.referencesTable[value - 1] = (BinaryExpression) expression; - for (int i = value - 1; i > 0; i--) { - this.referencesTable[i - 1] = - (BinaryExpression) this.referencesTable[i].left; - } - } else { - this.arityMax = defaultArityMaxStartingValue; - } -} - -@Override -public StringBuilder printExpressionNoParenthesis(int indent, - StringBuilder output) { - // keep implementation in sync with - // BinaryExpression#printExpressionNoParenthesis and - // OperatorExpression#printExpression - if (this.referencesTable == null) { - return super.printExpressionNoParenthesis(indent, output); - } - String operatorString = operatorToString(); - for (int i = this.arity - 1; i >= 0; i--) { - output.append('('); - } - output = this.referencesTable[0].left. - printExpression(indent, output); - for (int i = 0, end = this.arity; - i < end; i++) { - output.append(' ').append(operatorString).append(' '); - output = this.referencesTable[i].right. - printExpression(0, output); - output.append(')'); - } - output.append(' ').append(operatorString).append(' '); - return this.right.printExpression(0, output); -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - // keep implementation in sync with BinaryExpression#resolveType - if (this.referencesTable == null) { - return super.resolveType(scope); - } - BinaryExpression cursor; - if ((cursor = this.referencesTable[0]).left instanceof CastExpression) { - cursor.left.bits |= ASTNode.DisableUnnecessaryCastCheck; - // will check later on - } - cursor.left.resolveType(scope); - for (int i = 0, end = this.arity; i < end; i ++) { - this.referencesTable[i].nonRecursiveResolveTypeUpwards(scope); - } - nonRecursiveResolveTypeUpwards(scope); - return this.resolvedType; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (this.referencesTable == null) { - super.traverse(visitor, scope); - } else { - if (visitor.visit(this, scope)) { - int restart; - for (restart = this.arity - 1; - restart >= 0; - restart--) { - if (!visitor.visit( - this.referencesTable[restart], scope)) { - visitor.endVisit( - this.referencesTable[restart], scope); - break; - } - } - restart++; - // restart now points to the deepest BE for which - // visit returned true, if any - if (restart == 0) { - this.referencesTable[0].left.traverse(visitor, scope); - } - for (int i = restart, end = this.arity; - i < end; i++) { - this.referencesTable[i].right.traverse(visitor, scope); - visitor.endVisit(this.referencesTable[i], scope); - } - this.right.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } -} - -/** - * Change {@link #arityMax} if and as needed. The current policy is to double - * arityMax each time this method is called, until it reaches - * {@link #ARITY_MAX_MAX}. Other policies may consider incrementing it less - * agressively. Call only after an appropriate value has been assigned to - * {@link #left}. - */ -// more sophisticate increment policies would leverage the leftmost expression -// to hold an indication of the number of uses of a given arityMax in a row -public void tuneArityMax() { - if (this.arityMax < ARITY_MAX_MAX) { - this.arityMax *= 2; - } -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CompactConstructorDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CompactConstructorDeclaration.java deleted file mode 100644 index 17e7d75..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CompactConstructorDeclaration.java +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019 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 - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jdt.internal.compiler.CompilationResult; -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.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.parser.Parser; - -public class CompactConstructorDeclaration extends ConstructorDeclaration { - - public TypeDeclaration recordDeclaration; - - public CompactConstructorDeclaration(CompilationResult compilationResult) { - super(compilationResult); - } - @Override - public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { - this.constructorCall = SuperReference.implicitSuperConstructorCall(); - parser.parse(this, unit, false); - this.containsSwitchWithTry = parser.switchWithTry; - } - @Override - public void analyseCode(ClassScope classScope, InitializationFlowContext initializerFlowContext, FlowInfo flowInfo, int initialReachMode) { - try { - this.scope.isCompactConstructorScope = true; - super.analyseCode(classScope, initializerFlowContext, flowInfo, initialReachMode); - } finally { - this.scope.isCompactConstructorScope = false; - } - } - @Override - protected void doFieldReachAnalysis(FlowInfo flowInfo, FieldBinding[] fields) { - // do nothing - } - @Override - protected void checkAndGenerateFieldAssignment(FlowContext flowContext, FlowInfo flowInfo, FieldBinding[] fields) { - this.scope.isCompactConstructorScope = false; - if (fields == null) - return; - /* JLS 15 Record addendum Sec 8.10.4 All fields corresponding to the record components of the - * record class are implicitly initialized to the value of the corresponding formal - * parameter after the body of the compact constructor. - * These fields are implicitly initialized in the order that they are declared - * in the record component list. - */ - List fieldAssignments = new ArrayList<>(); - for (FieldBinding field : fields) { - if (field.isStatic()) - continue; - assert field.isFinal(); - - FieldReference lhs = new FieldReference(field.name,0); - lhs.receiver = new ThisReference(0, 0); - //TODO: Check whether anything has to be done for null analysis. - Assignment assignment = new Assignment(lhs, new SingleNameReference(field.name, 0), 0); - assignment.resolveType(this.scope); - assignment.analyseCode(this.scope, flowContext, flowInfo); - assignment.bits |= ASTNode.IsImplicit; - assert flowInfo.isDefinitelyAssigned(field); - fieldAssignments.add(assignment); - } - if (fieldAssignments.isEmpty() || (flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) - return; - - Statement[] fa = fieldAssignments.toArray(new Statement[0]); - if (this.statements == null) { - this.statements = fa; - return; - } - int len = this.statements.length; - int fLen = fa.length; - Statement[] stmts = new Statement[len + fLen]; - System.arraycopy(this.statements, 0, stmts, 0, len); - System.arraycopy(fa, 0, stmts, len, fLen); - this.statements = stmts; - } -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java deleted file mode 100644 index ba617d3..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java +++ /dev/null @@ -1,854 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 295551 - * Jesper S Moller - Contributions for - * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 - * Frits Jalvingh - contributions for bug 533830. - * Red Hat Inc. - add module-info Javadoc support - * Red Hat Inc. - add NLS support for Text Blocks - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.jdt.core.compiler.CategorizedProblem; -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ClassFile; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.ast.LambdaExpression.LocalTypeSubstitutor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.IrritantSet; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; -import org.eclipse.jdt.internal.compiler.lookup.ImportBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.Substitution.NullSubstitution; -import org.eclipse.jdt.internal.compiler.parser.NLSTag; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit; -import org.eclipse.jdt.internal.compiler.problem.AbortMethod; -import org.eclipse.jdt.internal.compiler.problem.AbortType; -import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; -import org.eclipse.jdt.internal.compiler.util.HashSetOfInt; - -@SuppressWarnings({ "rawtypes", "unchecked" }) -public class CompilationUnitDeclaration extends ASTNode implements ProblemSeverities, ReferenceContext { - - private static final Comparator STRING_LITERAL_COMPARATOR = new Comparator() { - @Override - public int compare(Object o1, Object o2) { - StringLiteral literal1 = (StringLiteral) o1; - StringLiteral literal2 = (StringLiteral) o2; - return literal1.sourceStart - literal2.sourceStart; - } - }; - private static final int STRING_LITERALS_INCREMENT = 10; - - public ImportReference currentPackage; - public ImportReference[] imports; - public TypeDeclaration[] types; - public ModuleDeclaration moduleDeclaration; - public int[][] comments; - - public boolean ignoreFurtherInvestigation = false; // once pointless to investigate due to errors - public boolean ignoreMethodBodies = false; - public CompilationUnitScope scope; - public ProblemReporter problemReporter; - public CompilationResult compilationResult; - - public Map localTypes = Collections.emptyMap(); - - public boolean isPropagatingInnerClassEmulation; - - public Javadoc javadoc; // 1.5 addition for package-info.java - - public NLSTag[] nlsTags; - private StringLiteral[] stringLiterals; - private int stringLiteralsPtr; - private HashSetOfInt stringLiteralsStart; - - public boolean[] validIdentityComparisonLines; - - IrritantSet[] suppressWarningIrritants; // irritant for suppressed warnings - Annotation[] suppressWarningAnnotations; - long[] suppressWarningScopePositions; // (start << 32) + end - int suppressWarningsCount; - public int functionalExpressionsCount; - public FunctionalExpression[] functionalExpressions; - -public CompilationUnitDeclaration(ProblemReporter problemReporter, CompilationResult compilationResult, int sourceLength) { - this.problemReporter = problemReporter; - this.compilationResult = compilationResult; - //by definition of a compilation unit.... - this.sourceStart = 0; - this.sourceEnd = sourceLength - 1; -} - -/* - * We cause the compilation task to abort to a given extent. - */ -@Override -public void abort(int abortLevel, CategorizedProblem problem) { - switch (abortLevel) { - case AbortType : - throw new AbortType(this.compilationResult, problem); - case AbortMethod : - throw new AbortMethod(this.compilationResult, problem); - default : - throw new AbortCompilationUnit(this.compilationResult, problem); - } -} - -/* - * Dispatch code analysis AND request saturation of inner emulation - */ -public void analyseCode() { - if (this.ignoreFurtherInvestigation) - return; - try { - if (this.types != null) { - for (int i = 0, count = this.types.length; i < count; i++) { - this.types[i].analyseCode(this.scope); - } - } - if (this.moduleDeclaration != null) { - this.moduleDeclaration.analyseCode(this.scope); - } - // request inner emulation propagation - propagateInnerEmulationForAllLocalTypes(); - } catch (AbortCompilationUnit e) { - this.ignoreFurtherInvestigation = true; - return; - } -} - -/* - * When unit result is about to be accepted, removed back pointers - * to compiler structures. - */ -public void cleanUp() { - if (this.types != null) { - for (int i = 0, max = this.types.length; i < max; i++) { - cleanUp(this.types[i]); - } - for (LocalTypeBinding localType : this.localTypes.values()) { - // null out the type's scope backpointers - localType.cleanUp(); // local members are already in the list - localType.enclosingCase = null; - } - } - if (this.functionalExpressionsCount > 0) { - for (int i = 0, max = this.functionalExpressionsCount; i < max; i++) { - this.functionalExpressions[i].cleanUp(); - } - } - - this.compilationResult.recoveryScannerData = null; // recovery is already done - - ClassFile[] classFiles = this.compilationResult.getClassFiles(); - for (int i = 0, max = classFiles.length; i < max; i++) { - // clear the classFile back pointer to the bindings - ClassFile classFile = classFiles[i]; - // null out the classfile backpointer to a type binding - classFile.referenceBinding = null; - classFile.innerClassesBindings = null; - classFile.bootstrapMethods = null; - classFile.missingTypes = null; - classFile.visitedTypes = null; - } - - this.suppressWarningAnnotations = null; - - if (this.scope != null) - this.scope.cleanUpInferenceContexts(); -} - -private void cleanUp(TypeDeclaration type) { - if (type.memberTypes != null) { - for (int i = 0, max = type.memberTypes.length; i < max; i++){ - cleanUp(type.memberTypes[i]); - } - } - if (type.binding != null && type.binding.isAnnotationType()) - this.compilationResult.hasAnnotations = true; - if (type.binding != null) { - // null out the type's scope backpointers - type.binding.cleanUp(); - } -} - -public void checkUnusedImports(){ - if (this.scope.imports != null){ - for (int i = 0, max = this.scope.imports.length; i < max; i++){ - ImportBinding importBinding = this.scope.imports[i]; - ImportReference importReference = importBinding.reference; - if (importReference != null && ((importReference.bits & ASTNode.Used) == 0)){ - this.scope.problemReporter().unusedImport(importReference); - } - } - } -} - -@Override -public CompilationResult compilationResult() { - return this.compilationResult; -} - -public void createPackageInfoType() { - TypeDeclaration declaration = new TypeDeclaration(this.compilationResult); - declaration.name = TypeConstants.PACKAGE_INFO_NAME; - declaration.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccInterface; - declaration.javadoc = this.javadoc; - this.types[0] = declaration; // Assumes the first slot is meant for this type -} - -/* - * Finds the matching type amoung this compilation unit types. - * Returns null if no type with this name is found. - * The type name is a compound name - * e.g. if we're looking for X.A.B then a type name would be {X, A, B} - */ -public TypeDeclaration declarationOfType(char[][] typeName) { - for (int i = 0; i < this.types.length; i++) { - TypeDeclaration typeDecl = this.types[i].declarationOfType(typeName); - if (typeDecl != null) { - return typeDecl; - } - } - return null; -} - -public void finalizeProblems() { - this.compilationResult.materializeProblems(); - int problemCount = this.compilationResult.problemCount; - CategorizedProblem[] problems = this.compilationResult.problems; - if (this.suppressWarningsCount == 0) { - return; - } - int removed = 0; - IrritantSet[] foundIrritants = new IrritantSet[this.suppressWarningsCount]; - CompilerOptions options = this.scope.compilerOptions(); - boolean hasMandatoryErrors = false; - nextProblem: for (int iProblem = 0, length = problemCount; iProblem < length; iProblem++) { - CategorizedProblem problem = problems[iProblem]; - int problemID = problem.getID(); - int irritant = ProblemReporter.getIrritant(problemID); - boolean isError = problem.isError(); - if (isError) { - if (irritant == 0) { - // tolerate unused warning tokens when mandatory errors - hasMandatoryErrors = true; - continue; - } - if (!options.suppressOptionalErrors) { - continue; - } - } - int start = problem.getSourceStart(); - int end = problem.getSourceEnd(); - nextSuppress: for (int iSuppress = 0, suppressCount = this.suppressWarningsCount; iSuppress < suppressCount; iSuppress++) { - long position = this.suppressWarningScopePositions[iSuppress]; - int startSuppress = (int) (position >>> 32); - int endSuppress = (int) position; - if (start < startSuppress) continue nextSuppress; - if (end > endSuppress) continue nextSuppress; - if (!this.suppressWarningIrritants[iSuppress].isSet(irritant)) { - continue nextSuppress; - } - // discard suppressed warning - removed++; - problems[iProblem] = null; - this.compilationResult.removeProblem(problem); - if (foundIrritants[iSuppress] == null){ - foundIrritants[iSuppress] = new IrritantSet(irritant); - } else { - foundIrritants[iSuppress].set(irritant); - } - continue nextProblem; - } - } - // compact remaining problems - if (removed > 0) { - for (int i = 0, index = 0; i < problemCount; i++) { - CategorizedProblem problem; - if ((problem = problems[i]) != null) { - if (i > index) { - problems[index++] = problem; - } else { - index++; - } - } - } - } - // flag SuppressWarnings which had no effect (only if no (mandatory) error got detected within unit - if (!hasMandatoryErrors) { - int severity = options.getSeverity(CompilerOptions.UnusedWarningToken); - if (severity != ProblemSeverities.Ignore) { - boolean unusedWarningTokenIsWarning = (severity & ProblemSeverities.Error) == 0; - for (int iSuppress = 0, suppressCount = this.suppressWarningsCount; iSuppress < suppressCount; iSuppress++) { - Annotation annotation = this.suppressWarningAnnotations[iSuppress]; - if (annotation == null) continue; // implicit annotation - IrritantSet irritants = this.suppressWarningIrritants[iSuppress]; - if (unusedWarningTokenIsWarning && irritants.areAllSet()) continue; // @SuppressWarnings("all") also suppresses unused warning token - if (irritants != foundIrritants[iSuppress]) { // mismatch, some warning tokens were unused - MemberValuePair[] pairs = annotation.memberValuePairs(); - pairLoop: for (int iPair = 0, pairCount = pairs.length; iPair < pairCount; iPair++) { - MemberValuePair pair = pairs[iPair]; - if (CharOperation.equals(pair.name, TypeConstants.VALUE)) { - Expression value = pair.value; - if (value instanceof ArrayInitializer) { - ArrayInitializer initializer = (ArrayInitializer) value; - Expression[] inits = initializer.expressions; - if (inits != null) { - for (int iToken = 0, tokenCount = inits.length; iToken < tokenCount; iToken++) { - Constant cst = inits[iToken].constant; - if (cst != Constant.NotAConstant && cst.typeID() == TypeIds.T_JavaLangString) { - IrritantSet tokenIrritants = CompilerOptions.warningTokenToIrritants(cst.stringValue()); - if (tokenIrritants != null) { - if (!tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all") - && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem - if (unusedWarningTokenIsWarning) { - int start = value.sourceStart, end = value.sourceEnd; - nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) { - long position = this.suppressWarningScopePositions[jSuppress]; - int startSuppress = (int) (position >>> 32); - int endSuppress = (int) position; - if (start < startSuppress) continue nextSuppress; - if (end > endSuppress) continue nextSuppress; - if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all? - } - } - int id = options.getIgnoredIrritant(tokenIrritants); - if (id > 0) { - String key = CompilerOptions.optionKeyFromIrritant(id); - this.scope.problemReporter().problemNotAnalysed(inits[iToken], key); - } else { - this.scope.problemReporter().unusedWarningToken(inits[iToken]); - } - } - } - } - } - } - } else { - Constant cst = value.constant; - if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) { - IrritantSet tokenIrritants = CompilerOptions.warningTokenToIrritants(cst.stringValue()); - if (tokenIrritants != null) { - if (!tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all") - && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem - if (unusedWarningTokenIsWarning) { - int start = value.sourceStart, end = value.sourceEnd; - nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) { - long position = this.suppressWarningScopePositions[jSuppress]; - int startSuppress = (int) (position >>> 32); - int endSuppress = (int) position; - if (start < startSuppress) continue nextSuppress; - if (end > endSuppress) continue nextSuppress; - if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all? - } - } - int id = options.getIgnoredIrritant(tokenIrritants); - if (id > 0) { - String key = CompilerOptions.optionKeyFromIrritant(id); - this.scope.problemReporter().problemNotAnalysed(value, key); - } else { - this.scope.problemReporter().unusedWarningToken(value); - } - } - } - } - } - break pairLoop; - } - } - } - } - } - } -} - -/** - * Bytecode generation - */ -public void generateCode() { - if (this.ignoreFurtherInvestigation) { - if (this.types != null) { - for (int i = 0, count = this.types.length; i < count; i++) { - this.types[i].ignoreFurtherInvestigation = true; - // propagate the flag to request problem type creation - this.types[i].generateCode(this.scope); - } - } - return; - } - try { - if (this.types != null) { - for (int i = 0, count = this.types.length; i < count; i++) - this.types[i].generateCode(this.scope); - } - if (this.moduleDeclaration != null) { - this.moduleDeclaration.generateCode(); - } - } catch (AbortCompilationUnit e) { - // ignore - } -} - -@Override -public CompilationUnitDeclaration getCompilationUnitDeclaration() { - return this; -} - -public char[] getFileName() { - return this.compilationResult.getFileName(); -} - -public char[] getMainTypeName() { - if (this.compilationResult.compilationUnit == null) { - char[] fileName = this.compilationResult.getFileName(); - - int start = CharOperation.lastIndexOf('/', fileName) + 1; - if (start == 0 || start < CharOperation.lastIndexOf('\\', fileName)) - start = CharOperation.lastIndexOf('\\', fileName) + 1; - - int end = CharOperation.lastIndexOf('.', fileName); - if (end == -1) - end = fileName.length; - - return CharOperation.subarray(fileName, start, end); - } else { - return this.compilationResult.compilationUnit.getMainTypeName(); - } -} - -public boolean isEmpty() { - return (this.currentPackage == null) && (this.imports == null) && (this.types == null); -} - -public boolean isPackageInfo() { - return CharOperation.equals(getMainTypeName(), TypeConstants.PACKAGE_INFO_NAME); -} - -public boolean isModuleInfo() { - return CharOperation.equals(getMainTypeName(), TypeConstants.MODULE_INFO_NAME); -} - -public boolean isSuppressed(CategorizedProblem problem) { - if (this.suppressWarningsCount == 0) return false; - int irritant = ProblemReporter.getIrritant(problem.getID()); - if (irritant == 0) return false; - int start = problem.getSourceStart(); - int end = problem.getSourceEnd(); - nextSuppress: for (int iSuppress = 0, suppressCount = this.suppressWarningsCount; iSuppress < suppressCount; iSuppress++) { - long position = this.suppressWarningScopePositions[iSuppress]; - int startSuppress = (int) (position >>> 32); - int endSuppress = (int) position; - if (start < startSuppress) continue nextSuppress; - if (end > endSuppress) continue nextSuppress; - if (this.suppressWarningIrritants[iSuppress].isSet(irritant)) - return true; - } - return false; -} - -public boolean hasFunctionalTypes() { - return this.compilationResult.hasFunctionalTypes; -} - -@Override -public boolean hasErrors() { - return this.ignoreFurtherInvestigation; -} - -@Override -public StringBuilder print(int indent, StringBuilder output) { - if (this.currentPackage != null) { - printIndent(indent, output).append("package "); //$NON-NLS-1$ - this.currentPackage.print(0, output, false).append(";\n"); //$NON-NLS-1$ - } - if (this.imports != null) - for (int i = 0; i < this.imports.length; i++) { - printIndent(indent, output).append("import "); //$NON-NLS-1$ - ImportReference currentImport = this.imports[i]; - if (currentImport.isStatic()) { - output.append("static "); //$NON-NLS-1$ - } - currentImport.print(0, output).append(";\n"); //$NON-NLS-1$ - } - if (this.moduleDeclaration != null) { - this.moduleDeclaration.print(indent, output).append("\n"); //$NON-NLS-1$ - } else if (this.types != null) { - for (int i = 0; i < this.types.length; i++) { - this.types[i].print(indent, output).append("\n"); //$NON-NLS-1$ - } - } - return output; -} - -/* - * Force inner local types to update their innerclass emulation - */ -public void propagateInnerEmulationForAllLocalTypes() { - this.isPropagatingInnerClassEmulation = true; - for (LocalTypeBinding localType : this.localTypes.values()) { - // only propagate for reachable local types - if ((localType.scope.referenceType().bits & IsReachable) != 0) { - localType.updateInnerEmulationDependents(); - } - } -} - -public void recordStringLiteral(StringLiteral literal, boolean fromRecovery) { - if (this.stringLiteralsStart != null) { - if (this.stringLiteralsStart.contains(literal.sourceStart)) return; - this.stringLiteralsStart.add(literal.sourceStart); - } else if (fromRecovery) { - this.stringLiteralsStart = new HashSetOfInt(this.stringLiteralsPtr + STRING_LITERALS_INCREMENT); - for (int i = 0; i < this.stringLiteralsPtr; i++) { - this.stringLiteralsStart.add(this.stringLiterals[i].sourceStart); - } - - if (this.stringLiteralsStart.contains(literal.sourceStart)) return; - this.stringLiteralsStart.add(literal.sourceStart); - } - - if (this.stringLiterals == null) { - this.stringLiterals = new StringLiteral[STRING_LITERALS_INCREMENT]; - this.stringLiteralsPtr = 0; - } else { - int stackLength = this.stringLiterals.length; - if (this.stringLiteralsPtr == stackLength) { - System.arraycopy( - this.stringLiterals, - 0, - this.stringLiterals = new StringLiteral[stackLength + STRING_LITERALS_INCREMENT], - 0, - stackLength); - } - } - this.stringLiterals[this.stringLiteralsPtr++] = literal; -} - -private boolean isLambdaExpressionCopyContext(ReferenceContext context) { - if (context instanceof LambdaExpression && context != ((LambdaExpression) context).original()) - return true; // Do not record from copies. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=441929 - Scope cScope = context instanceof AbstractMethodDeclaration ? ((AbstractMethodDeclaration) context).scope : - context instanceof TypeDeclaration ? ((TypeDeclaration) context).scope : - context instanceof LambdaExpression ? ((LambdaExpression) context).scope : - null; - return cScope != null ? isLambdaExpressionCopyContext(cScope.parent.referenceContext()) : false; -} -public void recordSuppressWarnings(IrritantSet irritants, Annotation annotation, int scopeStart, int scopeEnd, ReferenceContext context) { - if (isLambdaExpressionCopyContext(context)) - return; // Do not record from copies. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=441929 - - if (this.suppressWarningIrritants == null) { - this.suppressWarningIrritants = new IrritantSet[3]; - this.suppressWarningAnnotations = new Annotation[3]; - this.suppressWarningScopePositions = new long[3]; - } else if (this.suppressWarningIrritants.length == this.suppressWarningsCount) { - System.arraycopy(this.suppressWarningIrritants, 0,this.suppressWarningIrritants = new IrritantSet[2*this.suppressWarningsCount], 0, this.suppressWarningsCount); - System.arraycopy(this.suppressWarningAnnotations, 0,this.suppressWarningAnnotations = new Annotation[2*this.suppressWarningsCount], 0, this.suppressWarningsCount); - System.arraycopy(this.suppressWarningScopePositions, 0,this.suppressWarningScopePositions = new long[2*this.suppressWarningsCount], 0, this.suppressWarningsCount); - } - final long scopePositions = ((long)scopeStart<<32) + scopeEnd; - for (int i = 0, max = this.suppressWarningsCount; i < max; i++) { - if (this.suppressWarningAnnotations[i] == annotation - && this.suppressWarningScopePositions[i] == scopePositions - && this.suppressWarningIrritants[i].hasSameIrritants(irritants)) { - // annotation data already recorded - return; - } - } - this.suppressWarningIrritants[this.suppressWarningsCount] = irritants; - this.suppressWarningAnnotations[this.suppressWarningsCount] = annotation; - this.suppressWarningScopePositions[this.suppressWarningsCount++] = scopePositions; -} - -/* - * Keep track of all local types, so as to update their innerclass - * emulation later on. - */ -public void record(LocalTypeBinding localType) { - if (this.localTypes == Collections.EMPTY_MAP) - this.localTypes = new HashMap<>(); - this.localTypes.put(localType.sourceStart, localType); -} -public void updateLocalTypesInMethod(MethodBinding methodBinding) { - if (this.localTypes == Collections.EMPTY_MAP) - return; - LambdaExpression.updateLocalTypesInMethod(methodBinding, new LocalTypeSubstitutor(this.localTypes, methodBinding), new NullSubstitution(this.scope.environment())); -} - -/* - * Keep track of all lambda/method reference expressions, so as to be able to look it up later without - * having to traverse AST. Return the "ordinal" returned by the enclosing type. - */ -public int record(FunctionalExpression expression) { - if (this.functionalExpressionsCount == 0) { - this.functionalExpressions = new FunctionalExpression[5]; - } else if (this.functionalExpressionsCount == this.functionalExpressions.length) { - System.arraycopy(this.functionalExpressions, 0, (this.functionalExpressions = new FunctionalExpression[this.functionalExpressionsCount * 2]), 0, this.functionalExpressionsCount); - } - this.functionalExpressions[this.functionalExpressionsCount++] = expression; - return expression.enclosingScope.classScope().referenceContext.record(expression); -} - -public void resolve() { - int startingTypeIndex = 0; - boolean isPackageInfo = isPackageInfo(); - boolean isModuleInfo = isModuleInfo(); - if (this.types != null && isPackageInfo) { - // resolve synthetic type declaration - final TypeDeclaration syntheticTypeDeclaration = this.types[0]; - // set empty javadoc to avoid missing warning (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=95286) - if (syntheticTypeDeclaration.javadoc == null) { - syntheticTypeDeclaration.javadoc = new Javadoc(syntheticTypeDeclaration.declarationSourceStart, syntheticTypeDeclaration.declarationSourceStart); - } - syntheticTypeDeclaration.resolve(this.scope); - /* - * resolve javadoc package if any, skip this step if we don't have a valid scope due to an earlier error (bug 252555) - * we do it now as the javadoc in the fake type won't be resolved. The peculiar usage of MethodScope to resolve the - * package level javadoc is because the CU level resolve method is a NOP to mimic Javadoc's behavior and can't be used - * as such. - */ - if (this.javadoc != null && syntheticTypeDeclaration.staticInitializerScope != null) { - this.javadoc.resolve(syntheticTypeDeclaration.staticInitializerScope); - } - startingTypeIndex = 1; - } else if (this.moduleDeclaration != null && isModuleInfo) { - if (this.javadoc != null) { - this.javadoc.resolve(this.moduleDeclaration.scope); - } else if (this.moduleDeclaration.binding != null) { - ProblemReporter reporter = this.scope.problemReporter(); - int severity = reporter.computeSeverity(IProblem.JavadocMissing); - if (severity != ProblemSeverities.Ignore) { - reporter.javadocModuleMissing(this.moduleDeclaration.declarationSourceStart, this.moduleDeclaration.bodyStart, - severity); - } - } - } else { - // resolve compilation unit javadoc package if any - if (this.javadoc != null) { - this.javadoc.resolve(this.scope); - } - } - if (this.currentPackage != null && this.currentPackage.annotations != null && !isPackageInfo) { - this.scope.problemReporter().invalidFileNameForPackageAnnotations(this.currentPackage.annotations[0]); - } - try { - if (this.types != null) { - for (int i = startingTypeIndex, count = this.types.length; i < count; i++) { - this.types[i].resolve(this.scope); - } - } - if (!this.compilationResult.hasMandatoryErrors()) checkUnusedImports(); - reportNLSProblems(); - } catch (AbortCompilationUnit e) { - this.ignoreFurtherInvestigation = true; - return; - } -} - -private void reportNLSProblems() { - if (this.nlsTags != null || this.stringLiterals != null) { - final int stringLiteralsLength = this.stringLiteralsPtr; - final int nlsTagsLength = this.nlsTags == null ? 0 : this.nlsTags.length; - if (stringLiteralsLength == 0) { - if (nlsTagsLength != 0) { - for (int i = 0; i < nlsTagsLength; i++) { - NLSTag tag = this.nlsTags[i]; - if (tag != null) { - this.scope.problemReporter().unnecessaryNLSTags(tag.start, tag.end); - } - } - } - } else if (nlsTagsLength == 0) { - // resize string literals - if (this.stringLiterals.length != stringLiteralsLength) { - System.arraycopy(this.stringLiterals, 0, (this.stringLiterals = new StringLiteral[stringLiteralsLength]), 0, stringLiteralsLength); - } - Arrays.sort(this.stringLiterals, STRING_LITERAL_COMPARATOR); - for (int i = 0; i < stringLiteralsLength; i++) { - this.scope.problemReporter().nonExternalizedStringLiteral(this.stringLiterals[i]); - } - } else { - // need to iterate both arrays to find non matching elements - if (this.stringLiterals.length != stringLiteralsLength) { - System.arraycopy(this.stringLiterals, 0, (this.stringLiterals = new StringLiteral[stringLiteralsLength]), 0, stringLiteralsLength); - } - Arrays.sort(this.stringLiterals, STRING_LITERAL_COMPARATOR); - int indexInLine = 1; - int lastLineNumber = -1; - StringLiteral literal = null; - int index = 0; - int i = 0; - stringLiteralsLoop: for (; i < stringLiteralsLength; i++) { - literal = this.stringLiterals[i]; - final int literalLineNumber = literal instanceof TextBlock ? ((TextBlock)literal).endLineNumber : literal.getLineNumber(); - if (lastLineNumber != literalLineNumber) { - indexInLine = 1; - lastLineNumber = literalLineNumber; - } else { - indexInLine++; - } - if (index < nlsTagsLength) { - nlsTagsLoop: for (; index < nlsTagsLength; index++) { - NLSTag tag = this.nlsTags[index]; - if (tag == null) continue nlsTagsLoop; - int tagLineNumber = tag.lineNumber; - if (literalLineNumber < tagLineNumber) { - this.scope.problemReporter().nonExternalizedStringLiteral(literal); - continue stringLiteralsLoop; - } else if (literalLineNumber == tagLineNumber) { - if (tag.index == indexInLine) { - this.nlsTags[index] = null; - index++; - continue stringLiteralsLoop; - } else { - nlsTagsLoop2: for (int index2 = index + 1; index2 < nlsTagsLength; index2++) { - NLSTag tag2 = this.nlsTags[index2]; - if (tag2 == null) continue nlsTagsLoop2; - int tagLineNumber2 = tag2.lineNumber; - if (literalLineNumber == tagLineNumber2) { - if (tag2.index == indexInLine) { - this.nlsTags[index2] = null; - continue stringLiteralsLoop; - } else { - continue nlsTagsLoop2; - } - } else { - this.scope.problemReporter().nonExternalizedStringLiteral(literal); - continue stringLiteralsLoop; - } - } - this.scope.problemReporter().nonExternalizedStringLiteral(literal); - continue stringLiteralsLoop; - } - } else { - this.scope.problemReporter().unnecessaryNLSTags(tag.start, tag.end); - continue nlsTagsLoop; - } - } - } - // all nls tags have been processed, so remaining string literals are not externalized - break stringLiteralsLoop; - } - for (; i < stringLiteralsLength; i++) { - this.scope.problemReporter().nonExternalizedStringLiteral(this.stringLiterals[i]); - } - if (index < nlsTagsLength) { - for (; index < nlsTagsLength; index++) { - NLSTag tag = this.nlsTags[index]; - if (tag != null) { - this.scope.problemReporter().unnecessaryNLSTags(tag.start, tag.end); - } - } - } - } - } -} - -@Override -public void tagAsHavingErrors() { - this.ignoreFurtherInvestigation = true; -} - -@Override -public void tagAsHavingIgnoredMandatoryErrors(int problemId) { - // Nothing to do for this context; -} - -public void traverse(ASTVisitor visitor, CompilationUnitScope unitScope) { - traverse(visitor, unitScope, true); -} -public void traverse(ASTVisitor visitor, CompilationUnitScope unitScope, boolean skipOnError) { - if (skipOnError && this.ignoreFurtherInvestigation) - return; - try { - if (visitor.visit(this, this.scope)) { - if (this.types != null && isPackageInfo()) { - // resolve synthetic type declaration - final TypeDeclaration syntheticTypeDeclaration = this.types[0]; - // resolve javadoc package if any - final MethodScope methodScope = syntheticTypeDeclaration.staticInitializerScope; - // Don't traverse in null scope and invite trouble a la bug 252555. - if (this.javadoc != null && methodScope != null) { - this.javadoc.traverse(visitor, methodScope); - } - // Don't traverse in null scope and invite trouble a la bug 252555. - if (this.currentPackage != null && methodScope != null) { - final Annotation[] annotations = this.currentPackage.annotations; - if (annotations != null) { - int annotationsLength = annotations.length; - for (int i = 0; i < annotationsLength; i++) { - annotations[i].traverse(visitor, methodScope); - } - } - } - } - if (this.currentPackage != null) { - this.currentPackage.traverse(visitor, this.scope); - } - if (this.imports != null) { - int importLength = this.imports.length; - for (int i = 0; i < importLength; i++) { - this.imports[i].traverse(visitor, this.scope); - } - } - if (this.types != null) { - int typesLength = this.types.length; - for (int i = 0; i < typesLength; i++) { - this.types[i].traverse(visitor, this.scope); - } - } - if (this.isModuleInfo() && this.moduleDeclaration != null) { - this.moduleDeclaration.traverse(visitor, this.scope); - } - } - visitor.endVisit(this, this.scope); - } catch (AbortCompilationUnit e) { - // ignore - } -} -public ModuleBinding module(LookupEnvironment environment) { - if (this.moduleDeclaration != null) { - ModuleBinding binding = this.moduleDeclaration.binding; - if (binding != null) - return binding; - } - if (this.compilationResult != null) { - ICompilationUnit compilationUnit = this.compilationResult.compilationUnit; - if (compilationUnit != null) - return compilationUnit.module(environment); - } - return environment.module; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java deleted file mode 100644 index b390ca5..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/CompoundAssignment.java +++ /dev/null @@ -1,230 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check - * Jesper S Moller - Contributions for - * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class CompoundAssignment extends Assignment implements OperatorIds { - public int operator; - public int preAssignImplicitConversion; - - // var op exp is equivalent to var = (varType) var op exp - // assignmentImplicitConversion stores the cast needed for the assignment - - public CompoundAssignment(Expression lhs, Expression expression,int operator, int sourceEnd) { - //lhs is always a reference by construction , - //but is build as an expression ==> the checkcast cannot fail - - super(lhs, expression, sourceEnd); - lhs.bits &= ~IsStrictlyAssigned; // tag lhs as NON assigned - it is also a read access - lhs.bits |= IsCompoundAssigned; // tag lhs as assigned by compound - this.operator = operator ; - } - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, - FlowInfo flowInfo) { - // record setting a variable: various scenarii are possible, setting an array reference, - // a field reference, a blank final field reference, a field of an enclosing instance or - // just a local variable. - if (this.resolvedType.id != T_JavaLangString) { - this.lhs.checkNPE(currentScope, flowContext, flowInfo); - // account for exceptions thrown by any arithmetics: - flowContext.recordAbruptExit(); - } - this.expression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - flowInfo = ((Reference) this.lhs).analyseAssignment(currentScope, flowContext, flowInfo, this, true).unconditionalInits(); - if (this.resolvedType.id == T_JavaLangString) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=339250 - LocalVariableBinding local = this.lhs.localVariableBinding(); - if (local != null) { - // compound assignment results in a definitely non null value for String - flowInfo.markAsDefinitelyNonNull(local); - flowContext.markFinallyNullStatus(local, FlowInfo.NON_NULL); - } - } - return flowInfo; -} - - public boolean checkCastCompatibility() { - return true; - } - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - - // various scenarii are possible, setting an array reference, - // a field reference, a blank final field reference, a field of an enclosing instance or - // just a local variable. - - int pc = codeStream.position; - ((Reference) this.lhs).generateCompoundAssignment(currentScope, codeStream, this.expression, this.operator, this.preAssignImplicitConversion, valueRequired); - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - -@Override -public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - return FlowInfo.NON_NULL; - // we may have complained on checkNPE, but we avoid duplicate error -} - - public String operatorToString() { - switch (this.operator) { - case PLUS : - return "+="; //$NON-NLS-1$ - case MINUS : - return "-="; //$NON-NLS-1$ - case MULTIPLY : - return "*="; //$NON-NLS-1$ - case DIVIDE : - return "/="; //$NON-NLS-1$ - case AND : - return "&="; //$NON-NLS-1$ - case OR : - return "|="; //$NON-NLS-1$ - case XOR : - return "^="; //$NON-NLS-1$ - case REMAINDER : - return "%="; //$NON-NLS-1$ - case LEFT_SHIFT : - return "<<="; //$NON-NLS-1$ - case RIGHT_SHIFT : - return ">>="; //$NON-NLS-1$ - case UNSIGNED_RIGHT_SHIFT : - return ">>>="; //$NON-NLS-1$ - } - return "unknown operator"; //$NON-NLS-1$ - } - - @Override - public StringBuilder printExpressionNoParenthesis(int indent, StringBuilder output) { - - this.lhs.printExpression(indent, output).append(' ').append(operatorToString()).append(' '); - return this.expression.printExpression(0, output) ; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - this.constant = Constant.NotAConstant; - if (!(this.lhs instanceof Reference) || this.lhs.isThis()) { - scope.problemReporter().expressionShouldBeAVariable(this.lhs); - return null; - } - boolean expressionIsCast = this.expression instanceof CastExpression; - if (expressionIsCast) - this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - TypeBinding originalLhsType = this.lhs.resolveType(scope); - TypeBinding originalExpressionType = this.expression.resolveType(scope); - if (originalLhsType == null || originalExpressionType == null) - return null; - // autoboxing support - LookupEnvironment env = scope.environment(); - TypeBinding lhsType = originalLhsType, expressionType = originalExpressionType; - boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; - boolean unboxedLhs = false; - if (use15specifics) { - if (!lhsType.isBaseType() && expressionType.id != T_JavaLangString && expressionType.id != T_null) { - TypeBinding unboxedType = env.computeBoxingType(lhsType); - if (TypeBinding.notEquals(unboxedType, lhsType)) { - lhsType = unboxedType; - unboxedLhs = true; - } - } - if (!expressionType.isBaseType() && lhsType.id != T_JavaLangString && lhsType.id != T_null) { - expressionType = env.computeBoxingType(expressionType); - } - } - - if (restrainUsageToNumericTypes() && !lhsType.isNumericType()) { - scope.problemReporter().operatorOnlyValidOnNumericType(this, lhsType, expressionType); - return null; - } - int lhsID = lhsType.id; - int expressionID = expressionType.id; - if (lhsID > 15 || expressionID > 15) { - if (lhsID != T_JavaLangString) { // String += Thread is valid whereas Thread += String is not - scope.problemReporter().invalidOperator(this, lhsType, expressionType); - return null; - } - expressionID = T_JavaLangObject; // use the Object has tag table - } - - // the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 <<0 - - // the conversion is stored INTO the reference (info needed for the code gen) - int result = OperatorExpression.OperatorSignatures[this.operator][ (lhsID << 4) + expressionID]; - if (result == T_undefined) { - scope.problemReporter().invalidOperator(this, lhsType, expressionType); - return null; - } - if (this.operator == PLUS){ - if(lhsID == T_JavaLangObject && (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_7)) { - // += is illegal (39248) for compliance < 1.7 - scope.problemReporter().invalidOperator(this, lhsType, expressionType); - return null; - } else { - // += is illegal - if ((lhsType.isNumericType() || lhsID == T_boolean) && !expressionType.isNumericType()){ - scope.problemReporter().invalidOperator(this, lhsType, expressionType); - return null; - } - } - } - TypeBinding resultType = TypeBinding.wellKnownType(scope, result & 0x0000F); - if (checkCastCompatibility()) { - if (originalLhsType.id != T_JavaLangString && resultType.id != T_JavaLangString) { - if (!checkCastTypesCompatibility(scope, originalLhsType, resultType, null, true)) { - scope.problemReporter().invalidOperator(this, originalLhsType, expressionType); - return null; - } - } - } - this.lhs.computeConversion(scope, TypeBinding.wellKnownType(scope, (result >>> 16) & 0x0000F), originalLhsType); - this.expression.computeConversion(scope, TypeBinding.wellKnownType(scope, (result >>> 8) & 0x0000F), originalExpressionType); - this.preAssignImplicitConversion = (unboxedLhs ? BOXING : 0) | (lhsID << 4) | (result & 0x0000F); - if (unboxedLhs) scope.problemReporter().autoboxing(this, lhsType, originalLhsType); - if (expressionIsCast) - CastExpression.checkNeedForArgumentCasts(scope, this.operator, result, this.lhs, originalLhsType.id, false, this.expression, originalExpressionType.id, true); - return this.resolvedType = originalLhsType; - } - - public boolean restrainUsageToNumericTypes(){ - return false ; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.lhs.traverse(visitor, scope); - this.expression.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java deleted file mode 100644 index 5a2c96c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java +++ /dev/null @@ -1,879 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephen Herrmann - Contributions for - * bug 133125 - [compiler][null] need to report the null status of expressions and analyze them simultaneously - * 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 - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 400761 - [compiler][null] null may be return as boolean without a diagnostic - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 426078 - [1.8] VerifyError when conditional expression passed as an argument - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 418537 - [1.8][null] Fix null type annotation analysis for poly conditional expressions - * Bug 428352 - [1.8][compiler] Resolution errors don't always surface - * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.*; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class ConditionalExpression extends OperatorExpression implements IPolyExpression { - - public Expression condition, valueIfTrue, valueIfFalse; - public Constant optimizedBooleanConstant; - public Constant optimizedIfTrueConstant; - public Constant optimizedIfFalseConstant; - - // for local variables table attributes - int trueInitStateIndex = -1; - int falseInitStateIndex = -1; - int mergedInitStateIndex = -1; - - // we compute and store the null status during analyseCode (https://bugs.eclipse.org/324178): - private int nullStatus = FlowInfo.UNKNOWN; - int ifFalseNullStatus; - int ifTrueNullStatus; - private TypeBinding expectedType; - private ExpressionContext expressionContext = VANILLA_CONTEXT; - private boolean isPolyExpression = false; - private TypeBinding originalValueIfTrueType; - private TypeBinding originalValueIfFalseType; - private boolean use18specifics; - - public ConditionalExpression(Expression condition, Expression valueIfTrue, Expression valueIfFalse) { - this.condition = condition; - this.valueIfTrue = valueIfTrue; - this.valueIfFalse = valueIfFalse; - this.sourceStart = condition.sourceStart; - this.sourceEnd = valueIfFalse.sourceEnd; - } - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, - FlowInfo flowInfo) { - int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; - Constant cst = this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - - int mode = flowInfo.reachMode(); - flowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo, cst == Constant.NotAConstant); - - flowContext.conditionalLevel++; - - // process the if-true part - FlowInfo trueFlowInfo = flowInfo.initsWhenTrue().copy(); - final CompilerOptions compilerOptions = currentScope.compilerOptions(); - if (isConditionOptimizedFalse) { - if ((mode & FlowInfo.UNREACHABLE) == 0) { - trueFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - if (!isKnowDeadCodePattern(this.condition) || compilerOptions.reportDeadCodeInTrivialIfStatement) { - this.valueIfTrue.complainIfUnreachable(trueFlowInfo, currentScope, initialComplaintLevel, false); - } - } - this.trueInitStateIndex = currentScope.methodScope().recordInitializationStates(trueFlowInfo); - this.condition.updateFlowOnBooleanResult(trueFlowInfo, true); - trueFlowInfo = this.valueIfTrue.analyseCode(currentScope, flowContext, trueFlowInfo); - this.valueIfTrue.checkNPEbyUnboxing(currentScope, flowContext, trueFlowInfo); - - // may need to fetch this null status before expireNullCheckedFieldInfo(): - this.ifTrueNullStatus = -1; - if (compilerOptions.enableSyntacticNullAnalysisForFields) { - this.ifTrueNullStatus = this.valueIfTrue.nullStatus(trueFlowInfo, flowContext); - // wipe information that was meant only for valueIfTrue: - flowContext.expireNullCheckedFieldInfo(); - } - - // process the if-false part - FlowInfo falseFlowInfo = flowInfo.initsWhenFalse().copy(); - if (isConditionOptimizedTrue) { - if ((mode & FlowInfo.UNREACHABLE) == 0) { - falseFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - if (!isKnowDeadCodePattern(this.condition) || compilerOptions.reportDeadCodeInTrivialIfStatement) { - this.valueIfFalse.complainIfUnreachable(falseFlowInfo, currentScope, initialComplaintLevel, true); - } - } - this.falseInitStateIndex = currentScope.methodScope().recordInitializationStates(falseFlowInfo); - this.condition.updateFlowOnBooleanResult(falseFlowInfo, false); - - EqualExpression simpleCondition = this.condition instanceof EqualExpression ? (EqualExpression) this.condition : null; - boolean doSyntacticAnalysisForFalseBranch = compilerOptions.enableSyntacticNullAnalysisForFields && simpleCondition != null; - if (doSyntacticAnalysisForFalseBranch) { - simpleCondition.syntacticFieldAnalysisForFalseBranch(flowInfo, flowContext); - } - falseFlowInfo = this.valueIfFalse.analyseCode(currentScope, flowContext, falseFlowInfo); - this.valueIfFalse.checkNPEbyUnboxing(currentScope, flowContext, falseFlowInfo); - - // may need to fetch this null status before expireNullCheckedFieldInfo(): - this.ifFalseNullStatus = -1; - if (doSyntacticAnalysisForFalseBranch) { - this.ifFalseNullStatus = this.valueIfFalse.nullStatus(falseFlowInfo, flowContext); - // wipe information that was meant only for valueIfFalse: - flowContext.expireNullCheckedFieldInfo(); - } - flowContext.conditionalLevel--; - - // merge if-true & if-false initializations - FlowInfo mergedInfo; - if (isConditionOptimizedTrue){ - mergedInfo = trueFlowInfo.addPotentialInitializationsFrom(falseFlowInfo); - if (this.ifTrueNullStatus != -1) { - this.nullStatus = this.ifTrueNullStatus; - } else { - this.nullStatus = this.valueIfTrue.nullStatus(trueFlowInfo, flowContext); - } - } else if (isConditionOptimizedFalse) { - mergedInfo = falseFlowInfo.addPotentialInitializationsFrom(trueFlowInfo); - this.nullStatus = this.valueIfFalse.nullStatus(falseFlowInfo, flowContext); - } else { - // this block must meet two conflicting requirements (see https://bugs.eclipse.org/324178): - // (1) For null analysis of "Object o2 = (o1 != null) ? o1 : new Object();" we need to distinguish - // the paths *originating* from the evaluation of the condition to true/false respectively. - // This is used to determine the possible null status of the entire conditional expression. - // (2) For definite assignment analysis (JLS 16.1.5) of boolean conditional expressions of the form - // "if (c1 ? expr1 : expr2) use(v);" we need to check whether any variable v will be definitely - // assigned whenever the entire conditional expression evaluates to true (to reach the then branch). - // I.e., we need to collect flowInfo *towards* the overall outcome true/false - // (regardless of the evaluation of the condition). - - // to support (1) use the infos of both branches originating from the condition for computing the nullStatus: - computeNullStatus(trueFlowInfo, falseFlowInfo, flowContext); - - // to support (2) we split the true/false branches according to their inner structure. Consider this: - // if (b ? false : (true && (v = false))) return v; -- ok - // - expr1 ("false") has no path towards true (mark as unreachable) - // - expr2 ("(true && (v = false))") has a branch towards true on which v is assigned. - // -> merging these two branches yields: v is assigned - // - the paths towards false are irrelevant since the enclosing if has no else. - cst = this.optimizedIfTrueConstant; - boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; - - cst = this.optimizedIfFalseConstant; - boolean isValueIfFalseOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isValueIfFalseOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; - - UnconditionalFlowInfo trueFlowTowardsTrue = trueFlowInfo.initsWhenTrue().unconditionalCopy(); - UnconditionalFlowInfo falseFlowTowardsTrue = falseFlowInfo.initsWhenTrue().unconditionalCopy(); - UnconditionalFlowInfo trueFlowTowardsFalse = trueFlowInfo.initsWhenFalse().unconditionalInits(); - UnconditionalFlowInfo falseFlowTowardsFalse = falseFlowInfo.initsWhenFalse().unconditionalInits(); - if (isValueIfTrueOptimizedFalse) { - trueFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - if (isValueIfFalseOptimizedFalse) { - falseFlowTowardsTrue.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - if (isValueIfTrueOptimizedTrue) { - trueFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - if (isValueIfFalseOptimizedTrue) { - falseFlowTowardsFalse.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - mergedInfo = - FlowInfo.conditional( - trueFlowTowardsTrue.mergedWith(falseFlowTowardsTrue), - trueFlowTowardsFalse.mergedWith(falseFlowTowardsFalse)); - } - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); - mergedInfo.setReachMode(mode); - - return mergedInfo; - } - - @Override - public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - if ((this.nullStatus & FlowInfo.NULL) != 0) - scope.problemReporter().expressionNullReference(this); - else if ((this.nullStatus & FlowInfo.POTENTIALLY_NULL) != 0) - scope.problemReporter().expressionPotentialNullReference(this); - return true; // all checking done - } - - private void computeNullStatus(FlowInfo trueBranchInfo, FlowInfo falseBranchInfo, FlowContext flowContext) { - // given that the condition cannot be optimized to a constant - // we now merge the nullStatus from both branches: - if (this.ifTrueNullStatus == -1) { // has this status been pre-computed? - this.ifTrueNullStatus = this.valueIfTrue.nullStatus(trueBranchInfo, flowContext); - } - if (this.ifFalseNullStatus == -1) { // has this status been pre-computed? - this.ifFalseNullStatus = this.valueIfFalse.nullStatus(falseBranchInfo, flowContext); - } - - if (this.ifTrueNullStatus == this.ifFalseNullStatus) { - this.nullStatus = this.ifTrueNullStatus; - return; - } - if (trueBranchInfo.reachMode() != FlowInfo.REACHABLE) { - this.nullStatus = this.ifFalseNullStatus; - return; - } - if (falseBranchInfo.reachMode() != FlowInfo.REACHABLE) { - this.nullStatus = this.ifTrueNullStatus; - return; - } - - // is there a chance of null (or non-null)? -> potentially null etc. - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=133125 - int combinedStatus = this.ifTrueNullStatus|this.ifFalseNullStatus; - int status = Expression.computeNullStatus(0, combinedStatus); - if (status > 0) - this.nullStatus = status; - } - - /** - * Code generation for the conditional operator ?: - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ - @Override - public void generateCode( - BlockScope currentScope, - CodeStream codeStream, - boolean valueRequired) { - - int pc = codeStream.position; - BranchLabel endifLabel, falseLabel; - if (this.constant != Constant.NotAConstant) { - if (valueRequired) - codeStream.generateConstant(this.constant, this.implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - Constant cst = this.condition.optimizedBooleanConstant(); - if (cst == Constant.NotAConstant) { - cst = this.condition.optimizedNullComparisonConstant(); - } - boolean needTruePart = !(cst != Constant.NotAConstant && cst.booleanValue() == false); - boolean needFalsePart = !(cst != Constant.NotAConstant && cst.booleanValue() == true); - - endifLabel = new BranchLabel(codeStream); - - // Generate code for the condition - falseLabel = new BranchLabel(codeStream); - falseLabel.tagBits |= BranchLabel.USED; - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - null, - falseLabel, - cst == Constant.NotAConstant); - - if (this.trueInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - this.trueInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.trueInitStateIndex); - } - // Then code generation - if (needTruePart) { - this.valueIfTrue.generateCode(currentScope, codeStream, valueRequired); - if (needFalsePart) { - // Jump over the else part - int position = codeStream.position; - codeStream.goto_(endifLabel); - codeStream.recordPositionsFrom(position, this.valueIfTrue.sourceEnd); - // Tune codestream stack size - if (valueRequired) { - switch(this.resolvedType.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.decrStackSize(2); - break; - default : - codeStream.decrStackSize(1); - break; - } - } - } - } - if (needFalsePart) { - if (this.falseInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - this.falseInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.falseInitStateIndex); - } - if (falseLabel.forwardReferenceCount() > 0) { - falseLabel.place(); - } - this.valueIfFalse.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.recordExpressionType(this.resolvedType); - } - if (needTruePart) { - // End of if statement - endifLabel.place(); - } - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - this.mergedInitStateIndex); - } - // implicit conversion - if (valueRequired) - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - /** - * Optimized boolean code generation for the conditional operator ?: - */ - @Override - public void generateOptimizedBoolean( - BlockScope currentScope, - CodeStream codeStream, - BranchLabel trueLabel, - BranchLabel falseLabel, - boolean valueRequired) { - - int pc = codeStream.position; - - if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == T_boolean) // constant - || ((this.valueIfTrue.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_boolean - || ((this.valueIfFalse.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) != T_boolean) { // non boolean values - super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - return; - } - Constant cst = this.condition.constant; - Constant condCst = this.condition.optimizedBooleanConstant(); - boolean needTruePart = - !(((cst != Constant.NotAConstant) && (cst.booleanValue() == false)) - || ((condCst != Constant.NotAConstant) && (condCst.booleanValue() == false))); - boolean needFalsePart = - !(((cst != Constant.NotAConstant) && (cst.booleanValue() == true)) - || ((condCst != Constant.NotAConstant) && (condCst.booleanValue() == true))); - - BranchLabel internalFalseLabel, endifLabel = new BranchLabel(codeStream); - - // Generate code for the condition - boolean needConditionValue = (cst == Constant.NotAConstant) && (condCst == Constant.NotAConstant); - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - null, - internalFalseLabel = new BranchLabel(codeStream), - needConditionValue); - - if (this.trueInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - this.trueInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.trueInitStateIndex); - } - // Then code generation - if (needTruePart) { - this.valueIfTrue.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - - if (needFalsePart) { - // Jump over the else part - JumpEndif: { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - cst = this.optimizedIfTrueConstant; - boolean isValueIfTrueOptimizedTrue = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == true; - if (isValueIfTrueOptimizedTrue) break JumpEndif; // no need to jump over, since branched to true already - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - cst = this.optimizedIfTrueConstant; - boolean isValueIfTrueOptimizedFalse = cst != null && cst != Constant.NotAConstant && cst.booleanValue() == false; - if (isValueIfTrueOptimizedFalse) break JumpEndif; // no need to jump over, since branched to false already - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - int position = codeStream.position; - codeStream.goto_(endifLabel); - codeStream.recordPositionsFrom(position, this.valueIfTrue.sourceEnd); - } - // No need to decrement codestream stack size - // since valueIfTrue was already consumed by branch bytecode - } - } - if (needFalsePart) { - internalFalseLabel.place(); - if (this.falseInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.falseInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.falseInitStateIndex); - } - this.valueIfFalse.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - - // End of if statement - endifLabel.place(); - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - // no implicit conversion for boolean values - codeStream.recordPositionsFrom(pc, this.sourceEnd); - } - - @Override - public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - if ((this.implicitConversion & TypeIds.BOXING) != 0) - return FlowInfo.NON_NULL; - return this.nullStatus; - } - - @Override - public Constant optimizedBooleanConstant() { - - return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant; - } - - @Override - public StringBuilder printExpressionNoParenthesis(int indent, StringBuilder output) { - - this.condition.printExpression(indent, output).append(" ? "); //$NON-NLS-1$ - this.valueIfTrue.printExpression(0, output).append(" : "); //$NON-NLS-1$ - return this.valueIfFalse.printExpression(0, output); - } - - @Override - public void addPatternVariables(BlockScope scope, CodeStream codeStream) { - this.condition.addPatternVariables(scope, codeStream); - this.valueIfTrue.addPatternVariables(scope, codeStream); - this.valueIfFalse.addPatternVariables(scope, codeStream); - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - // JLS3 15.25 - LookupEnvironment env = scope.environment(); - final long sourceLevel = scope.compilerOptions().sourceLevel; - boolean use15specifics = sourceLevel >= ClassFileConstants.JDK1_5; - this.use18specifics = sourceLevel >= ClassFileConstants.JDK1_8; - - if (this.use18specifics) { - if (this.expressionContext == ASSIGNMENT_CONTEXT || this.expressionContext == INVOCATION_CONTEXT) { - this.valueIfTrue.setExpressionContext(this.expressionContext); - this.valueIfTrue.setExpectedType(this.expectedType); - this.valueIfFalse.setExpressionContext(this.expressionContext); - this.valueIfFalse.setExpectedType(this.expectedType); - } - } - - if (this.constant != Constant.NotAConstant) { - this.constant = Constant.NotAConstant; - TypeBinding conditionType = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); - this.condition.computeConversion(scope, TypeBinding.BOOLEAN, conditionType); - - if (this.valueIfTrue instanceof CastExpression) this.valueIfTrue.bits |= DisableUnnecessaryCastCheck; // will check later on - this.originalValueIfTrueType = this.valueIfTrue.resolveTypeWithBindings(this.condition.bindingsWhenTrue(), scope); - if (this.valueIfFalse instanceof CastExpression) this.valueIfFalse.bits |= DisableUnnecessaryCastCheck; // will check later on - this.originalValueIfFalseType = this.valueIfFalse.resolveTypeWithBindings(this.condition.bindingsWhenFalse(), scope); - - /* - * - * 6.3.1.4 Conditional Operator a ? b : c - * - * It is a compile-time error if any of the following conditions hold: - • A pattern variable is both (i) introduced by a when true and (ii) introduced by - c when true. - • A pattern variable is both (i) introduced by a when true and (ii) introduced by - c when false. - • A pattern variable is both (i) introduced by a when false and (ii) introduced by - b when true. - • A pattern variable is both (i) introduced by a when false and (ii) introduced by - b when false. - • A pattern variable is both (i) introduced by b when true and (ii) introduced by - c when true. - • A pattern variable is both (i) introduced by b when false and (ii) introduced by - c when false. - */ - scope.reportClashingDeclarations(this.condition.bindingsWhenTrue(), this.valueIfFalse.bindingsWhenTrue()); - scope.reportClashingDeclarations(this.condition.bindingsWhenTrue(), this.valueIfFalse.bindingsWhenFalse()); - scope.reportClashingDeclarations(this.condition.bindingsWhenFalse(), this.valueIfTrue.bindingsWhenTrue()); - scope.reportClashingDeclarations(this.condition.bindingsWhenFalse(), this.valueIfTrue.bindingsWhenFalse()); - scope.reportClashingDeclarations(this.valueIfTrue.bindingsWhenTrue(), this.valueIfFalse.bindingsWhenTrue()); - scope.reportClashingDeclarations(this.valueIfTrue.bindingsWhenFalse(), this.valueIfFalse.bindingsWhenFalse()); - - - if (conditionType == null || this.originalValueIfTrueType == null || this.originalValueIfFalseType == null) - return null; - } else { - if (this.originalValueIfTrueType.kind() == Binding.POLY_TYPE) - this.originalValueIfTrueType = this.valueIfTrue.resolveType(scope); - if (this.originalValueIfFalseType.kind() == Binding.POLY_TYPE) - this.originalValueIfFalseType = this.valueIfFalse.resolveType(scope); - - if (this.originalValueIfTrueType == null || !this.originalValueIfTrueType.isValidBinding()) - return this.resolvedType = null; - if (this.originalValueIfFalseType == null || !this.originalValueIfFalseType.isValidBinding()) - return this.resolvedType = null; - } - // Propagate the constant value from the valueIfTrue and valueIFFalse expression if it is possible - Constant condConstant, trueConstant, falseConstant; - if ((condConstant = this.condition.constant) != Constant.NotAConstant - && (trueConstant = this.valueIfTrue.constant) != Constant.NotAConstant - && (falseConstant = this.valueIfFalse.constant) != Constant.NotAConstant) { - // all terms are constant expression so we can propagate the constant - // from valueIFTrue or valueIfFalse to the receiver constant - this.constant = condConstant.booleanValue() ? trueConstant : falseConstant; - } - if (isPolyExpression()) { - if (this.expectedType == null || !this.expectedType.isProperType(true)) { - // We will be back here in case of a PolyTypeBinding. So, to enable - // further processing, set it back to default. - this.constant = Constant.NotAConstant; - return new PolyTypeBinding(this); - } - return this.resolvedType = computeConversions(scope, this.expectedType) ? this.expectedType : null; - } - - TypeBinding valueIfTrueType = this.originalValueIfTrueType; - TypeBinding valueIfFalseType = this.originalValueIfFalseType; - if (use15specifics && TypeBinding.notEquals(valueIfTrueType, valueIfFalseType)) { - if (valueIfTrueType.isBaseType()) { - if (valueIfFalseType.isBaseType()) { - // bool ? baseType : baseType - if (valueIfTrueType == TypeBinding.NULL) { // bool ? null : 12 --> Integer - valueIfFalseType = env.computeBoxingType(valueIfFalseType); // boxing - } else if (valueIfFalseType == TypeBinding.NULL) { // bool ? 12 : null --> Integer - valueIfTrueType = env.computeBoxingType(valueIfTrueType); // boxing - } - } else { - // bool ? baseType : nonBaseType - TypeBinding unboxedIfFalseType = valueIfFalseType.isBaseType() ? valueIfFalseType : env.computeBoxingType(valueIfFalseType); - if (valueIfTrueType.isNumericType() && unboxedIfFalseType.isNumericType()) { - valueIfFalseType = unboxedIfFalseType; // unboxing - } else if (valueIfTrueType != TypeBinding.NULL) { // bool ? 12 : new Integer(12) --> int - valueIfFalseType = env.computeBoxingType(valueIfFalseType); // unboxing - } - } - } else if (valueIfFalseType.isBaseType()) { - // bool ? nonBaseType : baseType - TypeBinding unboxedIfTrueType = valueIfTrueType.isBaseType() ? valueIfTrueType : env.computeBoxingType(valueIfTrueType); - if (unboxedIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) { - valueIfTrueType = unboxedIfTrueType; // unboxing - } else if (valueIfFalseType != TypeBinding.NULL) { // bool ? new Integer(12) : 12 --> int - valueIfTrueType = env.computeBoxingType(valueIfTrueType); // unboxing - } - } else { - // bool ? nonBaseType : nonBaseType - TypeBinding unboxedIfTrueType = env.computeBoxingType(valueIfTrueType); - TypeBinding unboxedIfFalseType = env.computeBoxingType(valueIfFalseType); - if (unboxedIfTrueType.isNumericType() && unboxedIfFalseType.isNumericType()) { - valueIfTrueType = unboxedIfTrueType; - valueIfFalseType = unboxedIfFalseType; - } - } - } - if (TypeBinding.equalsEquals(valueIfTrueType, valueIfFalseType)) { // harmed the implicit conversion - this.valueIfTrue.computeConversion(scope, valueIfTrueType, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, valueIfFalseType, this.originalValueIfFalseType); - if (TypeBinding.equalsEquals(valueIfTrueType, TypeBinding.BOOLEAN)) { - this.optimizedIfTrueConstant = this.valueIfTrue.optimizedBooleanConstant(); - this.optimizedIfFalseConstant = this.valueIfFalse.optimizedBooleanConstant(); - if (this.optimizedIfTrueConstant != Constant.NotAConstant - && this.optimizedIfFalseConstant != Constant.NotAConstant - && this.optimizedIfTrueConstant.booleanValue() == this.optimizedIfFalseConstant.booleanValue()) { - // a ? true : true / a ? false : false - this.optimizedBooleanConstant = this.optimizedIfTrueConstant; - } else if ((condConstant = this.condition.optimizedBooleanConstant()) != Constant.NotAConstant) { // Propagate the optimized boolean constant if possible - this.optimizedBooleanConstant = condConstant.booleanValue() - ? this.optimizedIfTrueConstant - : this.optimizedIfFalseConstant; - } - } - return this.resolvedType = NullAnnotationMatching.moreDangerousType(valueIfTrueType, valueIfFalseType); - } - // Determine the return type depending on argument types - // Numeric types - if (valueIfTrueType.isNumericType() && valueIfFalseType.isNumericType()) { - // (Short x Byte) or (Byte x Short)" - if ((TypeBinding.equalsEquals(valueIfTrueType, TypeBinding.BYTE) && TypeBinding.equalsEquals(valueIfFalseType, TypeBinding.SHORT)) - || (TypeBinding.equalsEquals(valueIfTrueType, TypeBinding.SHORT) && TypeBinding.equalsEquals(valueIfFalseType, TypeBinding.BYTE))) { - this.valueIfTrue.computeConversion(scope, TypeBinding.SHORT, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, TypeBinding.SHORT, this.originalValueIfFalseType); - return this.resolvedType = TypeBinding.SHORT; - } - // x constant(Int) ---> and reciprocally - if ((TypeBinding.equalsEquals(valueIfTrueType, TypeBinding.BYTE) || TypeBinding.equalsEquals(valueIfTrueType, TypeBinding.SHORT) || TypeBinding.equalsEquals(valueIfTrueType, TypeBinding.CHAR)) - && (TypeBinding.equalsEquals(valueIfFalseType, TypeBinding.INT) - && this.valueIfFalse.isConstantValueOfTypeAssignableToType(valueIfFalseType, valueIfTrueType))) { - this.valueIfTrue.computeConversion(scope, valueIfTrueType, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, valueIfTrueType, this.originalValueIfFalseType); - return this.resolvedType = valueIfTrueType; - } - if ((TypeBinding.equalsEquals(valueIfFalseType, TypeBinding.BYTE) - || TypeBinding.equalsEquals(valueIfFalseType, TypeBinding.SHORT) - || TypeBinding.equalsEquals(valueIfFalseType, TypeBinding.CHAR)) - && (TypeBinding.equalsEquals(valueIfTrueType, TypeBinding.INT) - && this.valueIfTrue.isConstantValueOfTypeAssignableToType(valueIfTrueType, valueIfFalseType))) { - this.valueIfTrue.computeConversion(scope, valueIfFalseType, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, valueIfFalseType, this.originalValueIfFalseType); - return this.resolvedType = valueIfFalseType; - } - // Manual binary numeric promotion - // int - if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_int) - && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_int)) { - this.valueIfTrue.computeConversion(scope, TypeBinding.INT, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, TypeBinding.INT, this.originalValueIfFalseType); - return this.resolvedType = TypeBinding.INT; - } - // long - if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_long) - && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_long)) { - this.valueIfTrue.computeConversion(scope, TypeBinding.LONG, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, TypeBinding.LONG, this.originalValueIfFalseType); - return this.resolvedType = TypeBinding.LONG; - } - // float - if (BaseTypeBinding.isNarrowing(valueIfTrueType.id, T_float) - && BaseTypeBinding.isNarrowing(valueIfFalseType.id, T_float)) { - this.valueIfTrue.computeConversion(scope, TypeBinding.FLOAT, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, TypeBinding.FLOAT, this.originalValueIfFalseType); - return this.resolvedType = TypeBinding.FLOAT; - } - // double - this.valueIfTrue.computeConversion(scope, TypeBinding.DOUBLE, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, TypeBinding.DOUBLE, this.originalValueIfFalseType); - return this.resolvedType = TypeBinding.DOUBLE; - } - // Type references (null null is already tested) - if (valueIfTrueType.isBaseType() && valueIfTrueType != TypeBinding.NULL) { - if (use15specifics) { - valueIfTrueType = env.computeBoxingType(valueIfTrueType); - } else { - scope.problemReporter().conditionalArgumentsIncompatibleTypes(this, valueIfTrueType, valueIfFalseType); - return null; - } - } - if (valueIfFalseType.isBaseType() && valueIfFalseType != TypeBinding.NULL) { - if (use15specifics) { - valueIfFalseType = env.computeBoxingType(valueIfFalseType); - } else { - scope.problemReporter().conditionalArgumentsIncompatibleTypes(this, valueIfTrueType, valueIfFalseType); - return null; - } - } - if (use15specifics) { - // >= 1.5 : LUB(operand types) must exist - TypeBinding commonType = null; - if (valueIfTrueType == TypeBinding.NULL) { - commonType = valueIfFalseType.withoutToplevelNullAnnotation(); // null on other branch invalidates any @NonNull - } else if (valueIfFalseType == TypeBinding.NULL) { - commonType = valueIfTrueType.withoutToplevelNullAnnotation(); // null on other branch invalidates any @NonNull - } else { - commonType = scope.lowerUpperBound(new TypeBinding[] { valueIfTrueType, valueIfFalseType }); - } - if (commonType != null) { - this.valueIfTrue.computeConversion(scope, commonType, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, commonType, this.originalValueIfFalseType); - return this.resolvedType = commonType.capture(scope, this.sourceStart, this.sourceEnd); - } - } else { - // < 1.5 : one operand must be convertible to the other - if (valueIfFalseType.isCompatibleWith(valueIfTrueType)) { - this.valueIfTrue.computeConversion(scope, valueIfTrueType, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, valueIfTrueType, this.originalValueIfFalseType); - return this.resolvedType = valueIfTrueType; - } else if (valueIfTrueType.isCompatibleWith(valueIfFalseType)) { - this.valueIfTrue.computeConversion(scope, valueIfFalseType, this.originalValueIfTrueType); - this.valueIfFalse.computeConversion(scope, valueIfFalseType, this.originalValueIfFalseType); - return this.resolvedType = valueIfFalseType; - } - } - scope.problemReporter().conditionalArgumentsIncompatibleTypes( - this, - valueIfTrueType, - valueIfFalseType); - return null; - } - - protected boolean computeConversions(BlockScope scope, TypeBinding targetType) { - boolean ok = true; - if (this.originalValueIfTrueType != null && this.originalValueIfTrueType.isValidBinding()) { - if (this.valueIfTrue.isConstantValueOfTypeAssignableToType(this.originalValueIfTrueType, targetType) - || this.originalValueIfTrueType.isCompatibleWith(targetType)) { - - this.valueIfTrue.computeConversion(scope, targetType, this.originalValueIfTrueType); - if (this.originalValueIfTrueType.needsUncheckedConversion(targetType)) { - scope.problemReporter().unsafeTypeConversion(this.valueIfTrue, this.originalValueIfTrueType, targetType); - } - if (this.valueIfTrue instanceof CastExpression - && (this.valueIfTrue.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { - CastExpression.checkNeedForAssignedCast(scope, targetType, (CastExpression) this.valueIfTrue); - } - } else if (isBoxingCompatible(this.originalValueIfTrueType, targetType, this.valueIfTrue, scope)) { - this.valueIfTrue.computeConversion(scope, targetType, this.originalValueIfTrueType); - if (this.valueIfTrue instanceof CastExpression - && (this.valueIfTrue.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { - CastExpression.checkNeedForAssignedCast(scope, targetType, (CastExpression) this.valueIfTrue); - } - } else { - scope.problemReporter().typeMismatchError(this.originalValueIfTrueType, targetType, this.valueIfTrue, null); - ok = false; - } - } - if (this.originalValueIfFalseType != null && this.originalValueIfFalseType.isValidBinding()) { - if (this.valueIfFalse.isConstantValueOfTypeAssignableToType(this.originalValueIfFalseType, targetType) - || this.originalValueIfFalseType.isCompatibleWith(targetType)) { - - this.valueIfFalse.computeConversion(scope, targetType, this.originalValueIfFalseType); - if (this.originalValueIfFalseType.needsUncheckedConversion(targetType)) { - scope.problemReporter().unsafeTypeConversion(this.valueIfFalse, this.originalValueIfFalseType, targetType); - } - if (this.valueIfFalse instanceof CastExpression - && (this.valueIfFalse.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { - CastExpression.checkNeedForAssignedCast(scope, targetType, (CastExpression) this.valueIfFalse); - } - } else if (isBoxingCompatible(this.originalValueIfFalseType, targetType, this.valueIfFalse, scope)) { - this.valueIfFalse.computeConversion(scope, targetType, this.originalValueIfFalseType); - if (this.valueIfFalse instanceof CastExpression - && (this.valueIfFalse.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { - CastExpression.checkNeedForAssignedCast(scope, targetType, (CastExpression) this.valueIfFalse); - } - } else { - scope.problemReporter().typeMismatchError(this.originalValueIfFalseType, targetType, this.valueIfFalse, null); - ok = false; - } - } - return ok; - } - - @Override - public void setExpectedType(TypeBinding expectedType) { - this.expectedType = expectedType; - } - - @Override - public void setExpressionContext(ExpressionContext context) { - this.expressionContext = context; - } - - @Override - public ExpressionContext getExpressionContext() { - return this.expressionContext; - } - - @Override - public Expression[] getPolyExpressions() { - Expression [] truePolys = this.valueIfTrue.getPolyExpressions(); - Expression [] falsePolys = this.valueIfFalse.getPolyExpressions(); - if (truePolys.length == 0) - return falsePolys; - if (falsePolys.length == 0) - return truePolys; - Expression [] allPolys = new Expression [truePolys.length + falsePolys.length]; - System.arraycopy(truePolys, 0, allPolys, 0, truePolys.length); - System.arraycopy(falsePolys, 0, allPolys, truePolys.length, falsePolys.length); - return allPolys; - } - - @Override - public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) { - return this.valueIfTrue.isPertinentToApplicability(targetType, method) - && this.valueIfFalse.isPertinentToApplicability(targetType, method); - } - - @Override - public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) { - return this.valueIfTrue.isPotentiallyCompatibleWith(targetType, scope) - && this.valueIfFalse.isPotentiallyCompatibleWith(targetType, scope); - } - - @Override - public boolean isFunctionalType() { - return this.valueIfTrue.isFunctionalType() || this.valueIfFalse.isFunctionalType(); // Even if only one arm is functional type, this will require a functional interface target - } - - @Override - public boolean isPolyExpression() throws UnsupportedOperationException { - - if (!this.use18specifics) - return false; - - if (this.isPolyExpression) - return true; - - if (this.expressionContext != ASSIGNMENT_CONTEXT && this.expressionContext != INVOCATION_CONTEXT) - return false; - - if (this.originalValueIfTrueType == null || this.originalValueIfFalseType == null) // resolution error. - return false; - - if (this.valueIfTrue.isPolyExpression() || this.valueIfFalse.isPolyExpression()) - return true; - - // "... unless both operands produce primitives (or boxed primitives)": - if (this.originalValueIfTrueType.isBaseType() || (this.originalValueIfTrueType.id >= TypeIds.T_JavaLangByte && this.originalValueIfTrueType.id <= TypeIds.T_JavaLangBoolean)) { - if (this.originalValueIfFalseType.isBaseType() || (this.originalValueIfFalseType.id >= TypeIds.T_JavaLangByte && this.originalValueIfFalseType.id <= TypeIds.T_JavaLangBoolean)) - return false; - } - - // clause around generic method's return type prior to instantiation needs double check. - return this.isPolyExpression = true; - } - - @Override - public boolean isCompatibleWith(TypeBinding left, Scope scope) { - return isPolyExpression() ? this.valueIfTrue.isCompatibleWith(left, scope) && this.valueIfFalse.isCompatibleWith(left, scope) : - super.isCompatibleWith(left, scope); - } - - @Override - public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope scope) { - // Note: compatibility check may have failed in just one arm and we may have reached here. - return isPolyExpression() ? (this.valueIfTrue.isCompatibleWith(targetType, scope) || - this.valueIfTrue.isBoxingCompatibleWith(targetType, scope)) && - (this.valueIfFalse.isCompatibleWith(targetType, scope) || - this.valueIfFalse.isBoxingCompatibleWith(targetType, scope)) : - super.isBoxingCompatibleWith(targetType, scope); - } - - @Override - public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) { - if (super.sIsMoreSpecific(s, t, scope)) - return true; - return isPolyExpression() ? - this.valueIfTrue.sIsMoreSpecific(s, t, scope) && this.valueIfFalse.sIsMoreSpecific(s, t, scope): - false; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.condition.traverse(visitor, scope); - this.valueIfTrue.traverse(visitor, scope); - this.valueIfFalse.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } -} - diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java deleted file mode 100644 index 9fdb324..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ConstructorDeclaration.java +++ /dev/null @@ -1,721 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * 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 - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 361407 - Resource leak warning when resource is assigned to a field outside of constructor - * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK - * bug 383690 - [compiler] location of error re uninitialized final field should be aligned - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 400421 - [compiler] Null analysis for fields does not take @com.google.inject.Inject into account - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables - * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 415399 - [1.8][compiler] Type annotations on constructor results dropped by the code generator - * Ulrich Grave - Contributions for - * bug 386692 - Missing "unused" warning on "autowired" fields - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jdt.core.compiler.*; -import org.eclipse.jdt.internal.compiler.*; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.parser.*; -import org.eclipse.jdt.internal.compiler.problem.*; -import org.eclipse.jdt.internal.compiler.util.Util; - -@SuppressWarnings({"rawtypes", "unchecked"}) -public class ConstructorDeclaration extends AbstractMethodDeclaration { - - public ExplicitConstructorCall constructorCall; - - public TypeParameter[] typeParameters; - -public ConstructorDeclaration(CompilationResult compilationResult){ - super(compilationResult); -} -/** - * The flowInfo corresponds to non-static field initialization infos. It may be unreachable (155423), but still the explicit constructor call must be - * 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) - return; - - int nonStaticFieldInfoReachMode = flowInfo.reachMode(); - flowInfo.setReachMode(initialReachMode); - - checkUnused: { - MethodBinding constructorBinding; - if ((constructorBinding = this.binding) == null) break checkUnused; - if ((this.bits & ASTNode.IsDefaultConstructor) != 0) break checkUnused; - if (constructorBinding.isUsed()) break checkUnused; - if (constructorBinding.isPrivate()) { - if ((this.binding.declaringClass.tagBits & TagBits.HasNonPrivateConstructor) == 0) - break checkUnused; // tolerate as known pattern to block instantiation - } else if (!constructorBinding.isOrEnclosedByPrivateType()) { - break checkUnused; - } - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=270446, When the AST built is an abridged version - // we don't have all tree nodes we would otherwise expect. (see ASTParser.setFocalPosition) - if (this.constructorCall == null) - break checkUnused; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=264991, Don't complain about this - // constructor being unused if the base class doesn't have a no-arg constructor. - // See that a seemingly unused constructor that chains to another constructor with a - // this(...) can be flagged as being unused without hesitation. - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=265142 - if (this.constructorCall.accessMode != ExplicitConstructorCall.This) { - ReferenceBinding superClass = constructorBinding.declaringClass.superclass(); - if (superClass == null) - break checkUnused; - // see if there is a no-arg super constructor - MethodBinding methodBinding = superClass.getExactConstructor(Binding.NO_PARAMETERS); - if (methodBinding == null) - break checkUnused; - if (!methodBinding.canBeSeenBy(SuperReference.implicitSuperConstructorCall(), this.scope)) - break checkUnused; - ReferenceBinding declaringClass = constructorBinding.declaringClass; - if (constructorBinding.isPublic() && constructorBinding.parameters.length == 0 && - declaringClass.isStatic() && - declaringClass.findSuperTypeOriginatingFrom(TypeIds.T_JavaIoExternalizable, false) != null) - break checkUnused; - // otherwise default super constructor exists, so go ahead and complain unused. - } - // complain unused - if ((this.bits & ASTNode.IsImplicit) == 0) - this.scope.problemReporter().unusedPrivateConstructor(this); - } - - // check constructor recursion, once all constructor got resolved - if (isRecursive(null /*lazy initialized visited list*/)) { - this.scope.problemReporter().recursiveConstructorInvocation(this.constructorCall); - } - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=385780 - if (this.typeParameters != null && - !this.scope.referenceCompilationUnit().compilationResult.hasSyntaxError) { - for (int i = 0, length = this.typeParameters.length; i < length; ++i) { - TypeParameter typeParameter = this.typeParameters[i]; - if ((typeParameter.binding.modifiers & ExtraCompilerModifiers.AccLocallyUsed) == 0) { - this.scope.problemReporter().unusedTypeParameter(typeParameter); - } - } - } - try { - ExceptionHandlingFlowContext constructorContext = - new ExceptionHandlingFlowContext( - initializerFlowContext.parent, - this, - this.binding.thrownExceptions, - initializerFlowContext, - this.scope, - FlowInfo.DEAD_END); - initializerFlowContext.checkInitializerExceptions( - this.scope, - constructorContext, - flowInfo); - - // anonymous constructor can gain extra thrown exceptions from unhandled ones - if (this.binding.declaringClass.isAnonymousType()) { - List computedExceptions = constructorContext.extendedExceptions; - if (computedExceptions != null){ - int size; - if ((size = computedExceptions.size()) > 0){ - ReferenceBinding[] actuallyThrownExceptions; - computedExceptions.toArray(actuallyThrownExceptions = new ReferenceBinding[size]); - this.binding.thrownExceptions = actuallyThrownExceptions; - } - } - } - - // nullity, owning and mark as assigned - analyseArguments(classScope.environment(), flowInfo, initializerFlowContext, this.arguments, this.binding); - - // propagate to constructor call - if (this.constructorCall != null) { - // if calling 'this(...)', then flag all non-static fields as definitely - // set since they are supposed to be set inside other local constructor - if (this.constructorCall.accessMode == ExplicitConstructorCall.This) { - FieldBinding[] fields = this.binding.declaringClass.fields(); - for (int i = 0, count = fields.length; i < count; i++) { - FieldBinding field; - if (!(field = fields[i]).isStatic()) { - flowInfo.markAsDefinitelyAssigned(field); - } - } - } - flowInfo = this.constructorCall.analyseCode(this.scope, constructorContext, flowInfo); - } - - // reuse the reachMode from non static field info - flowInfo.setReachMode(nonStaticFieldInfoReachMode); - - // propagate to statements - if (this.statements != null) { - CompilerOptions compilerOptions = this.scope.compilerOptions(); - boolean enableSyntacticNullAnalysisForFields = compilerOptions.enableSyntacticNullAnalysisForFields; - 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, true)) < Statement.COMPLAINED_UNREACHABLE) { - flowInfo = stat.analyseCode(this.scope, constructorContext, flowInfo); - } - if (enableSyntacticNullAnalysisForFields) { - constructorContext.expireNullCheckedFieldInfo(); - } - if (compilerOptions.analyseResourceLeaks) { - FakedTrackingVariable.cleanUpUnassigned(this.scope, stat, flowInfo, false); - } - } - } - // check for missing returning path - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - this.bits |= ASTNode.NeedFreeReturn; - } - - // reuse the initial reach mode for diagnosing missing blank finals - // no, we should use the updated reach mode for diagnosing uninitialized blank finals. - // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=235781 - // flowInfo.setReachMode(initialReachMode); - - // check missing blank final field initializations (plus @NonNull) - if ((this.constructorCall != null) - && (this.constructorCall.accessMode != ExplicitConstructorCall.This)) { - flowInfo = flowInfo.mergedWith(constructorContext.initsOnReturn); - FieldBinding[] fields = this.binding.declaringClass.fields(); - checkAndGenerateFieldAssignment(initializerFlowContext, flowInfo, fields); - doFieldReachAnalysis(flowInfo, fields); - } - // check unreachable catch blocks - constructorContext.complainIfUnusedExceptionHandlers(this); - // check unused parameters - this.scope.checkUnusedParameters(this.binding); - this.scope.checkUnclosedCloseables(flowInfo, null, null/*don't report against a specific location*/, null); - } catch (AbortMethod e) { - this.ignoreFurtherInvestigation = true; - } -} -protected void doFieldReachAnalysis(FlowInfo flowInfo, FieldBinding[] fields) { - for (int i = 0, count = fields.length; i < count; i++) { - FieldBinding field = fields[i]; - if (!field.isStatic() && !flowInfo.isDefinitelyAssigned(field)) { - if (field.isFinal()) { - this.scope.problemReporter().uninitializedBlankFinalField( - field, - ((this.bits & ASTNode.IsDefaultConstructor) != 0) - ? (ASTNode) this.scope.referenceType().declarationOf(field.original()) - : this); - } else if (field.isNonNull() || field.type.isFreeTypeVariable()) { - FieldDeclaration fieldDecl = this.scope.referenceType().declarationOf(field.original()); - if (!isValueProvidedUsingAnnotation(fieldDecl)) - this.scope.problemReporter().uninitializedNonNullField( - field, - ((this.bits & ASTNode.IsDefaultConstructor) != 0) - ? (ASTNode) fieldDecl - : this); - } - } - } -} - -protected void checkAndGenerateFieldAssignment(FlowContext flowContext, FlowInfo flowInfo, FieldBinding[] fields) { - return; -} -boolean isValueProvidedUsingAnnotation(FieldDeclaration fieldDecl) { - // a member field annotated with @Inject is considered to be initialized by the injector - if (fieldDecl.annotations != null) { - int length = fieldDecl.annotations.length; - for (int i = 0; i < length; i++) { - Annotation annotation = fieldDecl.annotations[i]; - if (annotation.resolvedType.id == TypeIds.T_JavaxInjectInject) { - return true; // no concept of "optional" - } else if (annotation.resolvedType.id == TypeIds.T_ComGoogleInjectInject) { - MemberValuePair[] memberValuePairs = annotation.memberValuePairs(); - if (memberValuePairs == Annotation.NoValuePairs) - return true; - for (int j = 0; j < memberValuePairs.length; j++) { - // if "optional=false" is specified, don't rely on initialization by the injector: - if (CharOperation.equals(memberValuePairs[j].name, TypeConstants.OPTIONAL)) - return memberValuePairs[j].value instanceof FalseLiteral; - } - } else if (annotation.resolvedType.id == TypeIds.T_OrgSpringframeworkBeansFactoryAnnotationAutowired) { - MemberValuePair[] memberValuePairs = annotation.memberValuePairs(); - if (memberValuePairs == Annotation.NoValuePairs) - return true; - for (int j = 0; j < memberValuePairs.length; j++) { - if (CharOperation.equals(memberValuePairs[j].name, TypeConstants.REQUIRED)) - return memberValuePairs[j].value instanceof TrueLiteral; - } - } - } - } - return false; -} - -/** - * Bytecode generation for a constructor - * - * @param classScope org.eclipse.jdt.internal.compiler.lookup.ClassScope - * @param classFile org.eclipse.jdt.internal.compiler.codegen.ClassFile - */ -@Override -public void generateCode(ClassScope classScope, ClassFile classFile) { - int problemResetPC = 0; - if (this.ignoreFurtherInvestigation) { - if (this.binding == null) - return; // Handle methods with invalid signature or duplicates - int problemsLength; - CategorizedProblem[] problems = - this.scope.referenceCompilationUnit().compilationResult.getProblems(); - CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; - System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); - classFile.addProblemConstructor(this, this.binding, problemsCopy); - return; - } - boolean restart = false; - boolean abort = false; - CompilationResult unitResult = null; - int problemCount = 0; - if (classScope != null) { - TypeDeclaration referenceContext = classScope.referenceContext; - if (referenceContext != null) { - unitResult = referenceContext.compilationResult(); - problemCount = unitResult.problemCount; - } - } - do { - try { - problemResetPC = classFile.contentsOffset; - internalGenerateCode(classScope, classFile); - restart = false; - } catch (AbortMethod e) { - if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { - // a branch target required a goto_w, restart code gen in wide mode. - classFile.contentsOffset = problemResetPC; - classFile.methodCount--; - classFile.codeStream.resetInWideMode(); // request wide mode - // reset the problem count to prevent reporting the same warning twice - if (unitResult != null) { - unitResult.problemCount = problemCount; - } - restart = true; - } else if (e.compilationResult == CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE) { - classFile.contentsOffset = problemResetPC; - classFile.methodCount--; - classFile.codeStream.resetForCodeGenUnusedLocals(); - // reset the problem count to prevent reporting the same warning twice - if (unitResult != null) { - unitResult.problemCount = problemCount; - } - restart = true; - } else { - restart = false; - abort = true; - } - } - } while (restart); - if (abort) { - int problemsLength; - CategorizedProblem[] problems = - this.scope.referenceCompilationUnit().compilationResult.getAllProblems(); - CategorizedProblem[] problemsCopy = new CategorizedProblem[problemsLength = problems.length]; - System.arraycopy(problems, 0, problemsCopy, 0, problemsLength); - classFile.addProblemConstructor(this, this.binding, problemsCopy, problemResetPC); - } -} - -public void generateSyntheticFieldInitializationsIfNecessary(MethodScope methodScope, CodeStream codeStream, ReferenceBinding declaringClass) { - if (!declaringClass.isNestedType()) return; - - NestedTypeBinding nestedType = (NestedTypeBinding) declaringClass; - - SyntheticArgumentBinding[] syntheticArgs = nestedType.syntheticEnclosingInstances(); - if (syntheticArgs != null) { - for (int i = 0, max = syntheticArgs.length; i < max; i++) { - SyntheticArgumentBinding syntheticArg; - if ((syntheticArg = syntheticArgs[i]).matchingField != null) { - codeStream.aload_0(); - codeStream.load(syntheticArg); - codeStream.fieldAccess(Opcodes.OPC_putfield, syntheticArg.matchingField, null /* default declaringClass */); - } - } - } - syntheticArgs = nestedType.syntheticOuterLocalVariables(); - if (syntheticArgs != null) { - for (int i = 0, max = syntheticArgs.length; i < max; i++) { - SyntheticArgumentBinding syntheticArg; - if ((syntheticArg = syntheticArgs[i]).matchingField != null) { - codeStream.aload_0(); - codeStream.load(syntheticArg); - codeStream.fieldAccess(Opcodes.OPC_putfield, syntheticArg.matchingField, null /* default declaringClass */); - } - } - } -} - -private void internalGenerateCode(ClassScope classScope, ClassFile classFile) { - classFile.generateMethodInfoHeader(this.binding); - int methodAttributeOffset = classFile.contentsOffset; - int attributeNumber = classFile.generateMethodInfoAttributes(this.binding); - if ((!this.binding.isNative()) && (!this.binding.isAbstract())) { - - TypeDeclaration declaringType = classScope.referenceContext; - int codeAttributeOffset = classFile.contentsOffset; - classFile.generateCodeAttributeHeader(); - CodeStream codeStream = classFile.codeStream; - codeStream.reset(this, classFile); - - // initialize local positions - including initializer scope. - ReferenceBinding declaringClass = this.binding.declaringClass; - - int enumOffset = declaringClass.isEnum() ? 2 : 0; // String name, int ordinal - int argSlotSize = 1 + enumOffset; // this==aload0 - - if (declaringClass.isNestedType()){ - this.scope.extraSyntheticArguments = declaringClass.syntheticOuterLocalVariables(); - this.scope.computeLocalVariablePositions(// consider synthetic arguments if any - declaringClass.getEnclosingInstancesSlotSize() + 1 + enumOffset, - codeStream); - argSlotSize += declaringClass.getEnclosingInstancesSlotSize(); - argSlotSize += declaringClass.getOuterLocalVariablesSlotSize(); - } else { - this.scope.computeLocalVariablePositions(1 + enumOffset, codeStream); - } - - if (this.arguments != null) { - for (int i = 0, max = this.arguments.length; i < max; i++) { - // arguments initialization for local variable debug attributes - LocalVariableBinding argBinding; - codeStream.addVisibleLocalVariable(argBinding = this.arguments[i].binding); - argBinding.recordInitializationStartPC(0); - switch(argBinding.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - argSlotSize += 2; - break; - default : - argSlotSize++; - break; - } - } - } - - MethodScope initializerScope = declaringType.initializerScope; - initializerScope.computeLocalVariablePositions(argSlotSize, codeStream); // offset by the argument size (since not linked to method scope) - - codeStream.pushPatternAccessTrapScope(this.scope); - boolean needFieldInitializations = this.constructorCall == null || this.constructorCall.accessMode != ExplicitConstructorCall.This; - - // post 1.4 target level, synthetic initializations occur prior to explicit constructor call - boolean preInitSyntheticFields = this.scope.compilerOptions().targetJDK >= ClassFileConstants.JDK1_4; - - if (needFieldInitializations && preInitSyntheticFields){ - generateSyntheticFieldInitializationsIfNecessary(this.scope, codeStream, declaringClass); - codeStream.recordPositionsFrom(0, this.bodyStart > 0 ? this.bodyStart : this.sourceStart); - } - // generate constructor call - if (this.constructorCall != null) { - this.constructorCall.generateCode(this.scope, codeStream); - } - // generate field initialization - only if not invoking another constructor call of the same class - if (needFieldInitializations) { - if (!preInitSyntheticFields){ - generateSyntheticFieldInitializationsIfNecessary(this.scope, codeStream, declaringClass); - } - // generate user field initialization - if (declaringType.fields != null) { - for (int i = 0, max = declaringType.fields.length; i < max; i++) { - FieldDeclaration fieldDecl; - if (!(fieldDecl = declaringType.fields[i]).isStatic()) { - fieldDecl.generateCode(initializerScope, codeStream); - } - } - } - } - // generate statements - if (this.statements != null) { - for (int i = 0, max = this.statements.length; i < max; i++) { - this.statements[i].generateCode(this.scope, codeStream); - } - } - // if a problem got reported during code gen, then trigger problem method creation - if (this.ignoreFurtherInvestigation) { - throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null); - } - if ((this.bits & ASTNode.NeedFreeReturn) != 0) { - codeStream.return_(); - } - // See https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1796#issuecomment-1933458054 - codeStream.exitUserScope(this.scope, lvb -> !lvb.isParameter()); - codeStream.handleRecordAccessorExceptions(this.scope); - // local variable attributes - codeStream.exitUserScope(this.scope); - codeStream.recordPositionsFrom(0, this.bodyEnd > 0 ? this.bodyEnd : this.sourceStart); - try { - classFile.completeCodeAttribute(codeAttributeOffset, this.scope); - } catch(NegativeArraySizeException e) { - throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null); - } - attributeNumber++; - if ((codeStream instanceof StackMapFrameCodeStream) - && needFieldInitializations - && declaringType.fields != null) { - ((StackMapFrameCodeStream) codeStream).resetSecretLocals(); - } - } - classFile.completeMethodInfo(this.binding, methodAttributeOffset, attributeNumber); -} - -@Override -protected AnnotationBinding[][] getPropagatedRecordComponentAnnotations() { - - if ((this.bits & (ASTNode.IsCanonicalConstructor | ASTNode.IsImplicit)) == 0) - return null; - if (this.binding == null) - return null; - AnnotationBinding[][] paramAnnotations = null; - ReferenceBinding declaringClass = this.binding.declaringClass; - if (declaringClass instanceof SourceTypeBinding) { - assert declaringClass.isRecord(); - RecordComponentBinding[] rcbs = ((SourceTypeBinding) declaringClass).components(); - for (int i = 0, length = rcbs.length; i < length; i++) { - RecordComponentBinding rcb = rcbs[i]; - RecordComponent recordComponent = rcb.sourceRecordComponent(); - long rcMask = TagBits.AnnotationForParameter | TagBits.AnnotationForTypeUse; - List relevantAnnotationBindings = new ArrayList<>(); - Annotation[] relevantAnnotations = ASTNode.getRelevantAnnotations(recordComponent.annotations, rcMask, relevantAnnotationBindings); - if (relevantAnnotations != null) { - if (paramAnnotations == null) { - paramAnnotations = new AnnotationBinding[length][]; - for (int j=0; j= 0) return index == 0; // only blame if directly part of the cycle - } - visited.add(this); - - return targetConstructor.isRecursive(visited); -} - -@Override -public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { - //fill up the constructor body with its statements - if (((this.bits & ASTNode.IsDefaultConstructor) != 0) && this.constructorCall == null){ - this.constructorCall = SuperReference.implicitSuperConstructorCall(); - this.constructorCall.sourceStart = this.sourceStart; - this.constructorCall.sourceEnd = this.sourceEnd; - return; - } - parser.parse(this, unit, false); - this.containsSwitchWithTry = parser.switchWithTry; -} - -@Override -public StringBuilder printBody(int indent, StringBuilder output) { - output.append(" {"); //$NON-NLS-1$ - if (this.constructorCall != null) { - output.append('\n'); - this.constructorCall.printStatement(indent, output); - } - if (this.statements != null) { - for (int i = 0; i < this.statements.length; i++) { - output.append('\n'); - this.statements[i].printStatement(indent, output); - } - } - output.append('\n'); - printIndent(indent == 0 ? 0 : indent - 1, output).append('}'); - return output; -} - -@Override -public void resolveJavadoc() { - if (this.binding == null || this.javadoc != null) { - super.resolveJavadoc(); - } else if ((this.bits & ASTNode.IsDefaultConstructor) == 0 ) { - if((this.bits & ASTNode.IsImplicit) != 0 ) return; - if (this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) { - // Set javadoc visibility - int javadocVisibility = this.binding.modifiers & ExtraCompilerModifiers.AccVisibilityMASK; - ClassScope classScope = this.scope.classScope(); - ProblemReporter reporter = this.scope.problemReporter(); - int severity = reporter.computeSeverity(IProblem.JavadocMissing); - if (severity != ProblemSeverities.Ignore) { - if (classScope != null) { - javadocVisibility = Util.computeOuterMostVisibility(classScope.referenceType(), javadocVisibility); - } - int javadocModifiers = (this.binding.modifiers & ~ExtraCompilerModifiers.AccVisibilityMASK) | javadocVisibility; - reporter.javadocMissing(this.sourceStart, this.sourceEnd, severity, javadocModifiers); - } - } - } -} - -/* - * Type checking for constructor, just another method, except for special check - * for recursive constructor invocations. - */ -@Override -public void resolveStatements() { - SourceTypeBinding sourceType = this.scope.enclosingSourceType(); - if (!CharOperation.equals(sourceType.sourceName, this.selector)){ - this.scope.problemReporter().missingReturnType(this); - } - // typeParameters are already resolved from Scope#connectTypeVariables() - if (this.binding != null && !this.binding.isPrivate()) { - sourceType.tagBits |= TagBits.HasNonPrivateConstructor; - } - // if null ==> an error has occurs at parsing time .... - if (this.constructorCall != null) { - if (sourceType.id == TypeIds.T_JavaLangObject - && this.constructorCall.accessMode != ExplicitConstructorCall.This) { - // cannot use super() in java.lang.Object - if (this.constructorCall.accessMode == ExplicitConstructorCall.Super) { - this.scope.problemReporter().cannotUseSuperInJavaLangObject(this.constructorCall); - } - this.constructorCall = null; - } else if (sourceType.isRecord() && - !(this instanceof CompactConstructorDeclaration) && // compact constr should be marked as canonical? - (this.binding != null && !this.binding.isCanonicalConstructor()) && - this.constructorCall.accessMode != ExplicitConstructorCall.This) { - this.scope.problemReporter().recordMissingExplicitConstructorCallInNonCanonicalConstructor(this); - this.constructorCall = null; - } - else { - this.constructorCall.resolve(this.scope); - } - } - if ((this.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) { - this.scope.problemReporter().methodNeedBody(this); - } - super.resolveStatements(); -} - -@Override -public void traverse(ASTVisitor visitor, ClassScope classScope) { - if (visitor.visit(this, classScope)) { - if (this.javadoc != null) { - this.javadoc.traverse(visitor, this.scope); - } - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, this.scope); - } - if (this.typeParameters != null) { - int typeParametersLength = this.typeParameters.length; - for (int i = 0; i < typeParametersLength; i++) { - this.typeParameters[i].traverse(visitor, this.scope); - } - } - if (this.arguments != null) { - int argumentLength = this.arguments.length; - for (int i = 0; i < argumentLength; i++) - this.arguments[i].traverse(visitor, this.scope); - } - if (this.thrownExceptions != null) { - int thrownExceptionsLength = this.thrownExceptions.length; - for (int i = 0; i < thrownExceptionsLength; i++) - this.thrownExceptions[i].traverse(visitor, this.scope); - } - if (this.constructorCall != null) - this.constructorCall.traverse(visitor, this.scope); - if (this.statements != null) { - int statementsLength = this.statements.length; - for (int i = 0; i < statementsLength; i++) - this.statements[i].traverse(visitor, this.scope); - } - } - visitor.endVisit(this, classScope); -} -@Override -public TypeParameter[] typeParameters() { - return this.typeParameters; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java deleted file mode 100644 index b865829..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ContainerAnnotation.java +++ /dev/null @@ -1,92 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013 Jesper S Moller and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Jesper S Moller - initial API and implementation - ********************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; - -public class ContainerAnnotation extends SingleMemberAnnotation { - - private Annotation [] containees; - private ArrayInitializer memberValues; - - public ContainerAnnotation(Annotation repeatingAnnotation, ReferenceBinding containerAnnotationType, BlockScope scope) { - - char [][] containerTypeName = containerAnnotationType.compoundName; - if (containerTypeName.length == 1) { - this.type = new SingleTypeReference(containerTypeName[0], 0); - } else { - this.type = new QualifiedTypeReference(containerTypeName, new long [containerTypeName.length]); - } - - this.sourceStart = repeatingAnnotation.sourceStart; - this.sourceEnd = repeatingAnnotation.sourceEnd; - - this.resolvedType = containerAnnotationType; - this.recipient = repeatingAnnotation.recipient; - this.containees = new Annotation[0]; - this.memberValue = this.memberValues = new ArrayInitializer(); - addContainee(repeatingAnnotation); - } - - public void addContainee(Annotation repeatingAnnotation) { - final int length = this.containees.length; - System.arraycopy(this.containees, 0, this.containees = new Annotation[length + 1], 0, length); - this.containees[length] = repeatingAnnotation; - this.memberValues.expressions = this.containees; - repeatingAnnotation.setPersistibleAnnotation(length == 0 ? this : null); - } - - // Resolve the compiler synthesized container annotation. - @Override - public TypeBinding resolveType(BlockScope scope) { - - if (this.compilerAnnotation != null) - return this.resolvedType; - - this.constant = Constant.NotAConstant; - - ReferenceBinding containerAnnotationType = (ReferenceBinding) this.resolvedType; - if (!containerAnnotationType.isValidBinding()) - containerAnnotationType = (ReferenceBinding) containerAnnotationType.closestMatch(); - Annotation repeatingAnnotation = this.containees[0]; - ReferenceBinding repeatingAnnotationType = (ReferenceBinding) repeatingAnnotation.resolvedType; - if (!repeatingAnnotationType.isDeprecated() && isTypeUseDeprecated(containerAnnotationType, scope)) { - scope.problemReporter().deprecatedType(containerAnnotationType, repeatingAnnotation); - } - checkContainerAnnotationType(repeatingAnnotation, scope, containerAnnotationType, repeatingAnnotationType, true); // true => repeated *use* site error reporting requested. - this.resolvedType = containerAnnotationType = repeatingAnnotationType.containerAnnotationType(); - if (!this.resolvedType.isValidBinding()) - return this.resolvedType; - - // OK, the declaration site of the repeating annotation type as well as the use site where the annotations actually repeat pass muster. - MethodBinding[] methods = containerAnnotationType.methods(); - MemberValuePair pair = memberValuePairs()[0]; - - for (int i = 0, length = methods.length; i < length; i++) { - MethodBinding method = methods[i]; - if (CharOperation.equals(method.selector, TypeConstants.VALUE)) { - pair.binding = method; - pair.resolveTypeExpecting(scope, method.returnType); - } - } - this.compilerAnnotation = scope.environment().createAnnotation((ReferenceBinding) this.resolvedType, computeElementValuePairs()); - return this.resolvedType; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java deleted file mode 100644 index d39b297..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ContinueStatement.java +++ /dev/null @@ -1,130 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class ContinueStatement extends BranchStatement { - -public ContinueStatement(char[] label, int sourceStart, int sourceEnd) { - super(label, sourceStart, sourceEnd); -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - - // here requires to generate a sequence of finally blocks invocations depending corresponding - // to each of the traversed try statements, so that execution will terminate properly. - - // lookup the label, this should answer the returnContext - FlowContext targetContext = (this.label == null) - ? flowContext.getTargetContextForDefaultContinue() - : flowContext.getTargetContextForContinueLabel(this.label); - - if (targetContext == null) { - if (this.label == null) { - currentScope.problemReporter().invalidContinue(this); - } else { - currentScope.problemReporter().undefinedLabel(this); - } - return flowInfo; // pretend it did not continue since no actual target - } else if (targetContext == FlowContext.NonLocalGotoThroughSwitchContext) { - currentScope.problemReporter().switchExpressionsContinueOutOfSwitchExpression(this); - return flowInfo; // pretend it did not continue since no actual target - } - - targetContext.recordAbruptExit(); - targetContext.expireNullCheckedFieldInfo(); - - if (targetContext == FlowContext.NotContinuableContext) { - currentScope.problemReporter().invalidContinue(this); - return flowInfo; // pretend it did not continue since no actual target - } - this.initStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); - - this.targetLabel = targetContext.continueLabel(); - FlowContext traversedContext = flowContext; - int subCount = 0; - this.subroutines = new SubRoutineStatement[5]; - - do { - SubRoutineStatement sub; - if ((sub = traversedContext.subroutine()) != null) { - if (subCount == this.subroutines.length) { - System.arraycopy(this.subroutines, 0, this.subroutines = new SubRoutineStatement[subCount*2], 0, subCount); // grow - } - this.subroutines[subCount++] = sub; - if (sub.isSubRoutineEscaping()) { - break; - } - } - 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 - } - } else if (traversedContext == targetContext) { - // only record continue info once accumulated through subroutines, and only against target context - targetContext.recordContinueFrom(flowContext, flowInfo); - break; - } - } while ((traversedContext = traversedContext.getLocalParent()) != null); - - // resize subroutines - if (subCount != this.subroutines.length) { - System.arraycopy(this.subroutines, 0, this.subroutines = new SubRoutineStatement[subCount], 0, subCount); - } - return FlowInfo.DEAD_END; -} - -@Override -public StringBuilder printStatement(int tab, StringBuilder output) { - printIndent(tab, output).append("continue "); //$NON-NLS-1$ - if (this.label != null) output.append(this.label); - return output.append(';'); -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - visitor.visit(this, blockScope); - visitor.endVisit(this, blockScope); -} -@Override -public boolean doesNotCompleteNormally() { - return true; -} - -@Override -public boolean completesByContinue() { - return true; -} - -@Override -public boolean canCompleteNormally() { - return false; -} - -@Override -public boolean continueCompletes() { - return true; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/DoStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/DoStatement.java deleted file mode 100644 index fd45167..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/DoStatement.java +++ /dev/null @@ -1,299 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 415790 - [compiler][resource]Incorrect potential resource leak warning in for loop with close in try/catch - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class DoStatement extends Statement { - - public Expression condition; - public Statement action; - - private BranchLabel breakLabel, continueLabel; - - // for local variables table attributes - int mergedInitStateIndex = -1; - int preConditionInitStateIndex = -1; - -public DoStatement(Expression condition, Statement action, int sourceStart, int sourceEnd) { - - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - this.condition = condition; - this.action = action; - // remember useful empty statement - if (action instanceof EmptyStatement) action.bits |= ASTNode.IsUsefulEmptyStatement; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - this.breakLabel = new BranchLabel(); - this.continueLabel = new BranchLabel(); - LoopingFlowContext loopingContext = - new LoopingFlowContext( - flowContext, - flowInfo, - this, - this.breakLabel, - this.continueLabel, - currentScope, - false); - - Constant cst = this.condition.constant; - boolean isConditionTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; - cst = this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - - int previousMode = flowInfo.reachMode(); - - FlowInfo initsOnCondition = flowInfo; - UnconditionalFlowInfo actionInfo = flowInfo.nullInfoLessUnconditionalCopy(); - // we need to collect the contribution to nulls of the coming paths through the - // loop, be they falling through normally or branched to break, continue labels - // or catch blocks - if ((this.action != null) && !this.action.isEmptyBlock()) { - actionInfo = this.action. - analyseCode(currentScope, loopingContext, actionInfo). - unconditionalInits(); - - // code generation can be optimized when no need to continue in the loop - if ((actionInfo.tagBits & - loopingContext.initsOnContinue.tagBits & - FlowInfo.UNREACHABLE_OR_DEAD) != 0) { - this.continueLabel = null; - } - if ((this.condition.implicitConversion & TypeIds.UNBOXING) != 0) { - initsOnCondition = flowInfo.unconditionalInits(). - addInitializationsFrom( - actionInfo.mergedWith(loopingContext.initsOnContinue)); - } - } - this.condition.checkNPEbyUnboxing(currentScope, flowContext, initsOnCondition); - /* Reset reach mode, to address following scenario. - * final blank; - * do { if (true) break; else blank = 0; } while(false); - * blank = 1; // may be initialized already - */ - actionInfo.setReachMode(previousMode); - - LoopingFlowContext condLoopContext; - FlowInfo condInfo = - this.condition.analyseCode( - currentScope, - (condLoopContext = - new LoopingFlowContext(flowContext, flowInfo, this, null, - null, currentScope, true)), - (this.action == null - ? actionInfo - : (actionInfo.mergedWith(loopingContext.initsOnContinue))).copy()); - /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=367023, we reach the condition at the bottom via two arcs, - one by free fall and another by continuing... Merge initializations propagated through the two pathways, - cf, while and for loops. - */ - this.preConditionInitStateIndex = currentScope.methodScope().recordInitializationStates(actionInfo.mergedWith(loopingContext.initsOnContinue)); - if (!isConditionOptimizedFalse && this.continueLabel != null) { - loopingContext.complainOnDeferredFinalChecks(currentScope, condInfo); - condLoopContext.complainOnDeferredFinalChecks(currentScope, condInfo); - loopingContext.complainOnDeferredNullChecks(currentScope, - flowInfo.unconditionalCopy().addPotentialNullInfoFrom( - condInfo.initsWhenTrue().unconditionalInits())); - condLoopContext.complainOnDeferredNullChecks(currentScope, - actionInfo.addPotentialNullInfoFrom( - condInfo.initsWhenTrue().unconditionalInits())); - } else { - loopingContext.complainOnDeferredNullChecks(currentScope, - flowInfo.unconditionalCopy().addPotentialNullInfoFrom( - condInfo.initsWhenTrue().unconditionalInits()), false); - condLoopContext.complainOnDeferredNullChecks(currentScope, - actionInfo.addPotentialNullInfoFrom( - condInfo.initsWhenTrue().unconditionalInits()), false); - } - if (loopingContext.hasEscapingExceptions()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=321926 - FlowInfo loopbackFlowInfo = flowInfo.copy(); - // loopback | (loopback + action + condition): - loopbackFlowInfo = loopbackFlowInfo.mergedWith(loopbackFlowInfo.unconditionalCopy().addNullInfoFrom(condInfo.initsWhenTrue()).unconditionalInits()); - loopingContext.simulateThrowAfterLoopBack(loopbackFlowInfo); - } - // end of loop - FlowInfo mergedInfo = - FlowInfo.mergedOptimizedBranches( - (loopingContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) != 0 - ? loopingContext.initsOnBreak - : flowInfo.unconditionalCopy().addInitializationsFrom(loopingContext.initsOnBreak), - // recover upstream null info - isConditionOptimizedTrue, - (condInfo.tagBits & FlowInfo.UNREACHABLE) == 0 - ? flowInfo.copy().addInitializationsFrom(condInfo.initsWhenFalse()) // https://bugs.eclipse.org/bugs/show_bug.cgi?id=380927 - : condInfo, - // recover null inits from before condition analysis - false, // never consider opt false case for DO loop, since break can always occur (47776) - !isConditionTrue /*do{}while(true); unreachable(); */); - this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; -} - -/** - * Do statement code generation - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) { - return; - } - int pc = codeStream.position; - - // labels management - BranchLabel actionLabel = new BranchLabel(codeStream); - if (this.action != null) actionLabel.tagBits |= BranchLabel.USED; - actionLabel.place(); - this.breakLabel.initialize(codeStream); - boolean hasContinueLabel = this.continueLabel != null; - if (hasContinueLabel) { - this.continueLabel.initialize(codeStream); - } - - // generate action - if (this.action != null) { - this.action.generateCode(currentScope, codeStream); - } - // continue label (135602) - if (hasContinueLabel) { - this.continueLabel.place(); - // May loose some local variable initializations : affecting the local variable attributes - if (this.preConditionInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preConditionInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.preConditionInitStateIndex); - } - // generate condition - Constant cst = this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - if (isConditionOptimizedFalse){ - this.condition.generateCode(currentScope, codeStream, false); - } else { - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - actionLabel, - null, - true); - } - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - if (this.breakLabel.forwardReferenceCount() > 0) { - this.breakLabel.place(); - } - - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public StringBuilder printStatement(int indent, StringBuilder output) { - printIndent(indent, output).append("do"); //$NON-NLS-1$ - if (this.action == null) - output.append(" ;\n"); //$NON-NLS-1$ - else { - output.append('\n'); - this.action.printStatement(indent + 1, output).append('\n'); - } - output.append("while ("); //$NON-NLS-1$ - return this.condition.printExpression(0, output).append(");"); //$NON-NLS-1$ -} - -@Override -public LocalVariableBinding[] bindingsWhenComplete() { - return this.condition.containsPatternVariable() && this.action != null && !this.action.breaksOut(null) ? - this.condition.bindingsWhenFalse() : NO_VARIABLES; -} - -@Override -public void resolve(BlockScope scope) { - TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); - this.condition.computeConversion(scope, type, type); - if (this.action != null) { - this.action.resolve(scope); - } -} - -@Override -public boolean containsPatternVariable() { - return this.condition.containsPatternVariable(); -} -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.action != null) { - this.action.traverse(visitor, scope); - } - this.condition.traverse(visitor, scope); - } - visitor.endVisit(this, scope); -} - -@Override -public boolean doesNotCompleteNormally() { - Constant cst = this.condition.constant; - boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true; - cst = this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true; - - if (isConditionTrue || isConditionOptimizedTrue) - return this.action == null || !this.action.breaksOut(null); - if (this.action == null || this.action.breaksOut(null)) - return false; - return this.action.doesNotCompleteNormally() && !this.action.completesByContinue(); -} - -@Override -public boolean completesByContinue() { - return this.action.continuesAtOuterLabel(); -} - -@Override -public boolean canCompleteNormally() { - Constant cst = this.condition.constant; - boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true; - cst = this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true; - - if (!(isConditionTrue || isConditionOptimizedTrue)) { - if (this.action == null || this.action.canCompleteNormally()) - return true; - if (this.action != null && this.action.continueCompletes()) - return true; - } - if (this.action != null && this.action.breaksOut(null)) - return true; - - return false; -} -@Override -public boolean continueCompletes() { - return this.action.continuesAtOuterLabel(); -} - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java deleted file mode 100644 index 87c58ad..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/DoubleLiteral.java +++ /dev/null @@ -1,131 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.util.FloatUtil; - -public class DoubleLiteral extends NumberLiteral { - - double value; - -public DoubleLiteral(char[] token, int s, int e) { - super(token, s, e); -} - -@Override -public void computeConstant() { - Double computedValue; - boolean containsUnderscores = CharOperation.indexOf('_', this.source) > 0; - if (containsUnderscores) { - // remove all underscores from source - this.source = CharOperation.remove(this.source, '_'); - } - try { - computedValue = Double.valueOf(String.valueOf(this.source)); - } catch (NumberFormatException e) { - // hex floating point literal - // being rejected by 1.4 libraries where Double.valueOf(...) doesn't handle hex decimal floats - try { - double v = FloatUtil.valueOfHexDoubleLiteral(this.source); - if (v == Double.POSITIVE_INFINITY) { - // error: the number is too large to represent - return; - } - if (Double.isNaN(v)) { - // error: the number is too small to represent - return; - } - this.value = v; - this.constant = DoubleConstant.fromValue(v); - } catch (NumberFormatException e1) { - // if the computation of the constant fails - } - return; - } - final double doubleValue = computedValue.doubleValue(); - if (doubleValue > Double.MAX_VALUE) { - // error: the number is too large to represent - return; - } - if (doubleValue < Double.MIN_VALUE) { - // see 1F6IGUU - // a true 0 only has '0' and '.' in mantissa - // 1.0e-5000d is non-zero, but underflows to 0 - boolean isHexaDecimal = false; - label : for (int i = 0; i < this.source.length; i++) { //it is welled formated so just test against '0' and potential . D d - switch (this.source[i]) { - case '0' : - case '.' : - break; - case 'x' : - case 'X' : - isHexaDecimal = true; - break; - case 'e' : - case 'E' : - case 'f' : - case 'F' : - case 'd' : - case 'D' : - if (isHexaDecimal) { - return; - } - // starting the exponent - mantissa is all zero - // no exponent - mantissa is all zero - break label; - case 'p' : - case 'P' : - break label; - default : - // error: the number is too small to represent - return; - } - } - } - this.value = doubleValue; - this.constant = DoubleConstant.fromValue(this.value); -} - -/** - * Code generation for the double literak - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public TypeBinding literalType(BlockScope scope) { - return TypeBinding.DOUBLE; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java deleted file mode 100644 index 19762f3..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/EmptyStatement.java +++ /dev/null @@ -1,73 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * 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; - -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -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.ASTVisitor; - -public class EmptyStatement extends Statement { - - public EmptyStatement(int startPosition, int endPosition) { - this.sourceStart = startPosition; - this.sourceEnd = endPosition; - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return flowInfo; - } - - // Report an error if necessary - @Override - 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, endOfBlock); - } - - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream){ - // no bytecode, no need to check for reachability or recording source positions - } - - @Override - public StringBuilder printStatement(int tab, StringBuilder output) { - return printIndent(tab, output).append(';'); - } - - @Override - public void resolve(BlockScope scope) { - if ((this.bits & IsUsefulEmptyStatement) == 0) { - scope.problemReporter().superfluousSemicolon(this.sourceStart, this.sourceEnd); - } else { - scope.problemReporter().emptyControlFlowStatement(this.sourceStart, this.sourceEnd); - } - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - -} - diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java deleted file mode 100644 index c80abd9..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/EqualExpression.java +++ /dev/null @@ -1,1032 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 382069 - [null] Make the null analysis consider JUnit's assertNotNull similarly to assertions - * bug 403086 - [compiler][null] include the effect of 'assert' in syntactic null analysis for fields - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class EqualExpression extends BinaryExpression { - - public EqualExpression(Expression left, Expression right,int operator) { - super(left,right,operator); - } - private void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) { - - // collect null status of child nodes: - int rightStatus = this.right.nullStatus(flowInfo, flowContext); - int leftStatus = this.left.nullStatus(flowInfo, flowContext); - - boolean leftNonNullChecked = false; - boolean rightNonNullChecked = false; - - // check if either is a non-local expression known to be nonnull and compared to null, candidates are - // - method/field annotated @NonNull - // - allocation expression, some literals, this reference (see inside expressionNonNullComparison(..)) - // these checks do not leverage the flowInfo. - boolean checkEquality = ((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL; - if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING_MASK) == 0) { - if (leftStatus == FlowInfo.NON_NULL && rightStatus == FlowInfo.NULL) { - leftNonNullChecked = scope.problemReporter().expressionNonNullComparison(this.left, checkEquality); - } else if (leftStatus == FlowInfo.NULL && rightStatus == FlowInfo.NON_NULL) { - rightNonNullChecked = scope.problemReporter().expressionNonNullComparison(this.right, checkEquality); - } - } - - boolean contextualCheckEquality = checkEquality ^ ((flowContext.tagBits & FlowContext.INSIDE_NEGATION) != 0); - // perform flowInfo-based checks for variables and record info for syntactic null analysis for fields: - if (!leftNonNullChecked) { - LocalVariableBinding local = this.left.localVariableBinding(); - if (local != null) { - if ((local.type.tagBits & TagBits.IsBaseType) == 0) { - checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, rightStatus, this.left); - } - } else if (this.left instanceof Reference reference - && ((contextualCheckEquality ? rightStatus == FlowInfo.NON_NULL : rightStatus == FlowInfo.NULL)) - && shouldPerformSyntacticAnalsysisFor(scope, reference)) - { - FieldBinding field = reference.lastFieldBinding(); - if (field != null && (field.type.tagBits & TagBits.IsBaseType) == 0) { - flowContext.recordNullCheckedFieldReference((Reference) this.left, 1); - } - } - } - if (!rightNonNullChecked) { - LocalVariableBinding local = this.right.localVariableBinding(); - if (local != null) { - if ((local.type.tagBits & TagBits.IsBaseType) == 0) { - checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, leftStatus, this.right); - } - } else if (this.right instanceof Reference reference - && ((contextualCheckEquality ? leftStatus == FlowInfo.NON_NULL : leftStatus == FlowInfo.NULL)) - && shouldPerformSyntacticAnalsysisFor(scope, reference)) - { - FieldBinding field = reference.lastFieldBinding(); - if (field != null && (field.type.tagBits & TagBits.IsBaseType) == 0) { - flowContext.recordNullCheckedFieldReference((Reference) this.right, 1); - } - } - } - - // handle reachability: - if (leftNonNullChecked || rightNonNullChecked) { - // above checks have not propagated unreachable into the corresponding branch, do it now: - if (checkEquality) { - initsWhenTrue.setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); - } else { - initsWhenFalse.setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); - } - } - } - boolean shouldPerformSyntacticAnalsysisFor(Scope scope, Reference reference) { - CompilerOptions compilerOptions = scope.compilerOptions(); - if (compilerOptions.enableSyntacticNullAnalysisForFields) - return true; - if (compilerOptions.isAnnotationBasedResourceAnalysisEnabled && (reference.bits & Binding.FIELD) != 0) { - // annotation based resource leak analysis implicitly "borrows" from syntactic analysis for fields - // in order to understand the pattern "if (this.resource != null) this.resource.close();" - FieldBinding fieldBinding = reference.fieldBinding(); - if (fieldBinding != null && fieldBinding.closeTracker != null) - return true; - } - return false; - } - public void syntacticFieldAnalysisForFalseBranch(FlowInfo flowInfo, FlowContext flowContext) { - // extracted slice of checkNullComparison concerning syntactic null analysis for fields: - // now compute the effect on the false branch and record it in flowContext: - int rightStatus = this.right.nullStatus(flowInfo, flowContext); - if (rightStatus == FlowInfo.NULL - && this.left instanceof Reference - && this.left.localVariableBinding() == null) - { - FieldBinding field = ((Reference)this.left).lastFieldBinding(); - if (field != null && (field.type.tagBits & TagBits.IsBaseType) == 0) { - flowContext.recordNullCheckedFieldReference((Reference) this.left, 1); - } - } - int leftStatus = this.left.nullStatus(flowInfo, flowContext); - if (leftStatus == FlowInfo.NULL - && this.right instanceof Reference - && this.right.localVariableBinding() == null) - { - FieldBinding field = ((Reference)this.right).lastFieldBinding(); - if (field != null && (field.type.tagBits & TagBits.IsBaseType) == 0) { - flowContext.recordNullCheckedFieldReference((Reference) this.right, 1); - } - } - } - private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, LocalVariableBinding local, int nullStatus, Expression reference) { - switch (nullStatus) { - case FlowInfo.NULL : - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { - flowContext.recordUsingNullReference(scope, local, reference, - FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo); - initsWhenTrue.markAsComparedEqualToNull(local); // from thereon it is set - initsWhenFalse.markAsComparedEqualToNonNull(local); // from thereon it is set - } else { - flowContext.recordUsingNullReference(scope, local, reference, - FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo); - initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set - initsWhenFalse.markAsComparedEqualToNull(local); // from thereon it is set - } - break; - case FlowInfo.NON_NULL : - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { - flowContext.recordUsingNullReference(scope, local, reference, - FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo); - initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set - } else { - flowContext.recordUsingNullReference(scope, local, reference, - FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo); - } - break; - } - // we do not impact enclosing try context because this kind of protection - // does not preclude the variable from being null in an enclosing scope - } - private void analyzeLocalVariable(Expression exp, FlowInfo flowInfo) { - if (exp instanceof SingleNameReference && (exp.bits & Binding.LOCAL) != 0 ) { - LocalVariableBinding localBinding = (LocalVariableBinding) ((SingleNameReference ) exp).binding; - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { - localBinding.useFlag = LocalVariableBinding.USED; - } else if (localBinding.useFlag == LocalVariableBinding.UNUSED ) { - localBinding.useFlag = LocalVariableBinding.FAKE_USED; - } - } - } - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - FlowInfo result; - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { - if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.typeID() == T_boolean)) { - if (this.left.constant.booleanValue()) { // true == anything - // this is equivalent to the right argument inits - result = this.right.analyseCode(currentScope, flowContext, flowInfo); - } else { // false == anything - // this is equivalent to the right argument inits negated - result = this.right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); - analyzeLocalVariable(this.left, flowInfo); - } - } - else if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.typeID() == T_boolean)) { - if (this.right.constant.booleanValue()) { // anything == true - // this is equivalent to the left argument inits - result = this.left.analyseCode(currentScope, flowContext, flowInfo); - } else { // anything == false - // this is equivalent to the right argument inits negated - result = this.left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); - analyzeLocalVariable(this.right, flowInfo); - } - } - else { - result = this.right.analyseCode( - currentScope, flowContext, - this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits(); - } - } else { //NOT_EQUAL : - if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.typeID() == T_boolean)) { - if (!this.left.constant.booleanValue()) { // false != anything - // this is equivalent to the right argument inits - result = this.right.analyseCode(currentScope, flowContext, flowInfo); - analyzeLocalVariable(this.left, flowInfo); - } else { // true != anything - // this is equivalent to the right argument inits negated - result = this.right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); - } - } - else if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.typeID() == T_boolean)) { - if (!this.right.constant.booleanValue()) { // anything != false - // this is equivalent to the right argument inits - result = this.left.analyseCode(currentScope, flowContext, flowInfo); - analyzeLocalVariable(this.right, flowInfo); - } else { // anything != true - // this is equivalent to the right argument inits negated - result = this.left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition(); - } - } - else { - result = this.right.analyseCode( - currentScope, flowContext, - this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()). - /* unneeded since we flatten it: asNegatedCondition(). */ - unconditionalInits(); - } - } - if (result instanceof UnconditionalFlowInfo && - (result.tagBits & FlowInfo.UNREACHABLE) == 0) { // the flow info is flat - result = FlowInfo.conditional(result.copy(), result.copy()); - // TODO (maxime) check, reintroduced copy - } - checkNullComparison(currentScope, flowContext, result, result.initsWhenTrue(), result.initsWhenFalse()); - return result; - } - - public final void computeConstant(TypeBinding leftType, TypeBinding rightType) { - if ((this.left.constant != Constant.NotAConstant) && (this.right.constant != Constant.NotAConstant)) { - this.constant = - Constant.computeConstantOperationEQUAL_EQUAL( - this.left.constant, - leftType.id, - this.right.constant, - rightType.id); - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT_EQUAL) - this.constant = BooleanConstant.fromValue(!this.constant.booleanValue()); - } else { - this.constant = Constant.NotAConstant; - // no optimization for null == null - } - } - /** - * Normal == or != code generation. - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - - int pc = codeStream.position; - if (this.constant != Constant.NotAConstant) { - if (valueRequired) - codeStream.generateConstant(this.constant, this.implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - - if ((this.left.implicitConversion & COMPILE_TYPE_MASK) /*compile-time*/ == T_boolean) { - generateBooleanEqual(currentScope, codeStream, valueRequired); - } else { - generateNonBooleanEqual(currentScope, codeStream, valueRequired); - } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - /** - * Boolean operator code generation - * Optimized operations are: == and != - */ - @Override - public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - - if (this.constant != Constant.NotAConstant) { - super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - return; - } - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) { - if ((this.left.implicitConversion & COMPILE_TYPE_MASK) /*compile-time*/ == T_boolean) { - generateOptimizedBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - } else { - generateOptimizedNonBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - } - } else { - if ((this.left.implicitConversion & COMPILE_TYPE_MASK) /*compile-time*/ == T_boolean) { - generateOptimizedBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired); - } else { - generateOptimizedNonBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired); - } - } - } - - /** - * Boolean generation for == with boolean operands - * - * Note this code does not optimize conditional constants !!!! - */ - public void generateBooleanEqual(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - - // optimized cases: == x, == x, - // optimized cases: != x, != x, - boolean isEqualOperator = ((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL; - Constant cst = this.left.optimizedBooleanConstant(); - if (cst != Constant.NotAConstant) { - Constant rightCst = this.right.optimizedBooleanConstant(); - if (rightCst != Constant.NotAConstant) { - // == , != - // == , != - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, false); - if (valueRequired) { - boolean leftBool = cst.booleanValue(); - boolean rightBool = rightCst.booleanValue(); - if (isEqualOperator) { - if (leftBool == rightBool) { - codeStream.iconst_1(); - } else { - codeStream.iconst_0(); - } - } else { - if (leftBool != rightBool) { - codeStream.iconst_1(); - } else { - codeStream.iconst_0(); - } - } - } - } else if (cst.booleanValue() == isEqualOperator) { - // == x, != x - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, valueRequired); - } else { - // == x, != x - if (valueRequired) { - BranchLabel falseLabel = new BranchLabel(codeStream); - this.left.generateCode(currentScope, codeStream, false); - this.right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired); - // comparison is TRUE - codeStream.iconst_0(); - if ((this.bits & IsReturnedValue) != 0){ - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_1(); - } else { - BranchLabel endLabel = new BranchLabel(codeStream); - codeStream.goto_(endLabel); - codeStream.decrStackSize(1); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_1(); - endLabel.place(); - } - } else { - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, false); - } -// left.generateCode(currentScope, codeStream, false); -// right.generateCode(currentScope, codeStream, valueRequired); -// if (valueRequired) { -// codeStream.iconst_1(); -// codeStream.ixor(); // negate -// } - } - return; - } - cst = this.right.optimizedBooleanConstant(); - if (cst != Constant.NotAConstant) { - if (cst.booleanValue() == isEqualOperator) { - // x == , x != - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, false); - } else { - // x == , x != - if (valueRequired) { - BranchLabel falseLabel = new BranchLabel(codeStream); - this.left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired); - this.right.generateCode(currentScope, codeStream, false); - // comparison is TRUE - codeStream.iconst_0(); - if ((this.bits & IsReturnedValue) != 0){ - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_1(); - } else { - BranchLabel endLabel = new BranchLabel(codeStream); - codeStream.goto_(endLabel); - codeStream.decrStackSize(1); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_1(); - endLabel.place(); - } - } else { - this.left.generateCode(currentScope, codeStream, false); - this.right.generateCode(currentScope, codeStream, false); - } -// left.generateCode(currentScope, codeStream, valueRequired); -// right.generateCode(currentScope, codeStream, false); -// if (valueRequired) { -// codeStream.iconst_1(); -// codeStream.ixor(); // negate -// } - } - return; - } - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - - if (valueRequired) { - if (isEqualOperator) { - BranchLabel falseLabel; - codeStream.if_icmpne(falseLabel = new BranchLabel(codeStream)); - // comparison is TRUE - codeStream.iconst_1(); - if ((this.bits & IsReturnedValue) != 0){ - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - } else { - BranchLabel endLabel = new BranchLabel(codeStream); - codeStream.goto_(endLabel); - codeStream.decrStackSize(1); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } else { - codeStream.ixor(); - } - } - } - - /** - * Boolean generation for == with boolean operands - * - * Note this code does not optimize conditional constants !!!! - */ - public void generateOptimizedBooleanEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - - // optimized cases: true == x, false == x - if (this.left.constant != Constant.NotAConstant) { - boolean inline = this.left.constant.booleanValue(); - this.right.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired); - return; - } // optimized cases: x == true, x == false - if (this.right.constant != Constant.NotAConstant) { - boolean inline = this.right.constant.booleanValue(); - this.left.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired); - return; - } - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - int pc = codeStream.position; - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - codeStream.if_icmpeq(trueLabel); - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.if_icmpne(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceEnd); - } - /** - * Boolean generation for == with non-boolean operands - */ - public void generateNonBooleanEqual(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - - boolean isEqualOperator = ((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL; - if (((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int) { - Constant cst; - if ((cst = this.left.constant) != Constant.NotAConstant && cst.intValue() == 0) { - // optimized case: 0 == x, 0 != x - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - BranchLabel falseLabel = new BranchLabel(codeStream); - if (isEqualOperator) { - codeStream.ifne(falseLabel); - } else { - codeStream.ifeq(falseLabel); - } - // comparison is TRUE - codeStream.iconst_1(); - if ((this.bits & IsReturnedValue) != 0){ - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - } else { - BranchLabel endLabel = new BranchLabel(codeStream); - codeStream.goto_(endLabel); - codeStream.decrStackSize(1); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } - return; - } - if ((cst = this.right.constant) != Constant.NotAConstant && cst.intValue() == 0) { - // optimized case: x == 0, x != 0 - this.left.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - BranchLabel falseLabel = new BranchLabel(codeStream); - if (isEqualOperator) { - codeStream.ifne(falseLabel); - } else { - codeStream.ifeq(falseLabel); - } - // comparison is TRUE - codeStream.iconst_1(); - if ((this.bits & IsReturnedValue) != 0){ - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - } else { - BranchLabel endLabel = new BranchLabel(codeStream); - codeStream.goto_(endLabel); - codeStream.decrStackSize(1); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } - return; - } - } - - // null cases - if (this.right instanceof NullLiteral) { - if (this.left instanceof NullLiteral) { - // null == null, null != null - if (valueRequired) { - if (isEqualOperator) { - codeStream.iconst_1(); - } else { - codeStream.iconst_0(); - } - } - } else { - // x == null, x != null - this.left.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - BranchLabel falseLabel = new BranchLabel(codeStream); - if (isEqualOperator) { - codeStream.ifnonnull(falseLabel); - } else { - codeStream.ifnull(falseLabel); - } - // comparison is TRUE - codeStream.iconst_1(); - if ((this.bits & IsReturnedValue) != 0){ - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - } else { - BranchLabel endLabel = new BranchLabel(codeStream); - codeStream.goto_(endLabel); - codeStream.decrStackSize(1); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } - } - return; - } else if (this.left instanceof NullLiteral) { - // null = x, null != x - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - BranchLabel falseLabel = new BranchLabel(codeStream); - if (isEqualOperator) { - codeStream.ifnonnull(falseLabel); - } else { - codeStream.ifnull(falseLabel); - } - // comparison is TRUE - codeStream.iconst_1(); - if ((this.bits & IsReturnedValue) != 0){ - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - } else { - BranchLabel endLabel = new BranchLabel(codeStream); - codeStream.goto_(endLabel); - codeStream.decrStackSize(1); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } - return; - } - - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - BranchLabel falseLabel = new BranchLabel(codeStream); - if (isEqualOperator) { - switch ((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type - case T_int : - codeStream.if_icmpne(falseLabel); - break; - case T_float : - codeStream.fcmpl(); - codeStream.ifne(falseLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifne(falseLabel); - break; - case T_double : - codeStream.dcmpl(); - codeStream.ifne(falseLabel); - break; - default : - codeStream.if_acmpne(falseLabel); - } - } else { - switch ((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type - case T_int : - codeStream.if_icmpeq(falseLabel); - break; - case T_float : - codeStream.fcmpl(); - codeStream.ifeq(falseLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifeq(falseLabel); - break; - case T_double : - codeStream.dcmpl(); - codeStream.ifeq(falseLabel); - break; - default : - codeStream.if_acmpeq(falseLabel); - } - } - // comparison is TRUE - codeStream.iconst_1(); - if ((this.bits & IsReturnedValue) != 0){ - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - } else { - BranchLabel endLabel = new BranchLabel(codeStream); - codeStream.goto_(endLabel); - codeStream.decrStackSize(1); - // comparison is FALSE - falseLabel.place(); - codeStream.iconst_0(); - endLabel.place(); - } - } - } - - /** - * Boolean generation for == with non-boolean operands - */ - public void generateOptimizedNonBooleanEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - - int pc = codeStream.position; - Constant inline; - if ((inline = this.right.constant) != Constant.NotAConstant) { - // optimized case: x == 0 - if ((((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int) && (inline.intValue() == 0)) { - this.left.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - codeStream.ifeq(trueLabel); - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.ifne(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - } - if ((inline = this.left.constant) != Constant.NotAConstant) { - // optimized case: 0 == x - if ((((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int) - && (inline.intValue() == 0)) { - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - codeStream.ifeq(trueLabel); - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.ifne(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - } - // null cases - // optimized case: x == null - if (this.right instanceof NullLiteral) { - if (this.left instanceof NullLiteral) { - // null == null - if (valueRequired) { - if (falseLabel == null) { - // implicit falling through the FALSE case - if (trueLabel != null) { - codeStream.goto_(trueLabel); - } - } - } - } else { - this.left.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - codeStream.ifnull(trueLabel); - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.ifnonnull(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } else if (this.left instanceof NullLiteral) { // optimized case: null == x - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - codeStream.ifnull(trueLabel); - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.ifnonnull(falseLabel); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - - // default case - this.left.generateCode(currentScope, codeStream, valueRequired); - this.right.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - switch ((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type - case T_int : - codeStream.if_icmpeq(trueLabel); - break; - case T_float : - codeStream.fcmpl(); - codeStream.ifeq(trueLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifeq(trueLabel); - break; - case T_double : - codeStream.dcmpl(); - codeStream.ifeq(trueLabel); - break; - default : - codeStream.if_acmpeq(trueLabel); - } - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - switch ((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type - case T_int : - codeStream.if_icmpne(falseLabel); - break; - case T_float : - codeStream.fcmpl(); - codeStream.ifne(falseLabel); - break; - case T_long : - codeStream.lcmp(); - codeStream.ifne(falseLabel); - break; - case T_double : - codeStream.dcmpl(); - codeStream.ifne(falseLabel); - break; - default : - codeStream.if_acmpne(falseLabel); - } - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - @Override - public boolean isCompactableOperation() { - return false; - } - - @Override - protected Constant optimizedNullComparisonConstant() { - int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT; - if (operator == OperatorIds.EQUAL_EQUAL) { - if (this.left instanceof NullLiteral && this.right instanceof NullLiteral) { - return BooleanConstant.fromValue(true); - } - } else if (operator == OperatorIds.NOT_EQUAL) { - if (this.left instanceof NullLiteral && this.right instanceof NullLiteral) { - return BooleanConstant.fromValue(false); - } - } - return Constant.NotAConstant; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - - boolean leftIsCast, rightIsCast; - if ((leftIsCast = this.left instanceof CastExpression) == true) this.left.bits |= DisableUnnecessaryCastCheck; // will check later on - TypeBinding originalLeftType = this.left.resolveType(scope); - - if ((rightIsCast = this.right instanceof CastExpression) == true) this.right.bits |= DisableUnnecessaryCastCheck; // will check later on - TypeBinding originalRightType = this.right.resolveType(scope); - - // always return BooleanBinding - if (originalLeftType == null || originalRightType == null){ - this.constant = Constant.NotAConstant; - return null; - } - - final CompilerOptions compilerOptions = scope.compilerOptions(); - if (compilerOptions.complainOnUninternedIdentityComparison && originalRightType.hasTypeBit(TypeIds.BitUninternedType) && originalLeftType.hasTypeBit(TypeIds.BitUninternedType)) - scope.problemReporter().uninternedIdentityComparison(this, originalLeftType, originalRightType, scope.referenceCompilationUnit()); - - // autoboxing support - boolean use15specifics = compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5; - TypeBinding leftType = originalLeftType, rightType = originalRightType; - if (use15specifics) { - if (leftType != TypeBinding.NULL && leftType.isBaseType()) { - if (!rightType.isBaseType()) { - rightType = scope.environment().computeBoxingType(rightType); - } - } else { - if (rightType != TypeBinding.NULL && rightType.isBaseType()) { - leftType = scope.environment().computeBoxingType(leftType); - } - } - } - // both base type - if (leftType.isBaseType() && rightType.isBaseType()) { - int leftTypeID = leftType.id; - int rightTypeID = rightType.id; - - // the code is an int - // (cast) left == (cast) right --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 <<0 - int operatorSignature = OperatorSignatures[EQUAL_EQUAL][ (leftTypeID << 4) + rightTypeID]; - this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), originalLeftType); - this.right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), originalRightType); - this.bits |= operatorSignature & 0xF; - if ((operatorSignature & 0x0000F) == T_undefined) { - this.constant = Constant.NotAConstant; - scope.problemReporter().invalidOperator(this, leftType, rightType); - return null; - } - // check need for operand cast - if (leftIsCast || rightIsCast) { - CastExpression.checkNeedForArgumentCasts(scope, EQUAL_EQUAL, operatorSignature, this.left, leftType.id, leftIsCast, this.right, rightType.id, rightIsCast); - } - computeConstant(leftType, rightType); - - // check whether comparing identical expressions - Binding leftDirect = Expression.getDirectBinding(this.left); - if (leftDirect != null && leftDirect == Expression.getDirectBinding(this.right)) { - if (leftTypeID != TypeIds.T_double && leftTypeID != TypeIds.T_float - &&(!(this.right instanceof Assignment))) // https://bugs.eclipse.org/bugs/show_bug.cgi?id=281776 - scope.problemReporter().comparingIdenticalExpressions(this); - } else if (this.constant != Constant.NotAConstant) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=276740 - int operator = (this.bits & OperatorMASK) >> OperatorSHIFT; - if ((operator == EQUAL_EQUAL && this.constant == BooleanConstant.fromValue(true)) - || (operator == NOT_EQUAL && this.constant == BooleanConstant.fromValue(false))) - scope.problemReporter().comparingIdenticalExpressions(this); - } - return this.resolvedType = TypeBinding.BOOLEAN; - } - - // Object references - // spec 15.20.3 - if ((!leftType.isBaseType() || leftType == TypeBinding.NULL) // cannot compare: Object == (int)0 - && (!rightType.isBaseType() || rightType == TypeBinding.NULL) - && (checkCastTypesCompatibility(scope, leftType, rightType, null, true) - || checkCastTypesCompatibility(scope, rightType, leftType, null, true))) { - - // (special case for String) - if ((rightType.id == T_JavaLangString) && (leftType.id == T_JavaLangString)) { - computeConstant(leftType, rightType); - } else { - this.constant = Constant.NotAConstant; - } - TypeBinding objectType = scope.getJavaLangObject(); - this.left.computeConversion(scope, objectType, leftType); - this.right.computeConversion(scope, objectType, rightType); - // check need for operand cast - boolean unnecessaryLeftCast = (this.left.bits & UnnecessaryCast) != 0; - boolean unnecessaryRightCast = (this.right.bits & UnnecessaryCast) != 0; - if (unnecessaryLeftCast || unnecessaryRightCast) { - TypeBinding alternateLeftType = unnecessaryLeftCast ? ((CastExpression)this.left).expression.resolvedType : leftType; - TypeBinding alternateRightType = unnecessaryRightCast ? ((CastExpression)this.right).expression.resolvedType : rightType; - // Bug 543727 - check if either cast is really needed - if (!isCastNeeded(alternateLeftType, alternateRightType)) { - if (checkCastTypesCompatibility(scope, alternateLeftType, alternateRightType, null, false) - || checkCastTypesCompatibility(scope, alternateRightType, alternateLeftType, null, false)) { - if (unnecessaryLeftCast) scope.problemReporter().unnecessaryCast((CastExpression)this.left); - if (unnecessaryRightCast) scope.problemReporter().unnecessaryCast((CastExpression)this.right); - } - } - } - // check whether comparing identical expressions - Binding leftDirect = Expression.getDirectBinding(this.left); - if (leftDirect != null && leftDirect == Expression.getDirectBinding(this.right)) { - if (!(this.right instanceof Assignment)) { - scope.problemReporter().comparingIdenticalExpressions(this); - } - } - return this.resolvedType = TypeBinding.BOOLEAN; - } - this.constant = Constant.NotAConstant; - scope.problemReporter().notCompatibleTypesError(this, leftType, rightType); - return null; - } - - private boolean isCastNeeded(TypeBinding leftType, TypeBinding rightType) { - // Bug 543727 - if either type is parameterized and the other is a base type, - // a cast is necessary, even if boxing the base type will result in a compatible - // type. - if (leftType.isParameterizedType()) { - return rightType.isBaseType(); - } - if (rightType.isParameterizedType()) { - return leftType.isBaseType(); - } - return false; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.left.traverse(visitor, scope); - this.right.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java deleted file mode 100644 index 9f8168a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java +++ /dev/null @@ -1,564 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 361407 - Resource leak warning when resource is assigned to a field outside of constructor - * bug 370639 - [compiler][resource] restore the default for resource leak warnings - * bug 388996 - [compiler][resource] Incorrect 'potential resource leak' - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 424710 - [1.8][compiler] CCE in SingleNameReference.localVariableBinding - * Bug 425152 - [1.8] [compiler] Lambda Expression not resolved but flow analyzed leading to NPE. - * Bug 424205 - [1.8] Cannot infer type for diamond type with lambda on method invocation - * Bug 424415 - [1.8][compiler] Eventual resolution of ReferenceExpression is not seen to be happening. - * Bug 426366 - [1.8][compiler] Type inference doesn't handle multiple candidate target types in outer overload context - * Bug 426290 - [1.8][compiler] Inference + overloading => wrong method resolution ? - * Bug 427483 - [Java 8] Variables in lambdas sometimes can't be resolved - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 428352 - [1.8][compiler] Resolution errors don't always surface - * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 409245 - [1.8][compiler] Type annotations dropped when call is routed through a synthetic bridge method - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.INVOCATION_CONTEXT; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -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.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; -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.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.VariableBinding; - -public class ExplicitConstructorCall extends Statement implements Invocation { - - public Expression[] arguments; - public Expression qualification; - public MethodBinding binding; // exact binding resulting from lookup - MethodBinding syntheticAccessor; // synthetic accessor for inner-emulation - public int accessMode; - public TypeReference[] typeArguments; - public TypeBinding[] genericTypeArguments; - - public final static int ImplicitSuper = 1; - public final static int Super = 2; - public final static int This = 3; - - public VariableBinding[][] implicitArguments; - - // TODO Remove once DOMParser is activated - public int typeArgumentsSourceStart; - - public ExplicitConstructorCall(int accessMode) { - this.accessMode = accessMode; - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // must verify that exceptions potentially thrown by this expression are caught in the method. - - try { - ((MethodScope) currentScope).isConstructorCall = true; - - // process enclosing instance - if (this.qualification != null) { - flowInfo = - this.qualification - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - } - // process arguments - if (this.arguments != null) { - boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; - for (int i = 0, max = this.arguments.length; i < max; i++) { - flowInfo = - this.arguments[i] - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - if (analyseResources) { - flowInfo = handleResourcePassedToInvocation(currentScope, this.binding, this.arguments[i], i, flowContext, flowInfo); - } - this.arguments[i].checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - } - analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); - } - - ReferenceBinding[] thrownExceptions; - if ((thrownExceptions = this.binding.thrownExceptions) != Binding.NO_EXCEPTIONS) { - if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6 - thrownExceptions = currentScope.environment().convertToRawTypes(this.binding.thrownExceptions, true, true); - } - // check exceptions - flowContext.checkExceptionHandlers( - thrownExceptions, - (this.accessMode == ExplicitConstructorCall.ImplicitSuper) - ? (ASTNode) currentScope.methodScope().referenceContext - : (ASTNode) this, - flowInfo, - currentScope); - } - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - manageSyntheticAccessIfNecessary(currentScope, flowInfo); - return flowInfo; - } finally { - ((MethodScope) currentScope).isConstructorCall = false; - } - } - - /** - * Constructor call code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) { - return; - } - try { - ((MethodScope) currentScope).isConstructorCall = true; - - int pc = codeStream.position; - codeStream.aload_0(); - - MethodBinding codegenBinding = this.binding.original(); - ReferenceBinding targetType = codegenBinding.declaringClass; - - // special name&ordinal argument generation for enum constructors - if (targetType.erasure().id == TypeIds.T_JavaLangEnum || targetType.isEnum()) { - codeStream.aload_1(); // pass along name param as name arg - codeStream.iload_2(); // pass along ordinal param as ordinal arg - } - // handling innerclass constructor invocation - // handling innerclass instance allocation - enclosing instance arguments - if (targetType.isNestedType()) { - codeStream.generateSyntheticEnclosingInstanceValues( - currentScope, - targetType, - (this.bits & ASTNode.DiscardEnclosingInstance) != 0 ? null : this.qualification, - this); - } - // generate arguments - generateArguments(this.binding, this.arguments, currentScope, codeStream); - - // handling innerclass instance allocation - outer local arguments - if (targetType.isNestedType()) { - codeStream.generateSyntheticOuterArgumentValues( - currentScope, - targetType, - this); - } - if (this.syntheticAccessor != null) { - // synthetic accessor got some extra arguments appended to its signature, which need values - for (int i = 0, - max = this.syntheticAccessor.parameters.length - codegenBinding.parameters.length; - i < max; - i++) { - codeStream.aconst_null(); - } - codeStream.invoke(Opcodes.OPC_invokespecial, this.syntheticAccessor, null /* default declaringClass */, this.typeArguments); - } else { - codeStream.invoke(Opcodes.OPC_invokespecial, codegenBinding, null /* default declaringClass */, this.typeArguments); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } finally { - ((MethodScope) currentScope).isConstructorCall = false; - } - } - - /** - * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() - */ - @Override - public TypeBinding[] genericTypeArguments() { - return this.genericTypeArguments; - } - - public boolean isImplicitSuper() { - return (this.accessMode == ExplicitConstructorCall.ImplicitSuper); - } - - @Override - public boolean isSuperAccess() { - return this.accessMode != ExplicitConstructorCall.This; - } - - @Override - public boolean isTypeAccess() { - return true; - } - - /* Inner emulation consists in either recording a dependency - * link only, or performing one level of propagation. - * - * Dependency mechanism is used whenever dealing with source target - * types, since by the time we reach them, we might not yet know their - * exact need. - */ - void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - ReferenceBinding superTypeErasure = (ReferenceBinding) this.binding.declaringClass.erasure(); - - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - // perform some emulation work in case there is some and we are inside a local type only - if (superTypeErasure.isNestedType() - && currentScope.enclosingSourceType().isLocalType()) { - - if (superTypeErasure.isLocalType()) { - ((LocalTypeBinding) superTypeErasure).addInnerEmulationDependent(currentScope, this.qualification != null); - } else { - // locally propagate, since we already now the desired shape for sure - currentScope.propagateInnerEmulation(superTypeErasure, this.qualification != null); - } - } - } - } - - public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - // if constructor from parameterized type got found, use the original constructor at codegen time - MethodBinding codegenBinding = this.binding.original(); - - // perform some emulation work in case there is some and we are inside a local type only - if (this.binding.isPrivate() && - !currentScope.enclosingSourceType().isNestmateOf(this.binding.declaringClass) && - this.accessMode != ExplicitConstructorCall.This) { - ReferenceBinding declaringClass = codegenBinding.declaringClass; - // from 1.4 on, local type constructor can lose their private flag to ease emulation - if ((declaringClass.tagBits & TagBits.IsLocalType) != 0 && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) { - // constructor will not be dumped as private, no emulation required thus - codegenBinding.tagBits |= TagBits.ClearPrivateModifier; - } else { - this.syntheticAccessor = ((SourceTypeBinding) declaringClass).addSyntheticMethod(codegenBinding, isSuperAccess()); - currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this); - } - } - } - } - - @Override - public StringBuilder printStatement(int indent, StringBuilder output) { - printIndent(indent, output); - if (this.qualification != null) this.qualification.printExpression(0, output).append('.'); - if (this.typeArguments != null) { - output.append('<'); - int max = this.typeArguments.length - 1; - for (int j = 0; j < max; j++) { - this.typeArguments[j].print(0, output); - output.append(", ");//$NON-NLS-1$ - } - this.typeArguments[max].print(0, output); - output.append('>'); - } - if (this.accessMode == ExplicitConstructorCall.This) { - output.append("this("); //$NON-NLS-1$ - } else { - output.append("super("); //$NON-NLS-1$ - } - if (this.arguments != null) { - for (int i = 0; i < this.arguments.length; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.arguments[i].printExpression(0, output); - } - } - return output.append(");"); //$NON-NLS-1$ - } - - @Override - public void resolve(BlockScope scope) { - // the return type should be void for a constructor. - // the test is made into getConstructor - - // mark the fact that we are in a constructor call..... - // unmark at all returns - MethodScope methodScope = scope.methodScope(); - try { - AbstractMethodDeclaration methodDeclaration = methodScope.referenceMethod(); - if (methodDeclaration != null && methodDeclaration.binding != null - && methodDeclaration.binding.isCanonicalConstructor()) { - if (!checkAndFlagExplicitConstructorCallInCanonicalConstructor(methodDeclaration, scope)) - return; - } - if (methodDeclaration == null - || !methodDeclaration.isConstructor() - || ((ConstructorDeclaration) methodDeclaration).constructorCall != this) { - if (!(methodDeclaration instanceof CompactConstructorDeclaration)) // already flagged for CCD - scope.problemReporter().invalidExplicitConstructorCall(this); - // fault-tolerance - if (this.qualification != null) { - this.qualification.resolveType(scope); - } - if (this.typeArguments != null) { - for (int i = 0, max = this.typeArguments.length; i < max; i++) { - this.typeArguments[i].resolveType(scope, true /* check bounds*/); - } - } - if (this.arguments != null) { - for (int i = 0, max = this.arguments.length; i < max; i++) { - this.arguments[i].resolveType(scope); - } - } - return; - } - methodScope.isConstructorCall = true; - ReferenceBinding receiverType = scope.enclosingReceiverType(); - boolean rcvHasError = false; - if (this.accessMode != ExplicitConstructorCall.This) { - receiverType = receiverType.superclass(); - TypeReference superclassRef = scope.referenceType().superclass; - if (superclassRef != null && superclassRef.resolvedType != null && !superclassRef.resolvedType.isValidBinding()) { - rcvHasError = true; - } - } - if (receiverType != null) { - // prevent (explicit) super constructor invocation from within enum - if (this.accessMode == ExplicitConstructorCall.Super && receiverType.erasure().id == TypeIds.T_JavaLangEnum) { - scope.problemReporter().cannotInvokeSuperConstructorInEnum(this, methodScope.referenceMethod().binding); - } - // qualification should be from the type of the enclosingType - if (this.qualification != null) { - if (this.accessMode != ExplicitConstructorCall.Super) { - scope.problemReporter().unnecessaryEnclosingInstanceSpecification( - this.qualification, - receiverType); - } - if (!rcvHasError) { - ReferenceBinding enclosingType = receiverType.enclosingType(); - if (enclosingType == null) { - scope.problemReporter().unnecessaryEnclosingInstanceSpecification(this.qualification, receiverType); - this.bits |= ASTNode.DiscardEnclosingInstance; - } else { - TypeBinding qTb = this.qualification.resolveTypeExpecting(scope, enclosingType); - this.qualification.computeConversion(scope, qTb, qTb); - } - } - } - } - // resolve type arguments (for generic constructor call) - long sourceLevel = scope.compilerOptions().sourceLevel; - if (this.typeArguments != null) { - boolean argHasError = sourceLevel < ClassFileConstants.JDK1_5; - int length = this.typeArguments.length; - this.genericTypeArguments = new TypeBinding[length]; - for (int i = 0; i < length; i++) { - TypeReference typeReference = this.typeArguments[i]; - if ((this.genericTypeArguments[i] = typeReference.resolveType(scope, true /* check bounds*/)) == null) { - argHasError = true; - } - if (argHasError && typeReference instanceof Wildcard) { - scope.problemReporter().illegalUsageOfWildcard(typeReference); - } - } - if (argHasError) { - if (this.arguments != null) { // still attempt to resolve arguments - for (int i = 0, max = this.arguments.length; i < max; i++) { - this.arguments[i].resolveType(scope); - } - } - return; - } - } - // arguments buffering for the method lookup - TypeBinding[] argumentTypes = Binding.NO_PARAMETERS; - boolean argsContainCast = false; - if (this.arguments != null) { - boolean argHasError = false; // typeChecks all arguments - int length = this.arguments.length; - argumentTypes = new TypeBinding[length]; - for (int i = 0; i < length; i++) { - Expression argument = this.arguments[i]; - if (argument instanceof CastExpression) { - argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - argsContainCast = true; - } - argument.setExpressionContext(INVOCATION_CONTEXT); - if ((argumentTypes[i] = argument.resolveType(scope)) == null) { - argHasError = true; - } - } - if (argHasError) { - if (receiverType == null) { - return; - } - // record a best guess, for clients who need hint about possible contructor match - TypeBinding[] pseudoArgs = new TypeBinding[length]; - for (int i = length; --i >= 0;) { - pseudoArgs[i] = argumentTypes[i] == null ? TypeBinding.NULL : argumentTypes[i]; // replace args with errors with null type - } - this.binding = scope.findMethod(receiverType, TypeConstants.INIT, pseudoArgs, this, false); - if (this.binding != null && !this.binding.isValidBinding()) { - MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; - // record the closest match, for clients who may still need hint about possible method match - if (closestMatch != null) { - if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method - // shouldn't return generic method outside its context, rather convert it to raw method (175409) - closestMatch = scope.environment().createParameterizedGenericMethod(closestMatch.original(), (RawTypeBinding)null); - } - this.binding = closestMatch; - MethodBinding closestMatchOriginal = closestMatch.original(); - if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { - // ignore cases where method is used from within inside itself (e.g. direct recursions) - closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - } - } - return; - } - } else if (receiverType.erasure().id == TypeIds.T_JavaLangEnum) { - // TODO (philippe) get rid of once well-known binding is available - argumentTypes = new TypeBinding[] { scope.getJavaLangString(), TypeBinding.INT }; - } - if (receiverType == null) { - return; - } - this.binding = findConstructorBinding(scope, this, receiverType, argumentTypes); - - if (this.binding.isValidBinding()) { - if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { - if (!methodScope.enclosingSourceType().isAnonymousType()) { - scope.problemReporter().missingTypeInConstructor(this, this.binding); - } - } - if (isMethodUseDeprecated(this.binding, scope, this.accessMode != ExplicitConstructorCall.ImplicitSuper, this)) { - scope.problemReporter().deprecatedMethod(this.binding, this); - } - if (checkInvocationArguments(scope, null, receiverType, this.binding, this.arguments, argumentTypes, argsContainCast, this)) { - this.bits |= ASTNode.Unchecked; - } - if (this.binding.isOrEnclosedByPrivateType()) { - this.binding.original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - if (this.typeArguments != null - && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { - scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(this.binding, this.genericTypeArguments, this.typeArguments); - } - } else { - if (this.binding.declaringClass == null) { - this.binding.declaringClass = receiverType; - } - if (rcvHasError) - return; - scope.problemReporter().invalidConstructor(this, this.binding); - } - } finally { - methodScope.isConstructorCall = false; - } - } - - private boolean checkAndFlagExplicitConstructorCallInCanonicalConstructor(AbstractMethodDeclaration methodDecl, BlockScope scope) { - - if (methodDecl.binding == null || methodDecl.binding.declaringClass == null - || !methodDecl.binding.declaringClass.isRecord()) - return true; - boolean isInsideCCD = methodDecl instanceof CompactConstructorDeclaration; - if (this.accessMode != ExplicitConstructorCall.ImplicitSuper) { - if (isInsideCCD) - scope.problemReporter().recordCompactConstructorHasExplicitConstructorCall(this); - else - scope.problemReporter().recordCanonicalConstructorHasExplicitConstructorCall(this); - return false; - } - return true; - } - @Override - public void setActualReceiverType(ReferenceBinding receiverType) { - // ignored - } - - @Override - public void setDepth(int depth) { - // ignore for here - } - - @Override - public void setFieldIndex(int depth) { - // ignore for here - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.qualification != null) { - this.qualification.traverse(visitor, scope); - } - if (this.typeArguments != null) { - for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) { - this.typeArguments[i].traverse(visitor, scope); - } - } - if (this.arguments != null) { - for (int i = 0, argumentLength = this.arguments.length; i < argumentLength; i++) - this.arguments[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - // -- interface Invocation - @Override - public MethodBinding binding() { - return this.binding; - } - - @Override - public void registerInferenceContext(ParameterizedGenericMethodBinding method, InferenceContext18 infCtx18) { - // Nothing to do. - } - - @Override - public void registerResult(TypeBinding targetType, MethodBinding method) { - // Nothing to do. - } - - @Override - public InferenceContext18 getInferenceContext(ParameterizedMethodBinding method) { - return null; - } - - @Override - public void cleanUpInferenceContexts() { - // Nothing to do. - } - - @Override - public Expression[] arguments() { - return this.arguments; - } - // -- interface InvocationSite: -- - @Override - public InferenceContext18 freshInferenceContext(Scope scope) { - return new InferenceContext18(scope, this.arguments, this, null); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExportsStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExportsStatement.java deleted file mode 100644 index ee83b1f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExportsStatement.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -public class ExportsStatement extends PackageVisibilityStatement { - - public ExportsStatement(ImportReference pkgRef) { - this(pkgRef, null); - } - public ExportsStatement(ImportReference pkgRef, ModuleReference[] targets) { - super(pkgRef, targets); - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - printIndent(indent, output); - output.append("exports "); //$NON-NLS-1$ - super.print(0, output); - output.append(";"); //$NON-NLS-1$ - return output; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Expression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Expression.java deleted file mode 100644 index b0703ae..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Expression.java +++ /dev/null @@ -1,1399 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 292478 - Report potentially null across variable assignment - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 400761 - [compiler][null] null may be return as boolean without a diagnostic - * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 426792 - [1.8][inference][impl] generify new type inference engine - * Bug 423505 - [1.8] Implement "18.5.4 More Specific Method Inference" - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 426996 - [1.8][inference] try to avoid method Expression.unresolve()? - * Bug 428274 - [1.8] [compiler] Cannot cast from Number to double - * Bug 428352 - [1.8][compiler] Resolution errors don't always surface - * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression - * Lars Vogel - Contributions for - * Bug 473178 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -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.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; -import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement; -import org.eclipse.jdt.internal.compiler.util.Messages; - -public abstract class Expression extends Statement { - - public Constant constant; - public int statementEnd = -1; - - //Some expression may not be used - from a java semantic point - //of view only - as statements. Other may. In order to avoid the creation - //of wrappers around expression in order to tune them as expression - //Expression is a subclass of Statement. See the message isValidJavaStatement() - - public int implicitConversion; - public TypeBinding resolvedType; - - public static Expression [] NO_EXPRESSIONS = new Expression[0]; - - -public static final boolean isConstantValueRepresentable(Constant constant, int constantTypeID, int targetTypeID) { - //true if there is no loss of precision while casting. - // constantTypeID == constant.typeID - if (targetTypeID == constantTypeID) - return true; - switch (targetTypeID) { - case T_char : - switch (constantTypeID) { - case T_char : - return true; - case T_double : - return constant.doubleValue() == constant.charValue(); - case T_float : - return constant.floatValue() == constant.charValue(); - case T_int : - return constant.intValue() == constant.charValue(); - case T_short : - return constant.shortValue() == constant.charValue(); - case T_byte : - return constant.byteValue() == constant.charValue(); - case T_long : - return constant.longValue() == constant.charValue(); - default : - return false;//boolean - } - - case T_float : - switch (constantTypeID) { - case T_char : - return constant.charValue() == constant.floatValue(); - case T_double : - return constant.doubleValue() == constant.floatValue(); - case T_float : - return true; - case T_int : - return constant.intValue() == constant.floatValue(); - case T_short : - return constant.shortValue() == constant.floatValue(); - case T_byte : - return constant.byteValue() == constant.floatValue(); - case T_long : - return constant.longValue() == constant.floatValue(); - default : - return false;//boolean - } - - case T_double : - switch (constantTypeID) { - case T_char : - return constant.charValue() == constant.doubleValue(); - case T_double : - return true; - case T_float : - return constant.floatValue() == constant.doubleValue(); - case T_int : - return constant.intValue() == constant.doubleValue(); - case T_short : - return constant.shortValue() == constant.doubleValue(); - case T_byte : - return constant.byteValue() == constant.doubleValue(); - case T_long : - return constant.longValue() == constant.doubleValue(); - default : - return false; //boolean - } - - case T_byte : - switch (constantTypeID) { - case T_char : - return constant.charValue() == constant.byteValue(); - case T_double : - return constant.doubleValue() == constant.byteValue(); - case T_float : - return constant.floatValue() == constant.byteValue(); - case T_int : - return constant.intValue() == constant.byteValue(); - case T_short : - return constant.shortValue() == constant.byteValue(); - case T_byte : - return true; - case T_long : - return constant.longValue() == constant.byteValue(); - default : - return false; //boolean - } - - case T_short : - switch (constantTypeID) { - case T_char : - return constant.charValue() == constant.shortValue(); - case T_double : - return constant.doubleValue() == constant.shortValue(); - case T_float : - return constant.floatValue() == constant.shortValue(); - case T_int : - return constant.intValue() == constant.shortValue(); - case T_short : - return true; - case T_byte : - return constant.byteValue() == constant.shortValue(); - case T_long : - return constant.longValue() == constant.shortValue(); - default : - return false; //boolean - } - - case T_int : - switch (constantTypeID) { - case T_char : - return constant.charValue() == constant.intValue(); - case T_double : - return constant.doubleValue() == constant.intValue(); - case T_float : - return constant.floatValue() == constant.intValue(); - case T_int : - return true; - case T_short : - return constant.shortValue() == constant.intValue(); - case T_byte : - return constant.byteValue() == constant.intValue(); - case T_long : - return constant.longValue() == constant.intValue(); - default : - return false; //boolean - } - - case T_long : - switch (constantTypeID) { - case T_char : - return constant.charValue() == constant.longValue(); - case T_double : - return constant.doubleValue() == constant.longValue(); - case T_float : - return constant.floatValue() == constant.longValue(); - case T_int : - return constant.intValue() == constant.longValue(); - case T_short : - return constant.shortValue() == constant.longValue(); - case T_byte : - return constant.byteValue() == constant.longValue(); - case T_long : - return true; - default : - return false; //boolean - } - - default : - return false; //boolean - } -} - -public Expression() { - super(); -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return flowInfo; -} - -/** - * More sophisticated for of the flow analysis used for analyzing expressions, and be able to optimize out - * portions of expressions where no actual value is required. - * - * @return The state of initialization after the analysis of the current expression - */ -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { - return analyseCode(currentScope, flowContext, flowInfo); -} - -/** - * Back-propagation of flow info: before analysing a branch where a given condition is known to hold true/false respectively, - * ask the condition to contribute its information to the given flowInfo. - * @param flowInfo the info to be used for analysing the branch - * @param result condition result that would cause entering the branch - */ -protected void updateFlowOnBooleanResult(FlowInfo flowInfo, boolean result) { - // nop -} - -/** - * Returns false if cast is not legal. - */ -public final boolean checkCastTypesCompatibility(Scope scope, TypeBinding castType, TypeBinding expressionType, Expression expression, boolean useAutoBoxing) { - // see specifications 5.5 - // handle errors and process constant when needed - - // if either one of the type is null ==> - // some error has been already reported some where ==> - // we then do not report an obvious-cascade-error. - - if (castType == null || expressionType == null) return true; - - // identity conversion cannot be performed upfront, due to side-effects - // like constant propagation - boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; - boolean use17specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_7; - useAutoBoxing &= use15specifics; - if (castType.isBaseType()) { - if (expressionType.isBaseType()) { - if (TypeBinding.equalsEquals(expressionType, castType)) { - if (expression != null) { - this.constant = expression.constant; //use the same constant - } - tagAsUnnecessaryCast(scope, castType); - return true; - } - boolean necessary = false; - if (expressionType.isCompatibleWith(castType) - || (necessary = BaseTypeBinding.isNarrowing(castType.id, expressionType.id))) { - if (expression != null) { - expression.implicitConversion = (castType.id << 4) + expressionType.id; - if (expression.constant != Constant.NotAConstant) { - this.constant = expression.constant.castTo(expression.implicitConversion); - } - } - if (!necessary) tagAsUnnecessaryCast(scope, castType); - return true; - - } - } else if (useAutoBoxing && use17specifics && castType.isPrimitiveType() && expressionType instanceof ReferenceBinding && - !expressionType.isBoxedPrimitiveType() && checkCastTypesCompatibility(scope, scope.boxing(castType), expressionType, expression, useAutoBoxing)) { - // cast from any reference type (other than boxing types) to base type allowed from 1.7, see JLS $5.5 - // by our own interpretation (in accordance with javac) we reject arays, though. - return true; - } else if (useAutoBoxing - && scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // unboxing - only widening match is allowed - tagAsUnnecessaryCast(scope, castType); - return true; - } - return false; - } else if (useAutoBoxing - && expressionType.isBaseType() - && scope.environment().computeBoxingType(expressionType).isCompatibleWith(castType)) { // boxing - only widening match is allowed - tagAsUnnecessaryCast(scope, castType); - return true; - } - - if (castType.isIntersectionType18()) { - ReferenceBinding [] intersectingTypes = castType.getIntersectingTypes(); - for (int i = 0, length = intersectingTypes.length; i < length; i++) { - if (!checkCastTypesCompatibility(scope, intersectingTypes[i], expressionType, expression, useAutoBoxing)) - return false; - } - return true; - } - - switch(expressionType.kind()) { - case Binding.BASE_TYPE : - //-----------cast to something which is NOT a base type-------------------------- - if (expressionType == TypeBinding.NULL) { - tagAsUnnecessaryCast(scope, castType); - return true; //null is compatible with every thing - } - return false; - - case Binding.ARRAY_TYPE : - if (TypeBinding.equalsEquals(castType, expressionType)) { - tagAsUnnecessaryCast(scope, castType); - return true; // identity conversion - } - switch (castType.kind()) { - case Binding.ARRAY_TYPE : - // ( ARRAY ) ARRAY - TypeBinding castElementType = ((ArrayBinding) castType).elementsType(); - TypeBinding exprElementType = ((ArrayBinding) expressionType).elementsType(); - if (exprElementType.isBaseType() || castElementType.isBaseType()) { - if (TypeBinding.equalsEquals(castElementType, exprElementType)) { - tagAsNeedCheckCast(); - return true; - } - return false; - } - // recurse on array type elements - return checkCastTypesCompatibility(scope, castElementType, exprElementType, expression, useAutoBoxing); - - case Binding.TYPE_PARAMETER : - // ( TYPE_PARAMETER ) ARRAY - TypeBinding match = expressionType.findSuperTypeOriginatingFrom(castType); - if (match == null) { - checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true); - } - for (TypeBinding bound : ((TypeVariableBinding) castType).allUpperBounds()) { - if (!checkCastTypesCompatibility(scope, bound, expressionType, expression, useAutoBoxing)) - return false; - } - return true; - - default: - // ( CLASS/INTERFACE ) ARRAY - switch (castType.id) { - case T_JavaLangCloneable : - case T_JavaIoSerializable : - tagAsNeedCheckCast(); - return true; - case T_JavaLangObject : - tagAsUnnecessaryCast(scope, castType); - return true; - default : - return false; - } - } - - case Binding.TYPE_PARAMETER : - TypeBinding match = expressionType.findSuperTypeOriginatingFrom(castType); - if (match == null) { - // recursively on the type variable upper bounds - if (castType instanceof TypeVariableBinding) { - // prefer iterating over required types, not provides - for (TypeBinding bound : ((TypeVariableBinding)castType).allUpperBounds()) { - if (!checkCastTypesCompatibility(scope, bound, expressionType, expression, useAutoBoxing)) - return false; - } - } else { - for (TypeBinding bound : ((TypeVariableBinding)expressionType).allUpperBounds()) { - if (!checkCastTypesCompatibility(scope, castType, bound, expression, useAutoBoxing)) - return false; - } - } - } - // if no incompatibility found: - return checkUnsafeCast(scope, castType, expressionType, match, match == null); - - case Binding.WILDCARD_TYPE : - case Binding.INTERSECTION_TYPE : - match = expressionType.findSuperTypeOriginatingFrom(castType); - if (match != null) { - return checkUnsafeCast(scope, castType, expressionType, match, false); - } - TypeBinding bound = ((WildcardBinding)expressionType).bound; - if (bound == null) bound = scope.getJavaLangObject(); - // recursively on the type variable upper bound - return checkCastTypesCompatibility(scope, castType, bound, expression, useAutoBoxing); - case Binding.INTERSECTION_TYPE18: - ReferenceBinding [] intersectingTypes = expressionType.getIntersectingTypes(); - for (int i = 0, length = intersectingTypes.length; i < length; i++) { - if (checkCastTypesCompatibility(scope, castType, intersectingTypes[i], expression, useAutoBoxing)) - return true; - } - return false; - default: - if (expressionType.isInterface()) { - switch (castType.kind()) { - case Binding.ARRAY_TYPE : - // ( ARRAY ) INTERFACE - switch (expressionType.id) { - case T_JavaLangCloneable : - case T_JavaIoSerializable : - tagAsNeedCheckCast(); - return true; - default : - return false; - } - - case Binding.TYPE_PARAMETER : - // ( INTERFACE ) TYPE_PARAMETER - match = expressionType.findSuperTypeOriginatingFrom(castType); - if (match == null) { - checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true); - } - // recursively on the type variable upper bounds - for (TypeBinding upperBound : ((TypeVariableBinding)castType).allUpperBounds()) { - if (!checkCastTypesCompatibility(scope, upperBound, expressionType, expression, useAutoBoxing)) - return false; - } - return true; - - default : - if (castType.isInterface()) { - // ( INTERFACE ) INTERFACE - ReferenceBinding interfaceType = (ReferenceBinding) expressionType; - match = interfaceType.findSuperTypeOriginatingFrom(castType); - if (match != null) { - return checkUnsafeCast(scope, castType, interfaceType, match, false); - } - tagAsNeedCheckCast(); - match = castType.findSuperTypeOriginatingFrom(interfaceType); - if (match != null) { - return checkUnsafeCast(scope, castType, interfaceType, match, true); - } - if (use15specifics) { - checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true); - // ensure there is no collision between both interfaces: i.e. I1 extends List, I2 extends List - if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_7) { - if (interfaceType.hasIncompatibleSuperType((ReferenceBinding) castType)) { - return false; - } - } else if (!castType.isRawType() && interfaceType.hasIncompatibleSuperType((ReferenceBinding) castType)) { - return false; - } - } else { - // pre1.5 semantics - no covariance allowed (even if 1.5 compliant, but 1.4 source) - // look at original methods rather than the parameterized variants at 1.4 to detect - // covariance. Otherwise when confronted with one raw type and one parameterized type, - // we could mistakenly detect covariance and scream foul. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=332744 - MethodBinding[] castTypeMethods = getAllOriginalInheritedMethods((ReferenceBinding) castType); - MethodBinding[] expressionTypeMethods = getAllOriginalInheritedMethods((ReferenceBinding) expressionType); - int exprMethodsLength = expressionTypeMethods.length; - for (int i = 0, castMethodsLength = castTypeMethods.length; i < castMethodsLength; i++) { - for (int j = 0; j < exprMethodsLength; j++) { - if ((TypeBinding.notEquals(castTypeMethods[i].returnType, expressionTypeMethods[j].returnType)) - && (CharOperation.equals(castTypeMethods[i].selector, expressionTypeMethods[j].selector)) - && castTypeMethods[i].areParametersEqual(expressionTypeMethods[j])) { - return false; - - } - } - } - } - return true; - } else { - // ( CLASS ) INTERFACE - if (castType.id == TypeIds.T_JavaLangObject) { // no runtime error - tagAsUnnecessaryCast(scope, castType); - return true; - } - // can only be a downcast - tagAsNeedCheckCast(); - match = castType.findSuperTypeOriginatingFrom(expressionType); - if (match != null) { - return checkUnsafeCast(scope, castType, expressionType, match, true); - } - if (((ReferenceBinding) castType).isFinal()) { - // no subclass for castType, thus compile-time check is invalid - return false; - } - if (use15specifics) { - checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true); - // ensure there is no collision between both interfaces: i.e. I1 extends List, I2 extends List - if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_7) { - if (((ReferenceBinding)castType).hasIncompatibleSuperType((ReferenceBinding) expressionType)) { - return false; - } - } else if (!castType.isRawType() && ((ReferenceBinding)castType).hasIncompatibleSuperType((ReferenceBinding) expressionType)) { - return false; - } - } - return true; - } - } - } else { - switch (castType.kind()) { - case Binding.ARRAY_TYPE : - // ( ARRAY ) CLASS - if (expressionType.id == TypeIds.T_JavaLangObject) { // potential runtime error - if (use15specifics) checkUnsafeCast(scope, castType, expressionType, expressionType, true); - tagAsNeedCheckCast(); - return true; - } - return false; - - case Binding.TYPE_PARAMETER : - // ( TYPE_PARAMETER ) CLASS - match = expressionType.findSuperTypeOriginatingFrom(castType); - if (match == null) { - checkUnsafeCast(scope, castType, expressionType, null, true); - } - // recursively on the type variable upper bounds - for (TypeBinding upperBound : ((TypeVariableBinding)castType).allUpperBounds()) { - if (!checkCastTypesCompatibility(scope, upperBound, expressionType, expression, useAutoBoxing)) - return false; - } - return true; - - default : - if (castType.isInterface()) { - // ( INTERFACE ) CLASS - ReferenceBinding refExprType = (ReferenceBinding) expressionType; - match = refExprType.findSuperTypeOriginatingFrom(castType); - if (match != null) { - return checkUnsafeCast(scope, castType, expressionType, match, false); - } - // unless final a subclass may implement the interface ==> no check at compile time - if (refExprType.isFinal()) { - return false; - } - tagAsNeedCheckCast(); - match = castType.findSuperTypeOriginatingFrom(expressionType); - if (match != null) { - return checkUnsafeCast(scope, castType, expressionType, match, true); - } - if (use15specifics) { - checkUnsafeCast(scope, castType, expressionType, null /*no match*/, true); - // ensure there is no collision between both interfaces: i.e. I1 extends List, I2 extends List - if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_7) { - if (refExprType.hasIncompatibleSuperType((ReferenceBinding) castType)) { - return false; - } - } else if (!castType.isRawType() && refExprType.hasIncompatibleSuperType((ReferenceBinding) castType)) { - return false; - } - } - return true; - } else { - // ( CLASS ) CLASS - match = expressionType.findSuperTypeOriginatingFrom(castType); - if (match != null) { - if (expression != null && castType.id == TypeIds.T_JavaLangString) this.constant = expression.constant; // (String) cst is still a constant - return checkUnsafeCast(scope, castType, expressionType, match, false); - } - match = castType.findSuperTypeOriginatingFrom(expressionType); - if (match != null) { - tagAsNeedCheckCast(); - return checkUnsafeCast(scope, castType, expressionType, match, true); - } - return false; - } - } - } - } -} - -/** - * Check this expression against potential NPEs, which may occur: - *
      - *
    • if the expression is the receiver in a field access, qualified allocation, array reference or message send - * incl. implicit message sends like it happens for the collection in a foreach statement.
    • - *
    • if the expression is subject to unboxing
    • - *
    • if the expression is the exception in a throw statement
    • - *
    - * If a risk of NPE is detected report it to the context. - * If the expression denotes a local variable, mark it as checked, which affects the flow info. - * @param scope the scope of the analysis - * @param flowContext the current flow context - * @param flowInfo the upstream flow info; caveat: may get modified - * @param ttlForFieldCheck if this is a reference to a field we will mark that field as nonnull for the specified timeToLive - * @return could this expression be checked by the current implementation? - */ -public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - boolean isNullable = false; - if (this.resolvedType != null) { - // 1. priority: @NonNull - if ((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0) { - return true; // no danger - } else if ((this.resolvedType.tagBits & TagBits.AnnotationNullable) != 0) { - isNullable = true; - } - } - LocalVariableBinding local = localVariableBinding(); - if (local != null && - (local.type.tagBits & TagBits.IsBaseType) == 0) { - // 2. priority: local with flow analysis (via the FlowContext) - if ((this.bits & ASTNode.IsNonNull) == 0) { - flowContext.recordUsingNullReference(scope, local, this, - FlowContext.MAY_NULL, flowInfo); - // account for possible NPE: - if (!flowInfo.isDefinitelyNonNull(local)) { - flowContext.recordAbruptExit(); - } - } - flowInfo.markAsComparedEqualToNonNull(local); - // from thereon it is set - flowContext.markFinallyNullStatus(local, FlowInfo.NON_NULL); - return true; - } else if (isNullable) { - // 3. priority: @Nullable without a local - scope.problemReporter().dereferencingNullableExpression(this); - return true; - } - return false; // not checked -} -public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) { - return checkNPE(scope, flowContext, flowInfo, 0); // default: don't mark field references as checked for null -} - -/** If this expression requires unboxing check if that operation can throw NPE. */ -protected void checkNPEbyUnboxing(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) { - int status; - if ((this.implicitConversion & UNBOXING) != 0 - && (this.bits & ASTNode.IsNonNull) == 0 - && (status = nullStatus(flowInfo, flowContext)) != FlowInfo.NON_NULL) - { - flowContext.recordUnboxing(scope, this, status, flowInfo); - } -} - -public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { - if (TypeBinding.equalsEquals(match, castType)) { - if (!isNarrowing) tagAsUnnecessaryCast(scope, castType); - return true; - } - if (match != null && (!castType.isReifiable() || !expressionType.isReifiable())) { - if(isNarrowing - ? match.isProvablyDistinct(expressionType) - : castType.isProvablyDistinct(match)) { - return false; - } - } - if (!isNarrowing) tagAsUnnecessaryCast(scope, castType); - return true; -} - -/** - * Base types need that the widening is explicitly done by the compiler using some bytecode like i2f. - * Also check unsafe type operations. - */ -public void computeConversion(Scope scope, TypeBinding runtimeType, TypeBinding compileTimeType) { - if (runtimeType == null || compileTimeType == null) - return; - if (this.implicitConversion != 0) return; // already set independently - - // it is possible for a Byte to be unboxed to a byte & then converted to an int - // but it is not possible for a byte to become Byte & then assigned to an Integer, - // or to become an int before boxed into an Integer - if (runtimeType != TypeBinding.NULL && runtimeType.isBaseType()) { - if (!compileTimeType.isBaseType()) { - TypeBinding unboxedType = scope.environment().computeBoxingType(compileTimeType); - this.implicitConversion = TypeIds.UNBOXING; - scope.problemReporter().autoboxing(this, compileTimeType, runtimeType); - compileTimeType = unboxedType; - } - } else if (compileTimeType != TypeBinding.NULL && compileTimeType.isBaseType()) { - TypeBinding boxedType = scope.environment().computeBoxingType(runtimeType); - if (TypeBinding.equalsEquals(boxedType, runtimeType)) // Object o = 12; - boxedType = compileTimeType; - if (boxedType.id > TypeIds.T_JavaLangBoolean) { // (Comparable & Serializable) 0 - boxedType = compileTimeType; - } - this.implicitConversion = TypeIds.BOXING | (boxedType.id << 4) + compileTimeType.id; - scope.problemReporter().autoboxing(this, compileTimeType, scope.environment().computeBoxingType(boxedType)); - return; - } else if (this.constant != Constant.NotAConstant && this.constant.typeID() != TypeIds.T_JavaLangString) { - this.implicitConversion = TypeIds.BOXING; - return; - } - int compileTimeTypeID, runtimeTypeID; - if ((compileTimeTypeID = compileTimeType.id) >= TypeIds.T_LastWellKnownTypeId) { // e.g. ? extends String ==> String (103227); >= TypeIds.T_LastWellKnownTypeId implies TypeIds.NoId - compileTimeTypeID = compileTimeType.erasure().id == TypeIds.T_JavaLangString ? TypeIds.T_JavaLangString : TypeIds.T_JavaLangObject; - } else if (runtimeType.isPrimitiveType() && compileTimeType instanceof ReferenceBinding && !compileTimeType.isBoxedPrimitiveType()) { - compileTimeTypeID = TypeIds.T_JavaLangObject; // treatment is the same as for jlO. - } - - switch (runtimeTypeID = runtimeType.id) { - case T_byte : - case T_short : - case T_char : - if (compileTimeTypeID == TypeIds.T_JavaLangObject) { - this.implicitConversion |= (runtimeTypeID << 4) + compileTimeTypeID; - } else { - this.implicitConversion |= (TypeIds.T_int << 4) + compileTimeTypeID; - } - break; - case T_JavaLangString : - case T_float : - case T_boolean : - case T_double : - case T_int : //implicitConversion may result in i2i which will result in NO code gen - case T_long : - this.implicitConversion |= (runtimeTypeID << 4) + compileTimeTypeID; - break; - default : // regular object ref -// if (compileTimeType.isRawType() && runtimeTimeType.isBoundParameterizedType()) { -// scope.problemReporter().unsafeRawExpression(this, compileTimeType, runtimeTimeType); -// } - } -} - -public static int computeNullStatus(int status, int combinedStatus) { - if ((combinedStatus & (FlowInfo.NULL|FlowInfo.POTENTIALLY_NULL)) != 0) - status |= FlowInfo.POTENTIALLY_NULL; - if ((combinedStatus & (FlowInfo.NON_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0) - status |= FlowInfo.POTENTIALLY_NON_NULL; - if ((combinedStatus & (FlowInfo.UNKNOWN|FlowInfo.POTENTIALLY_UNKNOWN)) != 0) - status |= FlowInfo.POTENTIALLY_UNKNOWN; - return status; -} -/** - * Expression statements are plain expressions, however they generate like - * normal expressions with no value required. - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) { - return; - } - generateCode(currentScope, codeStream, false); -} - -/** - * Every expression is responsible for generating its implicit conversion when necessary. - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - if (this.constant != Constant.NotAConstant) { - // generate a constant expression - int pc = codeStream.position; - codeStream.generateConstant(this.constant, this.implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } else { - // actual non-constant code generation - throw new ShouldNotImplement(Messages.ast_missingCode); - } -} -public void addPatternVariables(BlockScope scope, CodeStream codeStream) { - // Nothing by default -} -public LocalDeclaration getPatternVariable() { - return null; -} - -/** - * Default generation of a boolean value - */ -public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - // a label valued to nil means: by default we fall through the case... - // both nil means we leave the value on the stack - - Constant cst = optimizedBooleanConstant(); - generateCode(currentScope, codeStream, valueRequired && cst == Constant.NotAConstant); - if ((cst != Constant.NotAConstant) && (cst.typeID() == TypeIds.T_boolean)) { - int pc = codeStream.position; - if (cst.booleanValue() == true) { - // constant == true - if (valueRequired) { - if (falseLabel == null) { - // implicit falling through the FALSE case - if (trueLabel != null) { - codeStream.goto_(trueLabel); - } - } - } - } else { - if (valueRequired) { - if (falseLabel != null) { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.goto_(falseLabel); - } - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - // branching - int position = codeStream.position; - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // Implicit falling through the FALSE case - codeStream.ifne(trueLabel); - } - } else { - if (trueLabel == null) { - // Implicit falling through the TRUE case - codeStream.ifeq(falseLabel); - } else { - // No implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(position, this.sourceEnd); -} - -/* Optimized (java) code generation for string concatenations that involve StringBuffer - * creation: going through this path means that there is no need for a new StringBuffer - * creation, further operands should rather be only appended to the current one. - * By default: no optimization. - */ -public void generateOptimizedStringConcatenation(BlockScope blockScope, CodeStream codeStream, int typeID) { - if (typeID == TypeIds.T_JavaLangString && this.constant != Constant.NotAConstant && this.constant.stringValue().length() == 0) { - return; // optimize str + "" - } - generateCode(blockScope, codeStream, true); - codeStream.invokeStringConcatenationAppendForType(typeID); -} - -/* Optimized (java) code generation for string concatenations that involve StringBuffer - * creation: going through this path means that there is no need for a new StringBuffer - * creation, further operands should rather be only appended to the current one. - */ -public void generateOptimizedStringConcatenationCreation(BlockScope blockScope, CodeStream codeStream, int typeID) { - codeStream.newStringContatenation(); - codeStream.dup(); - switch (typeID) { - case T_JavaLangObject : - case T_undefined : - // in the case the runtime value of valueOf(Object) returns null, we have to use append(Object) instead of directly valueOf(Object) - // append(Object) returns append(valueOf(Object)), which means that the null case is handled by the next case. - codeStream.invokeStringConcatenationDefaultConstructor(); - generateCode(blockScope, codeStream, true); - codeStream.invokeStringConcatenationAppendForType(TypeIds.T_JavaLangObject); - return; - case T_JavaLangString : - case T_null : - if (this.constant != Constant.NotAConstant) { - String stringValue = this.constant.stringValue(); - if (stringValue.length() == 0) { // optimize ""+ - codeStream.invokeStringConcatenationDefaultConstructor(); - return; - } - codeStream.ldc(stringValue); - } else { - // null case is not a constant - generateCode(blockScope, codeStream, true); - codeStream.invokeStringValueOf(TypeIds.T_JavaLangObject); - } - break; - default : - generateCode(blockScope, codeStream, true); - codeStream.invokeStringValueOf(typeID); - } - codeStream.invokeStringConcatenationStringConstructor(); -} -private void addArgumentToRecipe(BlockScope blockScope, CodeStream codeStream, StringBuilder recipe, TypeBinding argType, List args) { - recipe.append(STRING_CONCAT_MARKER_1); - args.add(argType); - if (args.size() > 190) { - // StringConcatFactory#makeConcatWithConstants() can take only 200 arguments - // Commit whatever we have accumulated so far - // Get the result pushed to the stack and to be used as an operand - // for the subsequent concat operation - codeStream.invokeDynamicForStringConcat(recipe, args); - // Clear the arguments for the next batch - args.clear(); - recipe.delete(0, recipe.length()); - recipe.append(TypeConstants.STRING_CONCAT_MARKER_1); - args.add(blockScope.getJavaLangString()); - // We popped 190 and adding 1 for the invokeDynamic - codeStream.stackDepth -= 189; - } -} -public void buildStringForConcatation(BlockScope blockScope, CodeStream codeStream, int typeID, StringBuilder recipe, List argTypes) { - if (this.constant == Constant.NotAConstant) { - switch (typeID) { - case T_JavaLangString : - case TypeIds.T_int : - case TypeIds.T_byte : - case TypeIds.T_short : - case TypeIds.T_long : - case TypeIds.T_float : - case TypeIds.T_double : - case TypeIds.T_char : - case TypeIds.T_boolean : - generateCode(blockScope, codeStream, true); - addArgumentToRecipe(blockScope, codeStream, recipe, this.resolvedType, argTypes); - break; - default : - if (this.resolvedType.id == TypeIds.T_null) { - codeStream.aconst_null(); - } else { - generateCode(blockScope, codeStream, true); - codeStream.invokeStringValueOf(typeID); - } - addArgumentToRecipe(blockScope, codeStream, recipe, blockScope.getJavaLangString(), argTypes); - break; - } - } else { - // StringLiteral and CharLiteral may contain special characters - if (this.constant.stringValue().indexOf('\u0001') != -1 || this.constant.stringValue().indexOf('\u0002') != -1) { - codeStream.ldc(this.constant.stringValue()); - addArgumentToRecipe(blockScope, codeStream, recipe, blockScope.getJavaLangString(), argTypes); - } else { - recipe.append(this.constant.stringValue()); - } - } -} -private MethodBinding[] getAllOriginalInheritedMethods(ReferenceBinding binding) { - ArrayList collector = new ArrayList<>(); - getAllInheritedMethods0(binding, collector); - for (int i = 0, len = collector.size(); i < len; i++) { - collector.set(i, collector.get(i).original()); - } - return collector.toArray(new MethodBinding[collector.size()]); -} - -private void getAllInheritedMethods0(ReferenceBinding binding, ArrayList collector) { - if (!binding.isInterface()) return; - MethodBinding[] methodBindings = binding.methods(); - for (int i = 0, max = methodBindings.length; i < max; i++) { - collector.add(methodBindings[i]); - } - ReferenceBinding[] superInterfaces = binding.superInterfaces(); - for (int i = 0, max = superInterfaces.length; i < max; i++) { - getAllInheritedMethods0(superInterfaces[i], collector); - } -} - -public static Binding getDirectBinding(Expression someExpression) { - if ((someExpression.bits & ASTNode.IgnoreNoEffectAssignCheck) != 0) { - return null; - } - if (someExpression instanceof SingleNameReference) { - return ((SingleNameReference)someExpression).binding; - } else if (someExpression instanceof FieldReference) { - FieldReference fieldRef = (FieldReference)someExpression; - if (fieldRef.receiver.isThis() && !(fieldRef.receiver instanceof QualifiedThisReference)) { - return fieldRef.binding; - } - } else if (someExpression instanceof Assignment) { - Expression lhs = ((Assignment)someExpression).lhs; - if ((lhs.bits & ASTNode.IsStrictlyAssigned) != 0) { - // i = i = ...; // eq to int i = ...; - return getDirectBinding (((Assignment)someExpression).lhs); - } else if (someExpression instanceof PrefixExpression) { - // i = i++; // eq to ++i; - return getDirectBinding (((Assignment)someExpression).lhs); - } - } else if (someExpression instanceof QualifiedNameReference) { - QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) someExpression; - if (qualifiedNameReference.indexOfFirstFieldBinding != 1 - && qualifiedNameReference.otherBindings == null) { - // case where a static field is retrieved using ClassName.fieldname - return qualifiedNameReference.binding; - } - } else if (someExpression.isThis()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=276741 - return someExpression.resolvedType; - } -// } else if (someExpression instanceof PostfixExpression) { // recurse for postfix: i++ --> i -// // note: "b = b++" is equivalent to doing nothing, not to "b++" -// return getDirectBinding(((PostfixExpression) someExpression).lhs); - return null; -} - -public boolean isCompactableOperation() { - return false; -} - -//Return true if the conversion is done AUTOMATICALLY by the vm -//while the javaVM is an int based-machine, thus for example pushing -//a byte onto the stack , will automatically create an int on the stack -//(this request some work d be done by the VM on signed numbers) -public boolean isConstantValueOfTypeAssignableToType(TypeBinding constantType, TypeBinding targetType) { - - if (this.constant == Constant.NotAConstant) - return false; - if (TypeBinding.equalsEquals(constantType, targetType)) - return true; - //No free assignment conversion from anything but to integral ones. - if (BaseTypeBinding.isWidening(TypeIds.T_int, constantType.id) - && (BaseTypeBinding.isNarrowing(targetType.id, TypeIds.T_int))) { - //use current explicit conversion in order to get some new value to compare with current one - return isConstantValueRepresentable(this.constant, constantType.id, targetType.id); - } - return false; -} - -public boolean isTypeReference() { - return false; -} - -/** - * Returns the local variable referenced by this node. Can be a direct reference (SingleNameReference) - * or thru a cast expression etc... - */ -public LocalVariableBinding localVariableBinding() { - return null; -} - -/** - * Mark this expression as being non null, per a specific tag in the - * source code. - */ -// this is no more called for now, waiting for inter procedural null reference analysis -public void markAsNonNull() { - this.bits |= ASTNode.IsNonNull; -} - -public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - // many kinds of expression need no analysis / are always non-null, make it the default: - return FlowInfo.NON_NULL; -} - -/** - * Constant usable for bytecode pattern optimizations, but cannot be inlined - * since it is not strictly equivalent to the definition of constant expressions. - * In particular, some side-effects may be required to occur (only the end value - * is known). - * @return Constant known to be of boolean type - */ -public Constant optimizedBooleanConstant() { - return this.constant; -} - -public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) { - return true; -} -/** - * Returns the type of the expression after required implicit conversions. When expression type gets promoted - * or inserted a generic cast, the converted type will differ from the resolved type (surface side-effects from - * #computeConversion(...)). - * @return the type after implicit conversion - */ -public TypeBinding postConversionType(Scope scope) { - TypeBinding convertedType = this.resolvedType; - int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; - switch (runtimeType) { - case T_boolean : - convertedType = TypeBinding.BOOLEAN; - break; - case T_byte : - convertedType = TypeBinding.BYTE; - break; - case T_short : - convertedType = TypeBinding.SHORT; - break; - case T_char : - convertedType = TypeBinding.CHAR; - break; - case T_int : - convertedType = TypeBinding.INT; - break; - case T_float : - convertedType = TypeBinding.FLOAT; - break; - case T_long : - convertedType = TypeBinding.LONG; - break; - case T_double : - convertedType = TypeBinding.DOUBLE; - break; - default : - } - if ((this.implicitConversion & TypeIds.BOXING) != 0) { - convertedType = scope.environment().computeBoxingType(convertedType); - } - return convertedType; -} - -@Override -public StringBuilder print(int indent, StringBuilder output) { - printIndent(indent, output); - return printExpression(indent, output); -} - -public abstract StringBuilder printExpression(int indent, StringBuilder output); - -@Override -public StringBuilder printStatement(int indent, StringBuilder output) { - return print(indent, output).append(";"); //$NON-NLS-1$ -} - -@Override -public void resolve(BlockScope scope) { - // drops the returning expression's type whatever the type is. - this.resolveType(scope); - return; -} -@Override -public TypeBinding resolveExpressionType(BlockScope scope) { - return resolveType(scope); -} - -public TypeBinding resolveTypeWithBindings(LocalVariableBinding[] bindings, BlockScope scope) { - scope.include(bindings); - try { - return this.resolveType(scope); - } finally { - scope.exclude(bindings); - } -} - -public TypeBinding resolveTypeExpectingWithBindings(LocalVariableBinding[] bindings, BlockScope scope, TypeBinding expectedType) { - scope.include(bindings); - try { - return this.resolveTypeExpecting(scope, expectedType); - } finally { - scope.exclude(bindings); - } -} - -/** - * Resolve the type of this expression in the context of a blockScope - * - * @return - * Return the actual type of this expression after resolution - */ -public TypeBinding resolveType(BlockScope scope) { - // by default... subclasses should implement a better TB if required. - return null; -} - -/** - * Resolve the type of this expression in the context of a classScope - * - * @return - * Return the actual type of this expression after resolution - */ -public TypeBinding resolveType(ClassScope scope) { - // by default... subclasses should implement a better TB if required. - return null; -} - -public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) { - setExpectedType(expectedType); // needed in case of generic method invocation - TypeBinding expressionType = this.resolveType(scope); - if (expressionType == null) return null; - if (TypeBinding.equalsEquals(expressionType, expectedType)) return expressionType; - - if (!expressionType.isCompatibleWith(expectedType)) { - if (scope.isBoxingCompatibleWith(expressionType, expectedType)) { - computeConversion(scope, expectedType, expressionType); - } else { - scope.problemReporter().typeMismatchError(expressionType, expectedType, this, null); - return null; - } - } - return expressionType; -} - -public Expression resolveExpressionExpecting(TypeBinding targetType, Scope scope, InferenceContext18 context) { - return this; // subclasses should implement for a better resolved expression if required. -} - -/** - * Returns true if the receiver is forced to be of raw type either to satisfy the contract imposed - * by a super type or because it *is* raw and the current type has no control over it (i.e the rawness - * originates from some other file.) - */ -public boolean forcedToBeRaw(ReferenceContext referenceContext) { - if (this instanceof NameReference) { - final Binding receiverBinding = ((NameReference) this).binding; - if (receiverBinding.isParameter() && (((LocalVariableBinding) receiverBinding).tagBits & TagBits.ForcedToBeRawType) != 0) { - return true; // parameter is forced to be raw since super method uses raw types. - } else if (receiverBinding instanceof FieldBinding) { - FieldBinding field = (FieldBinding) receiverBinding; - if (field.type.isRawType()) { - if (referenceContext instanceof AbstractMethodDeclaration) { - AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration) referenceContext; - ReferenceBinding declaringClass = methodDecl.binding != null - ? methodDecl.binding.declaringClass - : methodDecl.scope.enclosingReceiverType(); - if (TypeBinding.notEquals(field.declaringClass, declaringClass)) { // inherited raw field, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=337962 - return true; - } - } else if (referenceContext instanceof TypeDeclaration) { - TypeDeclaration type = (TypeDeclaration) referenceContext; - if (TypeBinding.notEquals(field.declaringClass, type.binding)) { // inherited raw field, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=337962 - return true; - } - } - } - } - } else if (this instanceof MessageSend) { - if (!CharOperation.equals(((MessageSend) this).binding.declaringClass.getFileName(), - referenceContext.compilationResult().getFileName())) { // problem is rooted elsewhere - return true; - } - } else if (this instanceof FieldReference) { - FieldBinding field = ((FieldReference) this).binding; - if (!CharOperation.equals(field.declaringClass.getFileName(), - referenceContext.compilationResult().getFileName())) { // problem is rooted elsewhere - return true; - } - if (field.type.isRawType()) { - if (referenceContext instanceof AbstractMethodDeclaration) { - AbstractMethodDeclaration methodDecl = (AbstractMethodDeclaration) referenceContext; - ReferenceBinding declaringClass = methodDecl.binding != null - ? methodDecl.binding.declaringClass - : methodDecl.scope.enclosingReceiverType(); - if (TypeBinding.notEquals(field.declaringClass, declaringClass)) { // inherited raw field, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=337962 - return true; - } - } else if (referenceContext instanceof TypeDeclaration) { - TypeDeclaration type = (TypeDeclaration) referenceContext; - if (TypeBinding.notEquals(field.declaringClass, type.binding)) { // inherited raw field, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=337962 - return true; - } - } - } - } else if (this instanceof ConditionalExpression) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=337751 - ConditionalExpression ternary = (ConditionalExpression) this; - if (ternary.valueIfTrue.forcedToBeRaw(referenceContext) || ternary.valueIfFalse.forcedToBeRaw(referenceContext)) { - return true; - } - } else if (this instanceof SwitchExpression) { - SwitchExpression se = (SwitchExpression) this; - for (Expression e : se.resultExpressions) { - if (e.forcedToBeRaw(referenceContext)) - return true; - } - } - return false; -} - -/** - * Returns an object which can be used to identify identical JSR sequence targets - * (see TryStatement subroutine codegen) - * or null if not reusable - */ -public Object reusableJSRTarget() { - if (this.constant != Constant.NotAConstant && (this.implicitConversion & TypeIds.BOXING) == 0) { - return this.constant; - } - return null; -} - -/** - * Record the type expectation before this expression is typechecked. - * e.g. String s = foo();, foo() will be tagged as being expected of type String - * Used to trigger proper inference of generic method invocations. - * - * @param expectedType - * The type denoting an expectation in the context of an assignment conversion - */ -public void setExpectedType(TypeBinding expectedType) { - // do nothing by default -} - -public void setExpressionContext(ExpressionContext context) { - // don't care. Subclasses that are poly expressions in specific contexts should listen in and make note. -} - -public boolean isCompatibleWith(TypeBinding left, Scope scope) { - return this.resolvedType != null && this.resolvedType.isCompatibleWith(left, scope); -} - -public boolean isBoxingCompatibleWith(TypeBinding left, Scope scope) { - return this.resolvedType != null && isBoxingCompatible(this.resolvedType, left, this, scope); -} - -public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) { - return s.isCompatibleWith(t, scope); -} - -public boolean isExactMethodReference() { - return false; -} - -/* Answer if the receiver is a poly expression in the prevailing context. Caveat emptor: Some constructs (notably method calls) - cannot answer this question until after resolution is over and may throw unsupported operation exception if queried ahead of - resolution. Default implementation here returns false which is true for vast majority of AST nodes. The ones that are poly - expressions under one or more contexts should override and return suitable value. - */ -public boolean isPolyExpression() throws UnsupportedOperationException { - return false; -} -/** Variant of isPolyExpression() to be used during type inference, when a resolution candidate exists. */ -public boolean isPolyExpression(MethodBinding method) { - return false; -} - - -public void tagAsNeedCheckCast() { - // do nothing by default -} - -/** - * Record the fact a cast expression got detected as being unnecessary. - */ -public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) { - // do nothing by default -} - -public Expression toTypeReference() { - //by default undefined - - //this method is meanly used by the parser in order to transform - //an expression that is used as a type reference in a cast .... - //--appreciate the fact that castExpression and ExpressionWithParenthesis - //--starts with the same pattern..... - - return this; -} - -/** - * Traverse an expression in the context of a blockScope - */ -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - // nothing to do -} - -/** - * Traverse an expression in the context of a classScope - */ -public void traverse(ASTVisitor visitor, ClassScope scope) { - // nothing to do -} -// return true if this expression can be a stand alone statement when terminated with a semicolon -public boolean statementExpression() { - return false; -} -// for switch statement -public boolean isTrulyExpression() { - return true; -} - -/** - * Used on the lhs of an assignment for detecting null spec violation. - * If this expression represents a null-annotated variable return the variable binding, - * otherwise null. - * @param supportTypeAnnotations if true this causes any variable binding to be used - * independent of declaration annotations (for in-depth analysis of type annotations) -*/ -public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotations) { - return null; -} - -public boolean isFunctionalType() { - return false; -} - -/** Returns contained poly expressions, result could be 0, 1 or more (for conditional expression) */ -public Expression [] getPolyExpressions() { - return isPolyExpression() ? new Expression [] { this } : NO_EXPRESSIONS; -} - -public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) { - // A class instance creation expression, a method invocation expression, or an - // expression of a standalone form (§15.2) is potentially compatible with any type. - return true; -} - -protected Constant optimizedNullComparisonConstant() { - return Constant.NotAConstant; -} -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExpressionContext.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExpressionContext.java deleted file mode 100644 index a2754e8..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExpressionContext.java +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013, 2014 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -public enum ExpressionContext { - - /** Assignment context: potential poly-expressions are: method invocations, lambdas, reference expressions, - conditional expressions and allocation expressions. This is the only Java 7 context where target type - influenced evaluation of some expression. - - Context induced by: ReturnStatement, ArrayInitializer, Assignment, FieldDeclaration and LocalDeclaration. - */ - ASSIGNMENT_CONTEXT { - @Override - public String toString() { - return "assignment context"; //$NON-NLS-1$ - } - @Override - public boolean definesTargetType() { - return true; - } - }, - - /** Invocation context: potential poly-expressions are: method invocations, lambdas, reference expressions, - conditional expressions and allocation expressions. At this point, we don't distinguish between strict - and loose invocation contexts - we may have to cross the bridge some day. - - Context induced by: AllocationExpression, QualifiedAllocationExpression, ExplicitConstructorCall, MessageSend - CodeSnippetAllocationExpression and CodeSnippetMessageSend. - */ - INVOCATION_CONTEXT { - @Override - public String toString() { - return "invocation context"; //$NON-NLS-1$ - } - @Override - public boolean definesTargetType() { - return true; - } - }, - - /** Casting context: potential poly-expressions are: lambdas and reference expressions - Context induced by: CastExpression. - */ - CASTING_CONTEXT { - @Override - public String toString() { - return "casting context"; //$NON-NLS-1$ - } - @Override - public boolean definesTargetType() { - return false; - } - }, - - /** Instanceof context: potential poly-expressions are: None - Context induced by: InstanceOfExpression. - */ - INSTANCEOF_CONTEXT { - @Override - public String toString() { - return "instanceof context"; //$NON-NLS-1$ - } - @Override - public boolean definesTargetType() { - return false; - } - }, - - /** Vanilla context (string, numeric): potential poly-expressions are: NONE. This is the nonpoly context in which - expressions get evaluated, unless they feature in one of the above contexts. - */ - VANILLA_CONTEXT { - @Override - public String toString() { - return "vanilla context"; //$NON-NLS-1$ - } - @Override - public boolean definesTargetType() { - return false; - } - }; - - public abstract boolean definesTargetType(); -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java deleted file mode 100644 index b1e46ac..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ExtendedStringLiteral.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; - -public class ExtendedStringLiteral extends StringLiteral { - - protected ExtendedStringLiteral(StringLiteral optionalHead, Object sourcesTail, int start, int end, int lineNumber) { - super(optionalHead, sourcesTail, start, end, lineNumber); - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - return output.append("ExtendedStringLiteral{").append(this.source()).append('}'); //$NON-NLS-1$ - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FakeDefaultLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FakeDefaultLiteral.java deleted file mode 100644 index 7199c2a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FakeDefaultLiteral.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -/** - * Sole purpose of {@link FakeDefaultLiteral} is to appear - * in case 'default' of switch patterns (JEP 406 at the time - * of writing this comment) - */ -public class FakeDefaultLiteral extends MagicLiteral { - - static final char[] source = {'d' , 'e' , 'f' , 'a', 'u', 'l','t'}; - - public FakeDefaultLiteral(int s , int e) { - - super(s,e); - } - - @Override - public void computeConstant() { - - this.constant = Constant.NotAConstant; - } - - @Override - public TypeBinding literalType(BlockScope scope) { - // TODO Change this while implementing flow analysis - return TypeBinding.VOID; - } - - @Override - public char[] source() { - return source; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java deleted file mode 100644 index 5b3250f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FakedTrackingVariable.java +++ /dev/null @@ -1,1566 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011, 2024 GK Software SE and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Stephan Herrmann - initial API and implementation - * Nikolay Metchev (nikolaymetchev@gmail.com) - Contributions for - * bug 411098 - [compiler][resource] Invalid Resource Leak Warning using ternary operator inside try-with-resource - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Function; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; -import org.eclipse.jdt.internal.compiler.flow.FinallyFlowContext; -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.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; -import org.eclipse.jdt.internal.compiler.util.Util; - -/** - * 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 { - - private static final char[] UNASSIGNED_CLOSEABLE_NAME = "".toCharArray(); //$NON-NLS-1$ - private static final char[] UNASSIGNED_CLOSEABLE_NAME_TEMPLATE = "".toCharArray(); //$NON-NLS-1$ - private static final char[] TEMPLATE_ARGUMENT = "{0}".toCharArray(); //$NON-NLS-1$ - - // a call to close() was seen at least on one path: - private static final int CLOSE_SEEN = 1; - // the resource is shared with outside code either by - // - passing as an arg in a method call or - // - obtaining this from a method call or array reference - // Interpret that we may or may not be responsible for closing - private static final int SHARED_WITH_OUTSIDE = 2; - // the resource is likely owned by outside code (owner has responsibility to close): - // - obtained as argument of the current method, or via a field read - // - stored into a field - // - returned as the result of this method - private static final int OWNED_BY_OUTSIDE = 4; - // 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 = 8; - // explicit closing has been reported already against this resource: - private static final int REPORTED_EXPLICIT_CLOSE = 16; - // a location independent potential problem has been reported against this resource: - private static final int REPORTED_POTENTIAL_LEAK = 32; - // a location independent definitive problem has been reported against this resource: - private static final int REPORTED_DEFINITIVE_LEAK = 64; - // a local declarations that acts as the element variable of a foreach loop (should never suggest to use t-w-r): - private static final int FOREACH_ELEMENT_VAR = 128; - // - passed as an effectively final resource in t-w-r JDK 9 and above - private static final int TWR_EFFECTIVELY_FINAL = 256; - public MessageSend acquisition; - - public static boolean TEST_372319 = false; // see https://bugs.eclipse.org/372319 - - /** - * Bitset of {@link #CLOSE_SEEN}, {@link #SHARED_WITH_OUTSIDE}, {@link #OWNED_BY_OUTSIDE}, {@link #CLOSED_IN_NESTED_METHOD}, {@link #REPORTED_EXPLICIT_CLOSE}, {@link #REPORTED_POTENTIAL_LEAK} and {@link #REPORTED_DEFINITIVE_LEAK}. - */ - private int globalClosingState = 0; - - private boolean useAnnotations = false; - - public static final int NOT_OWNED = -2; - public static final int NOT_OWNED_PER_DEFAULT = -1; - public static final int OWNED_PER_DEFAULT = 1; - public static final int OWNED = 2; - - static int owningStateFromTagBits(long owningTagBits, int defaultState) { - if (owningTagBits == TagBits.AnnotationOwning) - return OWNED; - if (owningTagBits == TagBits.AnnotationNotOwning) - return NOT_OWNED; - return defaultState; - } - - /** - * One of {@link #NOT_OWNED}, {@link #NOT_OWNED_PER_DEFAULT}, {@link #OWNED_PER_DEFAULT}, {@link #OWNED}. - * A value of {@code 0} signals unknown state. - */ - public int owningState = 0; - - public LocalVariableBinding originalBinding; // the real local being tracked, can be null for preliminary track vars for allocation expressions - public FieldBinding originalFieldBinding; // when tracking an @Owning field of resource type - - public FakedTrackingVariable innerTracker; // chained tracking variable of a chained (wrapped) resource - public FakedTrackingVariable outerTracker; // inverse of 'innerTracker' - - MethodScope methodScope; // designates the method declaring this variable - - private HashMap recordedLocations; // initially null, ASTNode -> Integer - - // temporary storage while analyzing "res = new Res();": - private ASTNode currentAssignment; // temporarily store the assignment as the location for error reporting - - // if tracking var was allocated from a finally context, record here the flow context of the corresponding try block - private FlowContext tryContext; - // designate the exact scope where this FTV was created - private BlockScope blockScope; - // within try blocks remember in which contexts the local was re-assigned - private Set modificationContexts; - - public FakedTrackingVariable(LocalVariableBinding original, ASTNode location, FlowInfo flowInfo, FlowContext flowContext, int nullStatus, boolean useAnnotations) { - this(original.name, location, original.declaringScope, flowInfo, flowContext, nullStatus, useAnnotations); - this.methodScope = original.declaringScope.methodScope(); - this.originalBinding = original; - } - public FakedTrackingVariable(LocalVariableBinding original, BlockScope scope, ASTNode location, FlowInfo flowInfo, FlowContext flowContext, int nullStatus, boolean useAnnotations) { - this(original.name, location, original.declaringScope, flowInfo, flowContext, nullStatus, useAnnotations); - this.methodScope = original.declaringScope.methodScope(); - this.originalBinding = original; - this.blockScope = scope; - } - public FakedTrackingVariable(FieldBinding original, BlockScope scope, ASTNode location, FlowInfo flowInfo, FlowContext flowContext, int nullStatus, boolean useAnnotations) { - this(original.name, location, scope, flowInfo, flowContext, nullStatus, useAnnotations); - this.originalFieldBinding = original; - this.blockScope = scope; - } - private FakedTrackingVariable(char[] name, ASTNode location, BlockScope scope, FlowInfo flowInfo, FlowContext flowContext, - int nullStatus, boolean useAnnotations) { - super(name, location.sourceStart, location.sourceEnd); - this.type = new SingleTypeReference( - TypeConstants.OBJECT, - ((long)this.sourceStart <<32)+this.sourceEnd); - this.useAnnotations = useAnnotations; - // inside a finally block? - while (flowContext != null) { - if (flowContext instanceof FinallyFlowContext) { - // yes -> connect to the corresponding try block: - this.tryContext = ((FinallyFlowContext) flowContext).tryContext; - break; - } - flowContext = flowContext.parent; - } - resolve(scope); - if (nullStatus != 0) - flowInfo.markNullStatus(this.binding, nullStatus); // mark that this flow has seen the resource - } - - /* Create an unassigned tracking variable while analyzing an allocation expression: */ - private FakedTrackingVariable(BlockScope scope, ASTNode location, FlowInfo flowInfo, int nullStatus) { - super(UNASSIGNED_CLOSEABLE_NAME, location.sourceStart, location.sourceEnd); - this.type = new SingleTypeReference( - TypeConstants.OBJECT, - ((long)this.sourceStart <<32)+this.sourceEnd); - this.methodScope = scope.methodScope(); - this.originalBinding = null; - this.useAnnotations = scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled; - resolve(scope); - if (nullStatus != 0) - flowInfo.markNullStatus(this.binding, nullStatus); // mark that this flow has seen the resource - } - - private void attachTo(LocalVariableBinding local) { - local.closeTracker = this; - this.originalBinding = local; - } - - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) - { /* NOP - this variable is completely dummy, ie. for analysis only. */ } - - @Override - 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.closeTracker = this; - this.binding.declaringScope = scope; - this.binding.setConstant(Constant.NotAConstant); - this.binding.useFlag = LocalVariableBinding.USED; - // use a free slot without assigning it: - this.binding.id = scope.registerTrackingVariable(this); - } - - /** retrieve a closetracker for local that signifies a certain risk of resource leak in flowInfo. */ - private static FakedTrackingVariable getRiskyCloseTrackerAt(LocalVariableBinding local, Scope scope, FlowInfo flowInfo) { - if (local.closeTracker == null) { - return null; - } - if (flowInfo.nullStatus(local.closeTracker.binding) != FlowInfo.UNKNOWN) - return local.closeTracker; - while (scope instanceof BlockScope) { - FakedTrackingVariable tracker = ((BlockScope) scope).getCloseTrackerFor(local); - if (tracker != null) { - if (tracker.riskyNullStatusAt(flowInfo) != 0) - return tracker; - if (tracker.hasDefinitelyNoResource(flowInfo)) - return null; - } - scope = scope.parent; - } - return null; - } - - /** - * If expression resolves to a value of type AutoCloseable answer the variable that tracks closing of that local. - * Covers two cases: - *
      - *
    • value is a local variable reference, create tracking variable it if needed. - *
    • value is an allocation expression, return a preliminary tracking variable if set. - *
    - * @return a new {@link FakedTrackingVariable} or null. - */ - public static FakedTrackingVariable getCloseTrackingVariable(Expression expression, FlowInfo flowInfo, FlowContext flowContext, boolean useAnnotations) { - while (true) { - if (expression instanceof CastExpression) - expression = ((CastExpression) expression).expression; - else if (expression instanceof Assignment) - expression = ((Assignment) expression).expression; - else if (expression instanceof ConditionalExpression) { - return getMoreUnsafeFromBranches((ConditionalExpression)expression, flowInfo, - branch -> getCloseTrackingVariable(branch, flowInfo, flowContext, useAnnotations)); - } else if (expression instanceof SwitchExpression) { - for (Expression re : ((SwitchExpression) expression).resultExpressions) { - FakedTrackingVariable fakedTrackingVariable = getCloseTrackingVariable(re, flowInfo, flowContext, useAnnotations); - if (fakedTrackingVariable != null) { - return fakedTrackingVariable; - } - } - return null; - } - else - break; - } - FieldBinding fieldBinding = null; - 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 (!isCloseableNotWhiteListed(expression.resolvedType)) - return null; - if ((local.tagBits & TagBits.IsResource) != 0) - return null; - // tracking var doesn't yet exist. This happens in finally block - // which is analyzed before the corresponding try block - Statement location = local.declaration; - local.closeTracker = new FakedTrackingVariable(local, location, flowInfo, flowContext, FlowInfo.UNKNOWN, useAnnotations); - if (local.isParameter()) { - local.closeTracker.globalClosingState |= OWNED_BY_OUTSIDE; - // status of this tracker is now UNKNOWN - } - return local.closeTracker; - } else if (name.binding instanceof FieldBinding) { - fieldBinding = (FieldBinding) name.binding; - } - } else if (expression instanceof FieldReference) { - FieldReference fieldReference = (FieldReference) expression; - if (fieldReference.receiver.isThis()) - fieldBinding = fieldReference.binding; - } else if (expression instanceof AllocationExpression) { - // return any preliminary tracking variable from analyseCloseableAllocation - return ((AllocationExpression) expression).closeTracker; - } else if (expression instanceof MessageSend) { - // return any preliminary tracking variable from analyseCloseableAcquisition - return ((MessageSend) expression).closeTracker; - } - if (fieldBinding != null) - return fieldBinding.closeTracker; - return null; - } - - /** - * Before analyzing an assignment of this shape: singleName = new Allocation() - * connect any tracking variable of the LHS with the allocation on the RHS. - * Also the assignment is temporarily stored in the tracking variable in case we need to - * report errors because the assignment leaves the old LHS value unclosed. - * In this case the assignment should be used as the error location. - * - * @param location the assignment/local declaration being analyzed - * @param local the local variable being assigned to - * @param rhs the rhs of the assignment resp. the initialization of the local variable declaration. - * Precondition: client has already checked that the resolved type of this expression is either a closeable type or NULL. - */ - public static FakedTrackingVariable preConnectTrackerAcrossAssignment(ASTNode location, LocalVariableBinding local, Expression rhs, FlowInfo flowInfo, boolean useAnnotations) { - FakedTrackingVariable closeTracker = null; - if (containsAllocation(rhs)) { - closeTracker = local.closeTracker; - if (closeTracker == null) { - if (rhs.resolvedType != TypeBinding.NULL) { // not NULL means valid closeable as per method precondition - closeTracker = new FakedTrackingVariable(local, location, flowInfo, null, FlowInfo.UNKNOWN, useAnnotations); - if (local.isParameter()) { - closeTracker.globalClosingState |= OWNED_BY_OUTSIDE; - } - } - } - if (closeTracker != null) { - closeTracker.currentAssignment = location; - preConnectTrackerAcrossAssignment(location, local, flowInfo, closeTracker, rhs, useAnnotations); - } - } else if (rhs instanceof MessageSend) { - MessageSend messageSend = (MessageSend) rhs; - closeTracker = local.closeTracker; - if (closeTracker != null) { - closeTracker = handleReassignment(flowInfo, closeTracker, location); - } - if (rhs.resolvedType != TypeBinding.NULL // not NULL means valid closeable as per method precondition - && (!rhs.resolvedType.hasTypeBit(TypeIds.BitResourceFreeCloseable) - || isBlacklistedMethod(rhs))) { - if (closeTracker == null) - closeTracker = new FakedTrackingVariable(local, location, flowInfo, null, FlowInfo.UNKNOWN, useAnnotations); - messageSend.closeTracker = closeTracker; - closeTracker.currentAssignment = location; - } - if (closeTracker != null) { - if (messageSend.binding != null && ((messageSend.binding.tagBits & TagBits.AnnotationNotOwning) == 0)) - closeTracker.owningState = OWNED; - } - } - return closeTracker; - } - - private static boolean containsAllocation(SwitchExpression location) { - for (Expression re : location.resultExpressions) { - if (containsAllocation(re)) - return true; - } - return false; - } - private static boolean containsAllocation(ASTNode location) { - if (location instanceof AllocationExpression) { - return true; - } else if (location instanceof ConditionalExpression) { - ConditionalExpression conditional = (ConditionalExpression) location; - return containsAllocation(conditional.valueIfTrue) || containsAllocation(conditional.valueIfFalse); - } else if (location instanceof SwitchExpression) { - return containsAllocation((SwitchExpression) location); - } else if (location instanceof CastExpression) { - return containsAllocation(((CastExpression) location).expression); - } else if (location instanceof MessageSend) { - if (isFluentMethod(((MessageSend) location).binding)) - return containsAllocation(((MessageSend) location).receiver); - } - return false; - } - - private static void preConnectTrackerAcrossAssignment(ASTNode location, LocalVariableBinding local, FlowInfo flowInfo, - FakedTrackingVariable closeTracker, Expression expression, boolean useAnnotations) { - if (expression instanceof AllocationExpression) { - preConnectTrackerAcrossAssignment(location, local, flowInfo, (AllocationExpression) expression, closeTracker, useAnnotations); - } else if (expression instanceof ConditionalExpression) { - preConnectTrackerAcrossAssignment(location, local, flowInfo, (ConditionalExpression) expression, closeTracker, useAnnotations); - } else if (expression instanceof SwitchExpression) { - preConnectTrackerAcrossAssignment(location, local, flowInfo, (SwitchExpression) expression, closeTracker, useAnnotations); - } else if (expression instanceof CastExpression) { - preConnectTrackerAcrossAssignment(location, local, ((CastExpression) expression).expression, flowInfo, useAnnotations); - } else if (expression instanceof MessageSend) { - if (isFluentMethod(((MessageSend) expression).binding)) - preConnectTrackerAcrossAssignment(location, local, ((MessageSend) expression).receiver, flowInfo, useAnnotations); - } - } - - private static void preConnectTrackerAcrossAssignment(ASTNode location, LocalVariableBinding local, FlowInfo flowInfo, - ConditionalExpression conditional, FakedTrackingVariable closeTracker, boolean useAnnotations) { - preConnectTrackerAcrossAssignment(location, local, flowInfo, closeTracker, conditional.valueIfFalse, useAnnotations); - preConnectTrackerAcrossAssignment(location, local, flowInfo, closeTracker, conditional.valueIfTrue, useAnnotations); - } - - private static void preConnectTrackerAcrossAssignment(ASTNode location, LocalVariableBinding local, FlowInfo flowInfo, - SwitchExpression se, FakedTrackingVariable closeTracker, boolean useAnnotations) { - for (Expression re : se.resultExpressions) { - preConnectTrackerAcrossAssignment(location, local, flowInfo, closeTracker, re, useAnnotations); - } - } - - private static void preConnectTrackerAcrossAssignment(ASTNode location, LocalVariableBinding local, FlowInfo flowInfo, - AllocationExpression allocationExpression, FakedTrackingVariable closeTracker, boolean useAnnotations) { - allocationExpression.closeTracker = closeTracker; - if (allocationExpression.arguments != null && allocationExpression.arguments.length > 0) { - // also push into nested allocations, see https://bugs.eclipse.org/368709 - Expression firstArg = allocationExpression.arguments[0]; - if (isCloseableNotWhiteListed(firstArg.resolvedType)) { - FakedTrackingVariable inner = preConnectTrackerAcrossAssignment(location, local, firstArg, flowInfo, useAnnotations); - if (inner != closeTracker && closeTracker.innerTracker == null) - closeTracker.innerTracker = inner; - } - } - } - - /** - * Compute/assign a tracking variable for a freshly allocated closeable value, using information from our white lists. - * See Bug 358903 - Filter practically unimportant resource leak warnings - */ - public static void analyseCloseableAllocation(BlockScope scope, FlowInfo flowInfo, FlowContext flowContext, AllocationExpression allocation) { - // client has checked that the resolvedType is an AutoCloseable, hence the following cast is safe: - if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitResourceFreeCloseable)) { - // remove unnecessary attempts (closeable is not relevant) - if (allocation.closeTracker != null) { - allocation.closeTracker.withdraw(); - allocation.closeTracker = null; - } - } else if (((ReferenceBinding)allocation.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable)) { - boolean isWrapper = true; - if (allocation.arguments != null && allocation.arguments.length > 0) { - // find the wrapped resource represented by its tracking var: - FakedTrackingVariable innerTracker = findCloseTracker(scope, flowInfo, allocation.arguments[0]); - if (innerTracker != null) { - FakedTrackingVariable currentInner = innerTracker; - do { - if (currentInner == allocation.closeTracker) - return; // self wrap (res = new Res(res)) -> neither change (here) nor remove (below) - // also check for indirect cycles, see https://bugs.eclipse.org/368709 - currentInner = currentInner.innerTracker; - } while (currentInner != null); - int newStatus = FlowInfo.NULL; - if (allocation.closeTracker == null) { - allocation.closeTracker = new FakedTrackingVariable(scope, allocation, flowInfo, FlowInfo.UNKNOWN); // no local available, closeable is unassigned - } else { - if (scope.finallyInfo != null) { - // inject results from analysing a finally block onto the newly connected wrapper - int finallyStatus = scope.finallyInfo.nullStatus(allocation.closeTracker.binding); - if (finallyStatus != FlowInfo.UNKNOWN) - newStatus = finallyStatus; - } - } - if (allocation.closeTracker.innerTracker != null && allocation.closeTracker.innerTracker != innerTracker) { - innerTracker = pickMoreUnsafe(allocation.closeTracker.innerTracker, innerTracker, flowInfo); - } - allocation.closeTracker.innerTracker = innerTracker; - innerTracker.outerTracker = allocation.closeTracker; - flowInfo.markNullStatus(allocation.closeTracker.binding, newStatus); - if (newStatus != FlowInfo.NULL) { - // propagate results from a finally block also into nested resources: - FakedTrackingVariable currentTracker = innerTracker; - while (currentTracker != null) { - flowInfo.markNullStatus(currentTracker.binding, newStatus); - currentTracker.globalClosingState |= allocation.closeTracker.globalClosingState; - currentTracker = currentTracker.innerTracker; - } - } - return; // keep chaining wrapper (by avoiding to fall through to removeTrackingVar below) - } else { - if (!isAnyCloseable(allocation.arguments[0].resolvedType)) { - isWrapper = false; // argument is not closeable - } - } - } else { - isWrapper = false; // no argument - } - // successful wrapper detection has exited above, let's see why that failed - if (isWrapper) { - // remove unnecessary attempts (wrapper has no relevant inner) - if (allocation.closeTracker != null) { - allocation.closeTracker.withdraw(); - allocation.closeTracker = null; - } - } else { - // allocation does not provide a resource as the first argument -> don't treat as a wrapper - handleRegularResource(scope, flowInfo, flowContext, allocation); - } - } else { // regular resource - handleRegularResource(scope, flowInfo, flowContext, allocation); - } - } - - /** - * Check if a message send acquires a closeable from its receiver, see: - * Bug 463320 - [compiler][resource] potential "resource leak" problem disappears when local variable inlined - */ - public static FlowInfo analyseCloseableAcquisition(BlockScope scope, FlowInfo flowInfo, FlowContext flowContext, MessageSend acquisition) { - if (isFluentMethod(acquisition.binding)) { - // share the existing close tracker of the receiver (if any): - acquisition.closeTracker = findCloseTracker(scope, flowInfo, acquisition.receiver); - return flowInfo; - } - // client has checked that the resolvedType is an AutoCloseable, hence the following cast is safe: - if (((ReferenceBinding)acquisition.resolvedType).hasTypeBit(TypeIds.BitResourceFreeCloseable) - && !isBlacklistedMethod(acquisition)) { - // remove unnecessary attempts (closeable is not relevant) - if (acquisition.closeTracker != null) { - acquisition.closeTracker.withdraw(); - acquisition.closeTracker = null; - } - return flowInfo; - } else { // regular resource - FakedTrackingVariable tracker = acquisition.closeTracker; - if (scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled) { - long owningTagBits = acquisition.binding.tagBits & TagBits.AnnotationOwningMASK; - int initialNullStatus = (owningTagBits == TagBits.AnnotationNotOwning) ? FlowInfo.NON_NULL : FlowInfo.NULL; - if (tracker == null) { - acquisition.closeTracker = - tracker = new FakedTrackingVariable(scope, acquisition, flowInfo, initialNullStatus); // no local available, closeable is unassigned - tracker.owningState = owningStateFromTagBits(owningTagBits, OWNED_PER_DEFAULT); - } else { - flowInfo.markNullStatus(tracker.binding, initialNullStatus); - } - tracker.acquisition = acquisition; - return flowInfo; - } - if (tracker != null) { - // pre-connected tracker means: directly assigning the acquisition to a local, forget special treatment: - // (in the unannotated case the pre-connected tracker has no valuable information) - tracker.withdraw(); - acquisition.closeTracker = null; - return flowInfo; - } else { - tracker = new FakedTrackingVariable(scope, acquisition, flowInfo, FlowInfo.UNKNOWN); // no local available, closeable is unassigned - acquisition.closeTracker = tracker; - } - tracker.acquisition = acquisition; - FlowInfo outsideInfo = flowInfo.copy(); - outsideInfo.markAsDefinitelyNonNull(tracker.binding); - tracker.markNullStatus(flowInfo, flowContext, FlowInfo.NULL); - return FlowInfo.conditional(outsideInfo, flowInfo); - } - } - - private static boolean isFluentMethod(MethodBinding binding) { - if (binding.isStatic()) - return false; - ReferenceBinding declaringClass = binding.declaringClass; - if (declaringClass.equals(binding.returnType)) { - for (char[][] compoundName : TypeConstants.FLUENT_RESOURCE_CLASSES) { - if (CharOperation.equals(compoundName, declaringClass.compoundName)) - return true; - } - } - return false; - } - - private static FakedTrackingVariable getMoreUnsafeFromBranches(ConditionalExpression conditionalExpression, - FlowInfo flowInfo, Function retriever) - { - FakedTrackingVariable trackerIfTrue = retriever.apply(conditionalExpression.valueIfTrue); - FakedTrackingVariable trackerIfFalse = retriever.apply(conditionalExpression.valueIfFalse); - if (trackerIfTrue == null) - return trackerIfFalse; - if (trackerIfFalse == null) - return trackerIfTrue; - return pickMoreUnsafe(trackerIfTrue, trackerIfFalse, flowInfo); - } - - private static FakedTrackingVariable pickMoreUnsafe(FakedTrackingVariable tracker1, FakedTrackingVariable tracker2, FlowInfo info) { - // whichever of the two trackers has stronger indication to be leaking will be returned, - // the other one will be removed from the scope (considered to be merged into the former). - int status1 = info.nullStatus(tracker1.binding); - int status2 = info.nullStatus(tracker2.binding); - if (status1 == FlowInfo.NULL || status2 == FlowInfo.NON_NULL) return pick(tracker1, tracker2); - if (status1 == FlowInfo.NON_NULL || status2 == FlowInfo.NULL) return pick(tracker2, tracker1); - if ((status1 & FlowInfo.POTENTIALLY_NULL) != 0) return pick(tracker1, tracker2); - if ((status2 & FlowInfo.POTENTIALLY_NULL) != 0) return pick(tracker2, tracker1); - return pick(tracker1, tracker2); - } - - private static FakedTrackingVariable pick(FakedTrackingVariable tracker1, FakedTrackingVariable tracker2) { - tracker2.withdraw(); - return tracker1; - } - - private static void handleRegularResource(BlockScope scope, FlowInfo flowInfo, FlowContext flowContext, AllocationExpression allocation) { - FakedTrackingVariable presetTracker = allocation.closeTracker; - LocalVariableBinding local = null; - if (presetTracker != null && presetTracker.originalBinding != null) { - if (presetTracker.isInFinallyBlockOf(flowContext) && presetTracker.recordFirstModification(flowContext)) { - // not a re-assignment after the one seen within finally, but this excuse is valid only once. - } else { - local = presetTracker.originalBinding; - // the current assignment forgets a previous resource in the LHS, may cause a leak - // report now because handleResourceAssignment can't distinguish this from a self-wrap situation - handleReassignment(flowInfo, presetTracker, presetTracker.currentAssignment); - if (local != null && !presetTracker.hasDefinitelyNoResource(flowInfo) && presetTracker.currentAssignment instanceof Assignment) { - boolean useAnnotations = scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled; - allocation.closeTracker = - local.closeTracker = - new FakedTrackingVariable(local, scope, presetTracker.currentAssignment, flowInfo, flowContext, FlowInfo.NULL, useAnnotations); - if (useAnnotations) - allocation.closeTracker.owningState = OWNED; - // if finally closes the given local, this may affect any resource bound to the same local - // (but re-assignment over an existing unclosed resource will be recorded (at-location) in handleReassignment() above). - FlowInfo enclosingFinallyInfo = null; - Scope current = scope; - while (current instanceof BlockScope && enclosingFinallyInfo == null) { - enclosingFinallyInfo = ((BlockScope) current).finallyInfo; - current = current.parent; - } - if (enclosingFinallyInfo != null) { - int finallyNullStatus = enclosingFinallyInfo.nullStatus(presetTracker.binding); - enclosingFinallyInfo.markNullStatus(local.closeTracker.binding, finallyNullStatus); - } - presetTracker.markNullStatus(flowInfo, flowContext, FlowInfo.UNKNOWN); // no longer relevant in this flow - } - } - } else { - allocation.closeTracker = new FakedTrackingVariable(scope, allocation, flowInfo, FlowInfo.UNKNOWN); // no local available, closeable is unassigned - } - allocation.closeTracker.markNullStatus(flowInfo, flowContext, FlowInfo.NULL); - } - - /** Was this FTV created from the finally block of the current context? */ - private boolean isInFinallyBlockOf(FlowContext flowContext) { - if (this.tryContext != null) { - do { - if (flowContext == this.tryContext) - return true; - flowContext = flowContext.parent; - } while (flowContext != null); - } - return false; - } - - /** Try to remember flowContext as the first one where this FTV is being modified. */ - private boolean recordFirstModification(FlowContext flowContext) { - if (this.modificationContexts == null) { - this.modificationContexts = new HashSet<>(); - this.modificationContexts.add(flowContext); - return true; - } - FlowContext current = flowContext; - while (current != null) { - if (this.modificationContexts.contains(current)) - return false; - current = current.parent; - } - return this.modificationContexts.add(flowContext); - } - - private static FakedTrackingVariable handleReassignment(FlowInfo flowInfo, FakedTrackingVariable existingTracker, ASTNode location) { - int riskyStatus = existingTracker.riskyNullStatusAt(flowInfo); - if (riskyStatus != 0 - && !(location instanceof LocalDeclaration)) // forgetting old val in local decl is syntactically impossible - { - existingTracker.recordErrorLocation(location, riskyStatus); - return null; // stop using this tracker after re-assignment - } - return existingTracker; - } - - /** Find an existing tracking variable for the argument of an allocation for a resource wrapper. */ - private static FakedTrackingVariable findCloseTracker(BlockScope scope, FlowInfo flowInfo, Expression arg) - { - while (arg instanceof Assignment) { - Assignment assign = (Assignment)arg; - LocalVariableBinding innerLocal = assign.localVariableBinding(); - if (innerLocal != null) { - // nested assignment has already been processed - return innerLocal.closeTracker; - } else { - arg = assign.expression; // unwrap assignment and fall through - } - } - if (arg instanceof SingleNameReference) { - // is allocation arg a reference to an existing closeable? - LocalVariableBinding local = arg.localVariableBinding(); - if (local != null) { - return local.closeTracker; - } - } else if (arg instanceof AllocationExpression) { - // nested allocation - return ((AllocationExpression)arg).closeTracker; - } else if (arg instanceof MessageSend) { - return ((MessageSend) arg).closeTracker; - } - return null; // not a tracked expression - } - - /** - * Given the rhs of an assignment or local declaration has a (Auto)Closeable type (or null), setup for leak analysis now: - * Create or re-use a tracking variable, and wire and initialize everything. - * @param scope scope containing the assignment - * @param upstreamInfo info without analysis of the rhs, use this to determine the status of a resource being disconnected - * @param flowInfo info with analysis of the rhs, use this for recording resource status because this will be passed downstream - * @param location where to report warnigs/errors against - * @param rhs the right hand side of the assignment, this expression is to be analyzed. - * The caller has already checked that the rhs is either of a closeable type or null. - * @param local the local variable into which the rhs is being assigned - */ - public static void handleResourceAssignment(BlockScope scope, FlowInfo upstreamInfo, FlowInfo flowInfo, FlowContext flowContext, ASTNode location, Expression rhs, LocalVariableBinding local) - { - // does the LHS (local) already have a tracker, indicating we may leak a resource by the assignment? - FakedTrackingVariable previousTracker = getRiskyCloseTrackerAt(local, scope, upstreamInfo); - FakedTrackingVariable disconnectedTracker = null; - if (previousTracker != null) { - // assigning to a variable already holding an AutoCloseable, has it been closed before? - if (previousTracker.riskyNullStatusAt(upstreamInfo) != 0) // only if previous value may be relevant - disconnectedTracker = previousTracker; // report error below, unless we have a self-wrap assignment - } else { - previousTracker = local.closeTracker; // not yet risky, but may still be releavant below - } - - boolean useAnnotations = scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled; - - rhsAnalyis: - if (rhs.resolvedType != TypeBinding.NULL) { - // new value is AutoCloseable, start tracking, possibly re-using existing tracker var: - FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable(rhs, flowInfo, flowContext, useAnnotations); - if (rhsTrackVar != null) { // 1. if RHS has a tracking variable... - if (local.closeTracker == null) { - // null shouldn't occur but let's play safe: - if (rhsTrackVar.originalBinding != null) { - local.closeTracker = rhsTrackVar; // a.: let fresh LHS share it - } else if (rhsTrackVar.originalFieldBinding != null) { - local.closeTracker = rhsTrackVar; - } - if (rhsTrackVar.currentAssignment == location) { - // pre-set tracker from lhs - passed from outside (or foreach)? - // now it's a fresh resource - rhsTrackVar.globalClosingState &= ~(SHARED_WITH_OUTSIDE|OWNED_BY_OUTSIDE|FOREACH_ELEMENT_VAR); - } - } else { - if (rhs instanceof AllocationExpression || rhs instanceof ConditionalExpression || rhs instanceof SwitchExpression || rhs instanceof MessageSend) { - if (rhsTrackVar == disconnectedTracker) - return; // b.: self wrapper: res = new Wrap(res); -> done! - if (local.closeTracker == rhsTrackVar - && rhsTrackVar.isNotOwned()) { - // c.: assigning a fresh resource (pre-connected alloc) - // to a local previously holding an alien resource -> start over - local.closeTracker = new FakedTrackingVariable(local, scope, location, flowInfo, flowContext, FlowInfo.NULL, useAnnotations); - // still check disconnectedTracker below - break rhsAnalyis; - } - } - rhsTrackVar.attachTo(local); // d.: conflicting LHS and RHS, proceed with recordErrorLocation below - } - // keep close-status of RHS unchanged across this assignment - } else if (previousTracker != null) { // 2. re-use tracking variable from the LHS? - FlowContext currentFlowContext = flowContext; - checkReuseTracker : { - if (previousTracker.tryContext != null) { - while (currentFlowContext != null) { - if (previousTracker.tryContext == currentFlowContext) { - // "previous" location was the finally block of the current try statement. - // -> This is not a re-assignment. - // see https://bugs.eclipse.org/388996 - break checkReuseTracker; - } - currentFlowContext = currentFlowContext.parent; - } - } - // re-assigning from a fresh value, mark as not-closed again: - if ((previousTracker.globalClosingState & (SHARED_WITH_OUTSIDE|OWNED_BY_OUTSIDE|FOREACH_ELEMENT_VAR)) == 0 - && flowInfo.hasNullInfoFor(previousTracker.binding)) // avoid spilling info into a branch that doesn't see the corresponding resource - previousTracker.markNullStatus(flowInfo, flowContext, FlowInfo.NULL); - local.closeTracker = analyseCloseableExpression(scope, flowInfo, flowContext, useAnnotations, local, location, rhs, previousTracker); - } - } else { // 3. no re-use, create a fresh tracking variable: - rhsTrackVar = analyseCloseableExpression(scope, flowInfo, flowContext, useAnnotations, local, location, rhs, null); - if (rhsTrackVar != null) { - rhsTrackVar.attachTo(local); - if (!useAnnotations) { - // a fresh resource, mark as not-closed: - if ((rhsTrackVar.globalClosingState & (SHARED_WITH_OUTSIDE|OWNED_BY_OUTSIDE|FOREACH_ELEMENT_VAR)) == 0) - rhsTrackVar.markNullStatus(flowInfo, flowContext, FlowInfo.NULL); - } -// TODO(stephan): this might be useful, but I could not find a test case for it: -// if (flowContext.initsOnFinally != null) -// flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding); - } - } - } - - if (disconnectedTracker != null) { - if (disconnectedTracker.innerTracker != null && disconnectedTracker.innerTracker.binding.declaringScope == scope) { - // discard tracker for the wrapper but keep the inner: - disconnectedTracker.innerTracker.outerTracker = null; - scope.pruneWrapperTrackingVar(disconnectedTracker); - } else { - int upstreamStatus = disconnectedTracker.riskyNullStatusAt(upstreamInfo); - if (upstreamStatus != 0) - disconnectedTracker.recordErrorLocation(location, upstreamStatus); - } - } - } - - public int riskyNullStatusAt(FlowInfo info) { - if (hasDefinitelyNoResource(info)) - return 0; - int nullStatus = getNullStatusAggressively(this.binding, info); - if ((nullStatus & (FlowInfo.UNKNOWN | FlowInfo.NON_NULL)) == 0) - return nullStatus; - return 0; - } - - /** - * When assigning an rhs of an (Auto)Closeable type (or null) to a field, inspect annotations - * to find out if the assignment assigns ownership to the instance (rather than current method). - * @param scope scope containing the assignment - * @param flowInfo info with analysis of the rhs, use this for recording resource status because this will be passed downstream - * @param location where to report warnigs/errors against - * @param rhs the right hand side of the assignment, this expression is to be analyzed. - * The caller has already checked that the rhs is either of a closeable type or null. - */ - public static void handleResourceFieldAssignment(BlockScope scope, FlowInfo flowInfo, FlowContext flowContext, ASTNode location, Expression rhs) - { - boolean useAnnotations = scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled; - - if (rhs.resolvedType != TypeBinding.NULL) { - // new value is AutoCloseable, start tracking, possibly re-using existing tracker var: - FakedTrackingVariable rhsTrackVar = getCloseTrackingVariable(rhs, flowInfo, flowContext, useAnnotations); - if (rhsTrackVar != null) { - if (useAnnotations) { - if (location instanceof Assignment) { - Expression lhs = ((Assignment) location).lhs; - FieldBinding field = null; - // only consider access to field of the current instance: - if (lhs instanceof SingleNameReference) { - field = ((SingleNameReference) lhs).fieldBinding(); - } else if (lhs instanceof FieldReference) { - FieldReference fieldReference = (FieldReference) lhs; - if (fieldReference.receiver.isThis()) - field = fieldReference.binding; - } - if (field != null) { - if (!field.isStatic() && (field.tagBits & TagBits.AnnotationOwning) != 0) { - rhsTrackVar.markNullStatus(flowInfo, flowContext, FlowInfo.NON_NULL); - } else { - rhsTrackVar.markAsShared(); - } - } - } - } -// TODO(stephan): this might be useful, but I could not find a test case for it: -// if (flowContext.initsOnFinally != null) -// flowContext.initsOnFinally.markAsDefinitelyNonNull(trackerBinding); - } - } - } - /** - * Analyze structure of a closeable expression, matching (chained) resources against our white lists. - * @param scope scope of the expression - * @param flowInfo where to record close status - * @param useAnnotations is annotation based resource analysis enabled - * @param local local variable to which the closeable is being assigned - * @param location where to flag errors/warnings against - * @param expression expression to be analyzed - * @param previousTracker when analyzing a re-assignment we may already have a tracking variable for local, - * which we should then re-use - * @return a tracking variable associated with local or null if no need to track - */ - private static FakedTrackingVariable analyseCloseableExpression(BlockScope scope, FlowInfo flowInfo, FlowContext flowContext, boolean useAnnotations, - LocalVariableBinding local, ASTNode location, Expression expression, FakedTrackingVariable previousTracker) - { - // unwrap uninteresting nodes: - while (true) { - if (expression instanceof Assignment) - expression = ((Assignment)expression).expression; - else if (expression instanceof CastExpression) - expression = ((CastExpression) expression).expression; - else - break; - } - if (expression instanceof Literal) { - return null; - } - // delegate to components: - if (expression instanceof ConditionalExpression) { - return getMoreUnsafeFromBranches((ConditionalExpression) expression, flowInfo, - branch -> analyseCloseableExpression(scope, flowInfo, flowContext, useAnnotations, - local, location, branch, previousTracker)); - } else if (expression instanceof SwitchExpression) { - FakedTrackingVariable mostRisky = null; - for (Expression result : ((SwitchExpression) expression).resultExpressions) { - FakedTrackingVariable current = analyseCloseableExpression(scope, flowInfo, flowContext, useAnnotations, - local, location, result, previousTracker); - if (mostRisky == null) - mostRisky = current; - else - mostRisky = pickMoreUnsafe(mostRisky, current, flowInfo); - } - return mostRisky; - } - - boolean isResourceProducer = false; - if (expression.resolvedType instanceof ReferenceBinding) { - ReferenceBinding resourceType = (ReferenceBinding) expression.resolvedType; - if (resourceType.hasTypeBit(TypeIds.BitResourceFreeCloseable)) { - if (isBlacklistedMethod(expression)) - isResourceProducer = true; - else - return null; // (a) resource-free closeable: -> null - } - } - - if (local == null) { - FakedTrackingVariable tracker = null; - if (useAnnotations && (expression.bits & RestrictiveFlagMASK) == Binding.FIELD) { - // field read - FieldBinding fieldBinding = ((Reference) expression).lastFieldBinding(); - long owningBits = 0; - if (fieldBinding != null) { - owningBits = fieldBinding.getAnnotationTagBits() & TagBits.AnnotationOwningMASK; - } - int status = FlowInfo.UNKNOWN; - if (owningBits == TagBits.AnnotationOwning) { - status = FlowInfo.NON_NULL; - } else if (owningBits == TagBits.AnnotationNotOwning) { - status = FlowInfo.POTENTIALLY_NULL; - } - tracker = new FakedTrackingVariable(local, scope, location, flowInfo, flowContext, status, useAnnotations); - tracker.owningState = NOT_OWNED; - } - return tracker; - } - - // analyze by node type: - if (expression instanceof AllocationExpression) { - // allocation expressions already have their tracking variables analyzed by analyseCloseableAllocation(..) - FakedTrackingVariable tracker = ((AllocationExpression) expression).closeTracker; - if (tracker != null && tracker.originalBinding == null) { - // tracker without original binding (unassigned closeable) shouldn't reach here but let's play safe - return null; - } - return tracker; - } else if (expression instanceof MessageSend - || expression instanceof ArrayReference) - { - int initialNullStatus = 0; - if (isBlacklistedMethod(expression)) { - initialNullStatus = FlowInfo.NULL; - } else if (useAnnotations) { - initialNullStatus = getNullStatusFromMessageSend(expression); - } - if (initialNullStatus != 0) - return new FakedTrackingVariable(local, location, flowInfo, flowContext, initialNullStatus, useAnnotations); - - // we *might* be responsible for the resource obtained - FakedTrackingVariable tracker = new FakedTrackingVariable(local, location, flowInfo, flowContext, FlowInfo.POTENTIALLY_NULL, useAnnotations); // shed some doubt - if (!isResourceProducer && !useAnnotations) - tracker.globalClosingState |= SHARED_WITH_OUTSIDE; - return tracker; - } else if ( - (expression.bits & RestrictiveFlagMASK) == Binding.FIELD - ||((expression instanceof QualifiedNameReference) - && ((QualifiedNameReference) expression).isFieldAccess())) - { - if (!useAnnotations) { - // responsibility for this resource probably lies at a higher level - FakedTrackingVariable tracker = new FakedTrackingVariable(local, location, flowInfo, flowContext, FlowInfo.UNKNOWN, useAnnotations); - tracker.globalClosingState |= OWNED_BY_OUTSIDE; - // leave state as UNKNOWN, the bit OWNED_BY_OUTSIDE will prevent spurious warnings - return tracker; - } - } - - if (local.closeTracker != null) - // (c): inner has already been analyzed: -> re-use track var - return local.closeTracker; - FakedTrackingVariable newTracker = new FakedTrackingVariable(local, location, flowInfo, flowContext, FlowInfo.UNKNOWN, useAnnotations); - LocalVariableBinding rhsLocal = expression.localVariableBinding(); - if (rhsLocal != null && rhsLocal.isParameter()) { - newTracker.globalClosingState |= OWNED_BY_OUTSIDE; - } - return newTracker; - } - - private static boolean isBlacklistedMethod(Expression expression) { - if (expression instanceof MessageSend) { - MethodBinding method = ((MessageSend) expression).binding; - if (method != null && method.isValidBinding()) - // for all methods in java.nio.file.Files that return a resource (Stream) it really needs closing - return CharOperation.equals(method.declaringClass.compoundName, TypeConstants.JAVA_NIO_FILE_FILES); - } - return false; - } - - /* pre: usesOwningAnnotations. */ - protected static int getNullStatusFromMessageSend(Expression expression) { - if (expression instanceof MessageSend) { - if ((((MessageSend) expression).binding.tagBits & TagBits.AnnotationNotOwning) != 0) - return FlowInfo.NON_NULL; - return FlowInfo.NULL; // per default assume responsibility to close - } - return 0; - } - - public static void cleanUpAfterAssignment(BlockScope currentScope, int lhsBits, Expression expression) { - // remove all remaining track vars with no original binding - - // unwrap uninteresting nodes: - while (true) { - if (expression instanceof Assignment) - expression = ((Assignment)expression).expression; - else if (expression instanceof CastExpression) - expression = ((CastExpression) expression).expression; - else - break; - } - if (expression instanceof AllocationExpression) { - FakedTrackingVariable tracker = ((AllocationExpression) expression).closeTracker; - if (tracker != null && tracker.originalBinding == null) { - tracker.withdraw(); - ((AllocationExpression) expression).closeTracker = null; - } - } else if (expression instanceof MessageSend) { - FakedTrackingVariable tracker = ((MessageSend) expression).closeTracker; - if (tracker != null && tracker.originalBinding == null) { - tracker.withdraw(); - ((MessageSend) expression).closeTracker = null; - } - } else { - // assignment passing a local into a field? - LocalVariableBinding local = expression.localVariableBinding(); - if (local != null - && ((lhsBits & Binding.FIELD) != 0) - && !currentScope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled - && local.closeTracker != null) { - local.closeTracker.withdraw(); // TODO: may want to use local.closeTracker.markPassedToOutside(..,true) - } - } - } - - /** - * Unassigned closeables are not visible beyond their enclosing statement, immediately report and remove after each statement. - * @param returnMissingOwning at a return statement this signals {@code true} when the enclosing method lacks an {@code @Owning} annotation. - */ - public static void cleanUpUnassigned(BlockScope scope, ASTNode location, FlowInfo flowInfo, boolean returnMissingOwning) { - if (!scope.hasResourceTrackers()) return; - boolean useAnnotations = scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled; - location.traverse(new ASTVisitor() { - @Override - public boolean visit(MessageSend messageSend, BlockScope skope) { - FakedTrackingVariable closeTracker = messageSend.closeTracker; - handle(closeTracker, flowInfo, messageSend, skope); - return true; - } - @Override - public boolean visit(AllocationExpression allocation, BlockScope skope) { - if (handle(allocation.closeTracker, flowInfo, allocation, skope)) - allocation.closeTracker = null; - return true; - } - - /** @return has the tracker been withdrawn? */ - protected boolean handle(FakedTrackingVariable closeTracker, FlowInfo flow, ASTNode loc, BlockScope skope) { - if (closeTracker != null && closeTracker.originalBinding == null && closeTracker.originalFieldBinding == null) { - int nullStatus = closeTracker.riskyNullStatusAt(flow); - if (nullStatus != 0) { - int reportFlag = closeTracker.reportError(skope.problemReporter(), loc, nullStatus); - closeTracker.markAllConnected(ftv -> ftv.globalClosingState |= reportFlag); - } else if (returnMissingOwning && useAnnotations) { - skope.problemReporter().shouldMarkMethodAsOwning(location); - } - closeTracker.withdraw(); - return true; - } - return false; - } - }, - scope); - } - - /** Answer wither the given type binding is a subtype of java.lang.AutoCloseable. */ - public static boolean isAnyCloseable(TypeBinding typeBinding) { - return typeBinding instanceof ReferenceBinding - && ((ReferenceBinding)typeBinding).hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable); - } - - /** Answer wither the given type binding is a subtype of java.lang.AutoCloseable. */ - public static boolean isCloseableNotWhiteListed(TypeBinding typeBinding) { - if (typeBinding instanceof ReferenceBinding) { - ReferenceBinding referenceBinding = (ReferenceBinding)typeBinding; - return referenceBinding.hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable) - && !referenceBinding.hasTypeBit(TypeIds.BitResourceFreeCloseable); - } - return false; - } - - public int findMostSpecificStatus(FlowInfo flowInfo, BlockScope currentScope, BlockScope locationScope) { - int status = FlowInfo.UNKNOWN; - FakedTrackingVariable currentTracker = this; - // loop as to consider wrappers (per white list) encapsulating an inner resource. - while (currentTracker != null) { - LocalVariableBinding currentVar = currentTracker.binding; - int currentStatus = getNullStatusAggressively(currentVar, flowInfo); - if (locationScope != null) // only check at method exit points - currentStatus = mergeCloseStatus(locationScope, currentStatus, currentVar, currentScope); - if (currentStatus == FlowInfo.NON_NULL) { - status = currentStatus; - break; // closed -> stop searching - } else if (status == FlowInfo.NULL || status == FlowInfo.UNKNOWN) { - status = currentStatus; // improved although not yet safe -> keep searching for better - } - currentTracker = currentTracker.innerTracker; - } - return status; - } - - /** - * Get the null status looking even into unreachable flows - * @return one of the constants FlowInfo.{NULL,POTENTIALLY_NULL,POTENTIALLY_NON_NULL,NON_NULL}. - */ - private int getNullStatusAggressively(LocalVariableBinding local, FlowInfo flowInfo) { - if (flowInfo == FlowInfo.DEAD_END) { - return FlowInfo.UNKNOWN; - } - 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); - if (TEST_372319) { // see https://bugs.eclipse.org/372319 - try { - Thread.sleep(5); // increase probability of concurrency bug - } catch (InterruptedException e) { /* nop */ } - } - } 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; - } else if (status == FlowInfo.UNKNOWN) { - // if unassigned resource (not having an originalBinding) is not withdrawn it is unclosed: - if (this.originalBinding == null && this.originalFieldBinding == null) - return FlowInfo.NULL; - } - return status; - } - - public int mergeCloseStatus(BlockScope currentScope, int status, LocalVariableBinding local, BlockScope outerScope) { - // get the most suitable null status representing whether resource 'binding' has been closed - // start at 'currentScope' and potentially travel out until 'outerScope' - // at each scope consult any recorded 'finallyInfo'. - if (status != FlowInfo.NON_NULL) { - if (currentScope.finallyInfo != null) { - int finallyStatus = currentScope.finallyInfo.nullStatus(local); - if (finallyStatus == FlowInfo.NON_NULL) - return finallyStatus; - if (finallyStatus != FlowInfo.NULL && currentScope.finallyInfo.hasNullInfoFor(local)) // neither is NON_NULL, but not both are NULL => call it POTENTIALLY_NULL - status = FlowInfo.POTENTIALLY_NULL; - } - if (currentScope != outerScope && currentScope.parent instanceof BlockScope) - return mergeCloseStatus(((BlockScope) currentScope.parent), status, local, outerScope); - } - return status; - } - - /** Mark that this resource is closed locally. */ - public void markClose(FlowInfo flowInfo, FlowContext flowContext) { - markAllConnected(current -> { - flowInfo.markAsDefinitelyNonNull(current.binding); - current.globalClosingState |= CLOSE_SEEN; - flowContext.markFinallyNullStatus(current.binding, FlowInfo.NON_NULL); - }); - } - - public void markNullStatus(FlowInfo flowInfo, FlowContext flowContext, int status) { - markAllConnected(current -> { - flowInfo.markNullStatus(current.binding, status); - flowContext.markFinallyNullStatus(current.binding, status); - }); - } - - public void markOwnedByOutside(FlowInfo flowInfo, FlowContext flowContext) { - markAllConnected(current -> { - flowInfo.markAsDefinitelyNonNull(current.binding); - flowContext.markFinallyNullStatus(current.binding, FlowInfo.NON_NULL); - current.globalClosingState = FakedTrackingVariable.OWNED_BY_OUTSIDE; - }); - } - - public void markAllConnected(Consumer operation) { - FakedTrackingVariable current = this; - do { - operation.accept(current); - current = current.innerTracker; - } while (current != null); - current = this.outerTracker; - while (current != null) { - operation.accept(current); - current = current.outerTracker; - } - } - - /** Mark that this resource is closed from a nested method (inside a local class). */ - public void markClosedInNestedMethod() { - this.globalClosingState |= CLOSED_IN_NESTED_METHOD; - } - - public boolean isClosedInNestedMethod() { - return (this.globalClosingState & CLOSED_IN_NESTED_METHOD) != 0; - } - - /** Mark that this resource is closed from a try-with-resource with the tracking variable being effectively final). */ - public void markClosedEffectivelyFinal() { - this.globalClosingState |= TWR_EFFECTIVELY_FINAL; - } - /** - * 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. - * @param owned should the resource be considered owned by some outside? - */ - public static FlowInfo markPassedToOutside(BlockScope scope, Expression expression, FlowInfo flowInfo, FlowContext flowContext, boolean owned) { - - FakedTrackingVariable trackVar = getCloseTrackingVariable(expression, flowInfo, flowContext, - scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled); - if (trackVar != null) { - // insert info that the tracked resource *may* be closed (by the target method, i.e.) - FlowInfo infoResourceIsClosed = owned ? flowInfo : flowInfo.copy(); - int flag = owned ? OWNED_BY_OUTSIDE : SHARED_WITH_OUTSIDE; - trackVar.markAllConnected(ftv -> { - ftv.globalClosingState |= flag; - if (scope.methodScope() != ftv.methodScope) - ftv.globalClosingState |= CLOSED_IN_NESTED_METHOD; - ftv.markNullStatus(flowInfo, flowContext, FlowInfo.NON_NULL); - }); - if (owned) { - return infoResourceIsClosed; // don't let downstream signal any problems on this flow - } else { - return FlowInfo.conditional(flowInfo, infoResourceIsClosed).unconditionalCopy(); // only report potential problems on this flow - } - } - return flowInfo; - } - - public static void markForeachElementVar(LocalDeclaration local) { - if (local.binding != null && local.binding.closeTracker != null) { - local.binding.closeTracker.globalClosingState |= FOREACH_ELEMENT_VAR; - } - } - - /** - * Iterator for a set of FakedTrackingVariable, which dispenses the elements - * according to the priorities defined by enum {@link Stage}. - * Resources whose outer is owned by an enclosing scope are never answered, - * unless we are analysing on behalf of an exit (return/throw). - */ - public static class IteratorForReporting implements Iterator { - - private final Set varSet; - private final Scope scope; - private final boolean atExit; - - private Stage stage; - private Iterator iterator; - private FakedTrackingVariable next; - - enum Stage { - /** 1. prio: all top-level resources, ie., resources with no outer. */ - OuterLess, - /** 2. prio: resources whose outer has already been processed (element of the same varSet). */ - InnerOfProcessed, - /** 3. prio: resources whose outer is not owned by any enclosing scope. */ - InnerOfNotEnclosing, - /** 4. prio: when analysing on behalf of an exit point: anything not picked before. */ - AtExit - } - - public IteratorForReporting(List variables, Scope scope, boolean atExit) { - this.varSet = new HashSet<>(variables); - this.scope = scope; - this.atExit = atExit; - setUpForStage(Stage.OuterLess); - } - @Override - public boolean hasNext() { - FakedTrackingVariable trackingVar; - switch (this.stage) { - case OuterLess: - while (this.iterator.hasNext()) { - trackingVar = this.iterator.next(); - if (trackingVar.outerTracker == null) - return found(trackingVar); - } - setUpForStage(Stage.InnerOfProcessed); - //$FALL-THROUGH$ - case InnerOfProcessed: - while (this.iterator.hasNext()) { - trackingVar = this.iterator.next(); - FakedTrackingVariable outer = trackingVar.outerTracker; - if (outer.binding.declaringScope == this.scope && !this.varSet.contains(outer)) - return found(trackingVar); - } - setUpForStage(Stage.InnerOfNotEnclosing); - //$FALL-THROUGH$ - case InnerOfNotEnclosing: - searchAlien: while (this.iterator.hasNext()) { - trackingVar = this.iterator.next(); - FakedTrackingVariable outer = trackingVar.outerTracker; - if (!this.varSet.contains(outer)) { - Scope outerTrackerScope = outer.binding.declaringScope; - Scope currentScope = this.scope; - while ((currentScope = currentScope.parent) instanceof BlockScope) { - if (outerTrackerScope == currentScope) - break searchAlien; - } - return found(trackingVar); - } - } - setUpForStage(Stage.AtExit); - //$FALL-THROUGH$ - case AtExit: - if (this.atExit && this.iterator.hasNext()) - return found(this.iterator.next()); - return false; - default: throw new IllegalStateException("Unexpected Stage "+this.stage); //$NON-NLS-1$ - } - } - private boolean found(FakedTrackingVariable trackingVar) { - this.iterator.remove(); - this.next = trackingVar; - return true; - } - private void setUpForStage(Stage nextStage) { - this.iterator = this.varSet.iterator(); - this.stage = nextStage; - } - @Override - public FakedTrackingVariable next() { - return this.next; - } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - /** - * Answer true if we know for sure that no resource is bound to this variable - * at the point of 'flowInfo'. - */ - public boolean hasDefinitelyNoResource(FlowInfo flowInfo) { - if (this.originalBinding == null) return false; // shouldn't happen but keep quiet. - if (flowInfo.isDefinitelyNull(this.originalBinding)) { - return true; - } - if (!(flowInfo.isDefinitelyAssigned(this.originalBinding) - || flowInfo.isPotentiallyAssigned(this.originalBinding))) { - return true; - } - return false; - } - - public boolean isClosedInFinallyOfEnclosing(BlockScope scope) { - BlockScope currentScope = scope; - while (true) { - if (currentScope.finallyInfo != null - && currentScope.finallyInfo.isDefinitelyNonNull(this.binding)) { - return true; // closed in enclosing finally - } - if (!(currentScope.parent instanceof BlockScope)) { - return false; - } - currentScope = (BlockScope) currentScope.parent; - } - } - - public boolean isClosedInFinally() { - return this.blockScope != null && isClosedInFinallyOfEnclosing(this.blockScope); - } - - /** - * If current is the same as 'returnedResource' or a wrapper thereof, - * mark as reported and return true, otherwise false. - * - * When using {@code @Owning} annotation, do not mark as reported, to proceed to precise analysis - */ - public boolean isResourceBeingReturned(FakedTrackingVariable returnedResource, boolean useOwningAnnotation) { - FakedTrackingVariable current = this; - do { - if (current == returnedResource) { - if (!useOwningAnnotation) - this.globalClosingState |= REPORTED_DEFINITIVE_LEAK; - return true; - } - current = current.innerTracker; - } while (current != null); - return false; - } - - public void withdraw() { - // must unregister at the declaringScope, note that twr resources are owned by the scope enclosing the twr - this.binding.declaringScope.removeTrackingVar(this); - if (this.acquisition != null && this.acquisition.closeTracker == this) - this.acquisition.closeTracker = null; - } - - public void recordErrorLocation(ASTNode location, int nullStatus) { - if (isNotOwned()) { - return; - } - if (this.recordedLocations == null) - this.recordedLocations = new HashMap<>(); - this.recordedLocations.put(location, Integer.valueOf(nullStatus)); - } - - public boolean reportRecordedErrors(Scope scope, int mergedStatus, boolean atDeadEnd) { - FakedTrackingVariable current = this; - while (current.globalClosingState == 0) { - current = current.innerTracker; - if (current == null) { - // no relevant state found -> report: - if (atDeadEnd && neverClosedAtLocations()) - mergedStatus = FlowInfo.NULL; - if ((mergedStatus & (FlowInfo.NULL|FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0) { - reportError(scope.problemReporter(), null, mergedStatus); - return true; - } else { - break; - } - } - } - boolean hasReported = false; - if (this.recordedLocations != null) { - Iterator> locations = this.recordedLocations.entrySet().iterator(); - int reportFlags = 0; - while (locations.hasNext()) { - Entry entry = locations.next(); - reportFlags |= reportError(scope.problemReporter(), entry.getKey(), entry.getValue().intValue()); - hasReported = true; - } - if (reportFlags != 0) { - // after all locations have been reported, mark as reported to prevent duplicate report via an outer wrapper - current = this; - do { - current.globalClosingState |= reportFlags; - } while ((current = current.innerTracker) != null); - } - } - return hasReported; - } - - public boolean hasRecordedLocations() { - return this.recordedLocations != null; - } - - private boolean neverClosedAtLocations() { - if (this.recordedLocations != null) { - for (Object value : this.recordedLocations.values()) - if (!value.equals(FlowInfo.NULL)) - return false; - } - return true; - } - - public int reportError(ProblemReporter problemReporter, ASTNode location, int nullStatus) { - if (isNotOwned()) { - return 0; // TODO: should we still propagate some flags?? - } - // which degree of problem? - boolean isPotentialProblem = false; - if (nullStatus == FlowInfo.NULL) { - if ((this.globalClosingState & CLOSED_IN_NESTED_METHOD) != 0) - isPotentialProblem = true; - } else if ((nullStatus & (FlowInfo.POTENTIALLY_NULL|FlowInfo.POTENTIALLY_NON_NULL)) != 0) { - isPotentialProblem = true; - } - // report: - if (isPotentialProblem) { - if ((this.globalClosingState & (REPORTED_POTENTIAL_LEAK|REPORTED_DEFINITIVE_LEAK)) != 0) - return 0; -// if ((this.globalClosingState & (ACQUIRED_FROM_OUTSIDE)) != 0 -// && location instanceof ReturnStatement -// && ((ReturnStatement) location).expression == this.acquisition) -// return 0; // directly returning a resource acquired from a message send: don't assume responsibility - problemReporter.potentiallyUnclosedCloseable(this, location); - } else { - if ((this.globalClosingState & (REPORTED_DEFINITIVE_LEAK)) != 0) - return 0; - problemReporter.unclosedCloseable(this, location); - } - // propagate flag to inners: - int reportFlag = isPotentialProblem ? REPORTED_POTENTIAL_LEAK : REPORTED_DEFINITIVE_LEAK; - if (location == null) { // if location != null flags will be set after the loop over locations - markAllConnected(current -> current.globalClosingState |= reportFlag); - } - return reportFlag; - } - - public void reportExplicitClosing(ProblemReporter problemReporter) { - if (this.originalBinding != null && this.originalBinding.isParameter()) - return; - if ((this.globalClosingState & CLOSE_SEEN) == 0) - return; - if ((this.globalClosingState & (TWR_EFFECTIVELY_FINAL|OWNED_BY_OUTSIDE|REPORTED_EXPLICIT_CLOSE|FOREACH_ELEMENT_VAR)) == 0) { // can't use t-w-r for OWNED_BY_OUTSIDE - if (this.originalFieldBinding != null && this.blockScope instanceof MethodScope) { - AbstractMethodDeclaration method = ((MethodScope) this.blockScope).referenceMethod(); - if (method.binding != null && method.binding.isClosingMethod()) { - return; // this is the canonical close method, nothing to warn about. - } - } - this.globalClosingState |= REPORTED_EXPLICIT_CLOSE; - problemReporter.explicitlyClosedAutoCloseable(this); - } - } - - public String nameForReporting(ASTNode location, ReferenceContext referenceContext) { - if (this.name == UNASSIGNED_CLOSEABLE_NAME) { - if (location != null && referenceContext != null) { - CompilationResult compResult = referenceContext.compilationResult(); - if (compResult != null) { - int[] lineEnds = compResult.getLineSeparatorPositions(); - int resourceLine = Util.getLineNumber(this.sourceStart, lineEnds , 0, lineEnds.length-1); - int reportLine = Util.getLineNumber(location.sourceStart, lineEnds , 0, lineEnds.length-1); - if (resourceLine != reportLine) { - char[] replacement = Integer.toString(resourceLine).toCharArray(); - return String.valueOf(CharOperation.replace(UNASSIGNED_CLOSEABLE_NAME_TEMPLATE, TEMPLATE_ARGUMENT, replacement)); - } - } - } - } - if (this.originalFieldBinding != null) - return String.valueOf(CharOperation.concat(ConstantPool.This, this.name, '.')); - return String.valueOf(this.name); - } - - public void markAsShared() { - this.globalClosingState |= SHARED_WITH_OUTSIDE; - } - - public boolean isShared() { - return (this.globalClosingState & SHARED_WITH_OUTSIDE) != 0; - } - - protected boolean isNotOwned() { - if (this.useAnnotations) - return this.owningState < 0; - return (this.globalClosingState & OWNED_BY_OUTSIDE) != 0; - } - public boolean closeSeen() { - return (this.globalClosingState & CLOSE_SEEN) != 0; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java deleted file mode 100644 index 6c19fac..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FalseLiteral.java +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.impl.BooleanConstant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -public class FalseLiteral extends MagicLiteral { - - static final char[] source = {'f', 'a', 'l', 's', 'e'}; - -public FalseLiteral(int s , int e) { - super(s,e); -} -@Override -public void computeConstant() { - this.constant = BooleanConstant.fromValue(false); -} -/** - * Code generation for false literal - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} -@Override -public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - - // falseLabel being not nil means that we will not fall through into the FALSE case - - int pc = codeStream.position; - if (valueRequired) { - if (falseLabel != null) { - // implicit falling through the TRUE case - if (trueLabel == null) { - codeStream.goto_(falseLabel); - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} -@Override -public TypeBinding literalType(BlockScope scope) { - return TypeBinding.BOOLEAN; -} -@Override -public char[] source() { - return source; -} -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java deleted file mode 100644 index 092816d..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FieldDeclaration.java +++ /dev/null @@ -1,399 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation. - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 400761 - [compiler][null] null may be return as boolean without a diagnostic - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 429403 - [1.8][null] null mismatch from type arguments is not reported at field initializer - * Bug 453483 - [compiler][null][loop] Improve null analysis for loops - * Bug 458396 - NPE in CodeStream.invoke() - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 409250 - [1.8][compiler] Various loose ends in 308 code generation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.List; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.ASSIGNMENT_CONTEXT; - -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class FieldDeclaration extends AbstractVariableDeclaration { - - public FieldBinding binding; - public Javadoc javadoc; - - //allows to retrieve both the "type" part of the declaration (part1) - //and also the part that decribe the name and the init and optionally - //some other dimension ! .... - //public int[] a, b[] = X, c ; - //for b that would give for - // - part1 : public int[] - // - part2 : b[] = X, - - public int endPart1Position; - public int endPart2Position; - public boolean isARecordComponent; // used in record components - -public FieldDeclaration() { - // for subtypes or conversion -} - -public FieldDeclaration( char[] name, int sourceStart, int sourceEnd) { - this.name = name; - //due to some declaration like - // int x, y = 3, z , x ; - //the sourceStart and the sourceEnd is ONLY on the name - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; -} - -public FlowInfo analyseCode(MethodScope initializationScope, FlowContext flowContext, FlowInfo flowInfo) { - if (this.binding != null && !this.binding.isUsed() && this.binding.isOrEnclosedByPrivateType()) { - if (!initializationScope.referenceCompilationUnit().compilationResult.hasSyntaxError) { - if (!this.isARecordComponent) // record component used by implicit methods - initializationScope.problemReporter().unusedPrivateField(this); - } - } - // cannot define static non-constant field inside nested class - if (this.binding != null - && this.binding.isValidBinding() - && this.binding.isStatic() - && this.binding.constant(initializationScope) == Constant.NotAConstant - && this.binding.declaringClass.isNestedType() - && !this.binding.declaringClass.isStatic()) { - if (initializationScope.compilerOptions().sourceLevel < ClassFileConstants.JDK16) { - initializationScope.problemReporter().unexpectedStaticModifierForField( - (SourceTypeBinding) this.binding.declaringClass, - this); - } - } - - if (this.initialization != null) { - flowInfo = - this.initialization - .analyseCode(initializationScope, flowContext, flowInfo) - .unconditionalInits(); - flowInfo.markAsDefinitelyAssigned(this.binding); - } - CompilerOptions options = initializationScope.compilerOptions(); - if (this.initialization != null && this.binding != null) { - if (options.isAnnotationBasedNullAnalysisEnabled) { - if (this.binding.isNonNull() || options.sourceLevel >= ClassFileConstants.JDK1_8) { - int nullStatus = this.initialization.nullStatus(flowInfo, flowContext); - NullAnnotationMatching.checkAssignment(initializationScope, flowContext, this.binding, flowInfo, nullStatus, this.initialization, this.initialization.resolvedType); - } - } - this.initialization.checkNPEbyUnboxing(initializationScope, flowContext, flowInfo); - } - if (options.isAnnotationBasedResourceAnalysisEnabled - && this.binding != null - && this.binding.type.hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) - { - if ((this.binding.tagBits & TagBits.AnnotationOwning) == 0) { - initializationScope.problemReporter().shouldMarkFieldAsOwning(this); - } else if (!this.binding.declaringClass.hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable)) { - initializationScope.problemReporter().shouldImplementAutoCloseable(this); - } - } - return flowInfo; -} - -/** - * Code generation for a field declaration: - * standard assignment to a field - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & IsReachable) == 0) { - return; - } - // do not generate initialization code if final and static (constant is then - // recorded inside the field itself). - int pc = codeStream.position; - boolean isStatic; - if (this.initialization != null - && !((isStatic = this.binding.isStatic()) && this.binding.constant() != Constant.NotAConstant)) { - // non-static field, need receiver - if (!isStatic) - codeStream.aload_0(); - // generate initialization value - this.initialization.generateCode(currentScope, codeStream, true); - // store into field - if (isStatic) { - codeStream.fieldAccess(Opcodes.OPC_putstatic, this.binding, null /* default declaringClass */); - } else { - codeStream.fieldAccess(Opcodes.OPC_putfield, this.binding, null /* default declaringClass */); - } - } - // The fields escape CodeStream#exitUserScope(), and as a result end PC wouldn't be set. - // Set this explicitly (unlike a local declaration) -// if (this.initialization != null && this.initialization.containsPatternVariable()) { -// this.initialization.traverse(new ASTVisitor() { -// @Override -// public boolean visit( -// InstanceOfExpression instanceOfExpression, -// BlockScope scope) { -// instanceOfExpression.elementVariable.binding.recordInitializationEndPC(codeStream.position); -// return true; -// } -// }, currentScope); -// } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} -public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this.type, targetType, allAnnotationContexts); - for (int i = 0, max = this.annotations.length; i < max; i++) { - Annotation annotation = this.annotations[i]; - annotation.traverse(collector, (BlockScope) null); - } -} -/** - * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind() - */ -@Override -public int getKind() { - return this.type == null ? ENUM_CONSTANT : FIELD; -} - -public boolean isStatic() { - if (this.binding != null) - return this.binding.isStatic(); - return (this.modifiers & ClassFileConstants.AccStatic) != 0; -} - -public boolean isFinal() { - if (this.binding != null) - return this.binding.isFinal(); - return (this.modifiers & ClassFileConstants.AccFinal) != 0; -} -@Override -public StringBuilder print(int indent, StringBuilder output) { - if (this.isARecordComponent) - output.append("/* Implicit */"); //$NON-NLS-1$ - return super.print(indent, output); -} - -@Override -public StringBuilder printStatement(int indent, StringBuilder output) { - if (this.javadoc != null) { - this.javadoc.print(indent, output); - } - return super.printStatement(indent, output); -} - -public void resolve(MethodScope initializationScope) { - if (this.isUnnamed(initializationScope)) { - initializationScope.problemReporter().illegalUseOfUnderscoreAsAnIdentifier(this.sourceStart, this.sourceEnd, initializationScope.compilerOptions().sourceLevel > ClassFileConstants.JDK1_8, true); - } - - // the two could be regrouped into - // a single line but it is clearer to have two lines while the reason of their - // existence is not at all the same. See comment for the second one. - - //-------------------------------------------------------- - if ((this.bits & ASTNode.HasBeenResolved) != 0) return; - if (this.binding == null || !this.binding.isValidBinding()) return; - - this.bits |= ASTNode.HasBeenResolved; - - // check if field is hiding some variable - issue is that field binding already got inserted in scope - // thus must lookup separately in super type and outer context - ClassScope classScope = initializationScope.enclosingClassScope(); - - if (classScope != null) { - checkHiding: { - SourceTypeBinding declaringType = classScope.enclosingSourceType(); - checkHidingSuperField: { - if (declaringType.superclass == null) break checkHidingSuperField; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=318171, find field skipping visibility checks - // we do the checks below ourselves, using the appropriate conditions for access check of - // protected members from superclasses. - FieldBinding existingVariable = classScope.findField(declaringType.superclass, this.name, this, false /*do not resolve hidden field*/, true /* no visibility checks please */); - if (existingVariable == null) break checkHidingSuperField; // keep checking outer scenario - if (!existingVariable.isValidBinding()) break checkHidingSuperField; // keep checking outer scenario - if (existingVariable.original() == this.binding) break checkHidingSuperField; // keep checking outer scenario - if (!existingVariable.canBeSeenBy(declaringType, this, initializationScope)) break checkHidingSuperField; // keep checking outer scenario - // collision with supertype field - initializationScope.problemReporter().fieldHiding(this, existingVariable); - break checkHiding; // already found a matching field - } - // only corner case is: lookup of outer field through static declaringType, which isn't detected by #getBinding as lookup starts - // from outer scope. Subsequent static contexts are detected for free. - Scope outerScope = classScope.parent; - if (outerScope.kind == Scope.COMPILATION_UNIT_SCOPE) break checkHiding; - Binding existingVariable = outerScope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/); - if (existingVariable == null) break checkHiding; - if (!existingVariable.isValidBinding()) break checkHiding; - if (existingVariable == this.binding) break checkHiding; - if (existingVariable instanceof FieldBinding) { - FieldBinding existingField = (FieldBinding) existingVariable; - if (existingField.original() == this.binding) break checkHiding; - if (!existingField.isStatic() && declaringType.isStatic()) break checkHiding; - } - // collision with outer field or local variable - initializationScope.problemReporter().fieldHiding(this, existingVariable); - } - } - - if (this.type != null ) { // enum constants have no declared type - this.type.resolvedType = this.binding.type; // update binding for type reference - } - - FieldBinding previousField = initializationScope.initializedField; - int previousFieldID = initializationScope.lastVisibleFieldID; - try { - initializationScope.initializedField = this.binding; - initializationScope.lastVisibleFieldID = this.binding.id; - - resolveAnnotations(initializationScope, this.annotations, this.binding); - // Check if this declaration should now have the type annotations bit set - if (this.annotations != null) { - for (int i = 0, max = this.annotations.length; i < max; i++) { - TypeBinding resolvedAnnotationType = this.annotations[i].resolvedType; - if (resolvedAnnotationType != null && (resolvedAnnotationType.getAnnotationTagBits() & TagBits.AnnotationForTypeUse) != 0) { - this.bits |= ASTNode.HasTypeAnnotations; - break; - } - } - } - - // check @Deprecated annotation presence - if ((this.binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) == 0 - && (this.binding.modifiers & ClassFileConstants.AccDeprecated) != 0 - && initializationScope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { - initializationScope.problemReporter().missingDeprecatedAnnotationForField(this); - } - // the resolution of the initialization hasn't been done - if (this.initialization == null) { - this.binding.setConstant(Constant.NotAConstant); - } else { - // break dead-lock cycles by forcing constant to NotAConstant - this.binding.setConstant(Constant.NotAConstant); - - TypeBinding fieldType = this.binding.type; - TypeBinding initializationType; - this.initialization.setExpressionContext(ASSIGNMENT_CONTEXT); - this.initialization.setExpectedType(fieldType); // needed in case of generic method invocation - if (this.initialization instanceof ArrayInitializer) { - - if ((initializationType = this.initialization.resolveTypeExpecting(initializationScope, fieldType)) != null) { - ((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationType; - this.initialization.computeConversion(initializationScope, fieldType, initializationType); - } - } else if ((initializationType = this.initialization.resolveType(initializationScope)) != null) { - - if (TypeBinding.notEquals(fieldType, initializationType)) // must call before computeConversion() and typeMismatchError() - initializationScope.compilationUnitScope().recordTypeConversion(fieldType, initializationType); - if (this.initialization.isConstantValueOfTypeAssignableToType(initializationType, fieldType) - || initializationType.isCompatibleWith(fieldType, classScope)) { - this.initialization.computeConversion(initializationScope, fieldType, initializationType); - if (initializationType.needsUncheckedConversion(fieldType)) { - initializationScope.problemReporter().unsafeTypeConversion(this.initialization, initializationType, fieldType); - } - if (this.initialization instanceof CastExpression - && (this.initialization.bits & ASTNode.UnnecessaryCast) == 0) { - CastExpression.checkNeedForAssignedCast(initializationScope, fieldType, (CastExpression) this.initialization); - } - } else if (isBoxingCompatible(initializationType, fieldType, this.initialization, initializationScope)) { - this.initialization.computeConversion(initializationScope, fieldType, initializationType); - if (this.initialization instanceof CastExpression - && (this.initialization.bits & ASTNode.UnnecessaryCast) == 0) { - CastExpression.checkNeedForAssignedCast(initializationScope, fieldType, (CastExpression) this.initialization); - } - } else { - if (((fieldType.tagBits | initializationType.tagBits) & TagBits.HasMissingType) == 0) { - // if problem already got signaled on either type, do not report secondary problem - initializationScope.problemReporter().typeMismatchError(initializationType, fieldType, this.initialization, null); - } - } - if (this.binding.isFinal()){ // cast from constant actual type to variable type - this.binding.setConstant(this.initialization.constant.castTo((this.binding.type.id << 4) + this.initialization.constant.typeID())); - } - } else { - this.binding.setConstant(Constant.NotAConstant); - } - // check for assignment with no effect - if (this.binding == Expression.getDirectBinding(this.initialization)) { - initializationScope.problemReporter().assignmentHasNoEffect(this, this.name); - } - } - } finally { - initializationScope.initializedField = previousField; - initializationScope.lastVisibleFieldID = previousFieldID; - if (this.binding.constant(initializationScope) == null) - this.binding.setConstant(Constant.NotAConstant); - } -} -public void resolveJavadoc(MethodScope initializationScope) { - if (this.javadoc != null) { - FieldBinding previousField = initializationScope.initializedField; - int previousFieldID = initializationScope.lastVisibleFieldID; - try { - initializationScope.initializedField = this.binding; - if (this.binding != null) - initializationScope.lastVisibleFieldID = this.binding.id; - this.javadoc.resolve(initializationScope); - } finally { - initializationScope.initializedField = previousField; - initializationScope.lastVisibleFieldID = previousFieldID; - } - } else if (this.binding != null && this.binding.declaringClass != null && !this.binding.declaringClass.isLocalType()) { - // Set javadoc visibility - int javadocVisibility = this.binding.modifiers & ExtraCompilerModifiers.AccVisibilityMASK; - ProblemReporter reporter = initializationScope.problemReporter(); - int severity = reporter.computeSeverity(IProblem.JavadocMissing); - if (severity != ProblemSeverities.Ignore) { - ClassScope classScope = initializationScope.enclosingClassScope(); - if (classScope != null) { - javadocVisibility = Util.computeOuterMostVisibility(classScope.referenceType(), javadocVisibility); - } - int javadocModifiers = (this.binding.modifiers & ~ExtraCompilerModifiers.AccVisibilityMASK) | javadocVisibility; - reporter.javadocMissing(this.sourceStart, this.sourceEnd, severity, javadocModifiers); - } - } -} - -public void traverse(ASTVisitor visitor, MethodScope scope) { - if (visitor.visit(this, scope)) { - if (this.javadoc != null) { - this.javadoc.traverse(visitor, scope); - } - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, scope); - } - if (this.type != null) { - this.type.traverse(visitor, scope); - } - if (this.initialization != null) - this.initialization.traverse(visitor, scope); - } - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FieldReference.java deleted file mode 100644 index 282c891..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FieldReference.java +++ /dev/null @@ -1,797 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 185682 - Increment/decrement operators mark local variables as read - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * Bug 412203 - [compiler] Internal compiler error: java.lang.IllegalArgumentException: info cannot be null - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 458396 - NPE in CodeStream.invoke() - * Jesper S Moller - Contributions for - * Bug 378674 - "The method can be declared as static" is wrong - * Robert Roth - Contributions for - * Bug 361039 - NPE in FieldReference.optimizedBooleanConstant - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.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.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.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -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.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; - -public class FieldReference extends Reference implements InvocationSite { - - public static final int READ = 0; - public static final int WRITE = 1; - public Expression receiver; - public char[] token; - public FieldBinding binding; // exact binding resulting from lookup - public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor - - public long nameSourcePosition; //(start<<32)+end - public TypeBinding actualReceiverType; - public TypeBinding genericCast; - -public FieldReference(char[] source, long pos) { - this.token = source; - this.nameSourcePosition = pos; - //by default the position are the one of the field (not true for super access) - this.sourceStart = (int) (pos >>> 32); - this.sourceEnd = (int) (pos & 0x00000000FFFFFFFFL); - this.bits |= Binding.FIELD; - -} - -@Override -public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { - // compound assignment extra work - if (isCompound) { // check the variable part is initialized if blank final - if (this.binding.isBlankFinal() - && this.receiver.isThis() - && currentScope.needBlankFinalFieldInitializationCheck(this.binding)) { - FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(this.binding.declaringClass.original(), flowInfo); - if (!fieldInits.isDefinitelyAssigned(this.binding)) { - currentScope.problemReporter().uninitializedBlankFinalField(this.binding, this); - // we could improve error msg here telling "cannot use compound assignment on final blank field" - } - } - manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); - } - flowInfo = - this.receiver - .analyseCode(currentScope, flowContext, flowInfo, !this.binding.isStatic()) - .unconditionalInits(); - - this.receiver.checkNPE(currentScope, flowContext, flowInfo); - - if (assignment.expression != null) { - flowInfo = - assignment - .expression - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - } - manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/); - - // check if assigning a final field - if (this.binding.isFinal()) { - // in a context where it can be assigned? - if (this.binding.isBlankFinal() - && !isCompound - && this.receiver.isThis() - && !(this.receiver instanceof QualifiedThisReference) - && ((this.receiver.bits & ASTNode.ParenthesizedMASK) == 0) // (this).x is forbidden - && currentScope.allowBlankFinalFieldAssignment(this.binding) - && !currentScope.methodScope().isCompactConstructorScope) { - if (flowInfo.isPotentiallyAssigned(this.binding)) { - currentScope.problemReporter().duplicateInitializationOfBlankFinalField( - this.binding, - this); - } else { - flowContext.recordSettingFinal(this.binding, this, flowInfo); - } - flowInfo.markAsDefinitelyAssigned(this.binding); - } else { - if (currentScope.methodScope().isCompactConstructorScope) - currentScope.problemReporter().recordIllegalExplicitFinalFieldAssignInCompactConstructor(this.binding, this); - else - // assigning a final field outside an initializer or constructor or wrong reference - currentScope.problemReporter().cannotAssignToFinalField(this.binding, this); - } - } else if (this.binding.isNonNull() || this.binding.type.isTypeVariable()) { - // in a context where it can be assigned? - if ( !isCompound - && this.receiver.isThis() - && !(this.receiver instanceof QualifiedThisReference) - && TypeBinding.equalsEquals(this.receiver.resolvedType, this.binding.declaringClass) // inherited fields are not tracked here - && ((this.receiver.bits & ASTNode.ParenthesizedMASK) == 0)) { // (this).x is forbidden - flowInfo.markAsDefinitelyAssigned(this.binding); - } - } - return flowInfo; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return analyseCode(currentScope, flowContext, flowInfo, true); -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { - boolean nonStatic = !this.binding.isStatic(); - this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic); - if (nonStatic) { - this.receiver.checkNPE(currentScope, flowContext, flowInfo, 1); - } - - if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) { - manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); - } - if (currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_7) { - FieldBinding fieldBinding = this.binding; - if (this.receiver.isThis() && fieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { - FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo); - if (!fieldInits.isDefinitelyAssigned(fieldBinding)) { - currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); - } - } - } - return flowInfo; -} - -@Override -public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - if (flowContext.isNullcheckedFieldAccess(this)) { - return true; // enough seen - } - return checkNullableFieldDereference(scope, this.binding, this.nameSourcePosition, flowContext, ttlForFieldCheck); -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) - */ -@Override -public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { - if (runtimeTimeType == null || compileTimeType == null) - return; - // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast) - if (this.binding != null && this.binding.isValidBinding()) { - FieldBinding originalBinding = this.binding.original(); - TypeBinding originalType = originalBinding.type; - // extra cast needed if field type is type variable - if (originalType.leafComponentType().isTypeVariable()) { - TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) - ? compileTimeType // unboxing: checkcast before conversion - : runtimeTimeType; - this.genericCast = originalBinding.type.genericCast(targetType); - if (this.genericCast instanceof ReferenceBinding) { - ReferenceBinding referenceCast = (ReferenceBinding) this.genericCast; - if (!referenceCast.canBeSeenBy(scope)) { - scope.problemReporter().invalidType(this, - new ProblemReferenceBinding( - CharOperation.splitOn('.', referenceCast.shortReadableName()), - referenceCast, - ProblemReasons.NotVisible)); - } - } - } - } - super.computeConversion(scope, runtimeTimeType, compileTimeType); -} - -@Override -public FieldBinding fieldBinding() { - return this.binding; -} - -@Override -public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { - int pc = codeStream.position; - FieldBinding codegenBinding = this.binding.original(); - this.receiver.generateCode(currentScope, codeStream, !codegenBinding.isStatic()); - codeStream.recordPositionsFrom(pc, this.sourceStart); - assignment.expression.generateCode(currentScope, codeStream, true); - fieldStore(currentScope, codeStream, codegenBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[FieldReference.WRITE], this.actualReceiverType, this.receiver.isImplicitThis(), valueRequired); - if (valueRequired) { - codeStream.generateImplicitConversion(assignment.implicitConversion); - } - // no need for generic cast as value got dupped -} - -/** - * Field reference code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (this.constant != Constant.NotAConstant) { - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - FieldBinding codegenBinding = this.binding.original(); - boolean isStatic = codegenBinding.isStatic(); - boolean isThisReceiver = this.receiver instanceof ThisReference; - Constant fieldConstant = codegenBinding.constant(); - if (fieldConstant != Constant.NotAConstant) { - if (!isThisReceiver) { - this.receiver.generateCode(currentScope, codeStream, !isStatic); - if (!isStatic){ - codeStream.invokeObjectGetClass(); - codeStream.pop(); - } - } - if (valueRequired) { - codeStream.generateConstant(fieldConstant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - if (valueRequired - || (!isThisReceiver && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) - || ((this.implicitConversion & TypeIds.UNBOXING) != 0) - || (this.genericCast != null)) { - this.receiver.generateCode(currentScope, codeStream, !isStatic); - if ((this.bits & NeedReceiverGenericCast) != 0) { - codeStream.checkcast(this.actualReceiverType); - } - pc = codeStream.position; - if (codegenBinding.declaringClass == null) { // array length - codeStream.arraylength(); - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - // could occur if !valueRequired but compliance >= 1.4 - codeStream.pop(); - } - } else { - if (this.syntheticAccessors == null || this.syntheticAccessors[FieldReference.READ] == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis()); - if (isStatic) { - codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenBinding, constantPoolDeclaringClass); - } else { - codeStream.fieldAccess(Opcodes.OPC_getfield, codegenBinding, constantPoolDeclaringClass); - } - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[FieldReference.READ], null /* default declaringClass */); - } - // required cast must occur even if no value is required - if (this.genericCast != null) codeStream.checkcast(this.genericCast); - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; - // conversion only generated if unboxing - if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion); - switch (isUnboxing ? postConversionType(currentScope).id : codegenBinding.type.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - } - } - } - } else { - if (isThisReceiver) { - if (isStatic){ - // if no valueRequired, still need possible side-effects of invocation, if field belongs to different class - if (TypeBinding.notEquals(this.binding.original().declaringClass, this.actualReceiverType.erasure())) { - MethodBinding accessor = this.syntheticAccessors == null ? null : this.syntheticAccessors[FieldReference.READ]; - if (accessor == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis()); - codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */); - } - switch (codegenBinding.type.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - } - } - } - } else { - this.receiver.generateCode(currentScope, codeStream, !isStatic); - if (!isStatic){ - codeStream.invokeObjectGetClass(); // perform null check - codeStream.pop(); - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceEnd); -} - -@Override -public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { - boolean isStatic; - // check if compound assignment is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired); - FieldBinding codegenBinding = this.binding.original(); - this.receiver.generateCode(currentScope, codeStream, !(isStatic = codegenBinding.isStatic())); - if (isStatic) { - if (this.syntheticAccessors == null || this.syntheticAccessors[FieldReference.READ] == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis()); - codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[FieldReference.READ], null /* default declaringClass */); - } - } else { - codeStream.dup(); - if (this.syntheticAccessors == null || this.syntheticAccessors[FieldReference.READ] == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis()); - codeStream.fieldAccess(Opcodes.OPC_getfield, codegenBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[FieldReference.READ], null /* default declaringClass */); - } - } - int operationTypeID; - switch(operationTypeID = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { - case T_JavaLangString : - case T_JavaLangObject : - case T_undefined : - codeStream.generateStringConcatenationAppend(currentScope, null, expression); - break; - default : - if (this.genericCast != null) - codeStream.checkcast(this.genericCast); - // promote the array reference to the suitable operation type - codeStream.generateImplicitConversion(this.implicitConversion); - // generate the increment value (will by itself be promoted to the operation value) - if (expression == IntLiteral.One) { // prefix operation - codeStream.generateConstant(expression.constant, this.implicitConversion); - } else { - expression.generateCode(currentScope, codeStream, true); - } - // perform the operation - codeStream.sendOperator(operator, operationTypeID); - // cast the value back to the array reference type - codeStream.generateImplicitConversion(assignmentImplicitConversion); - } - fieldStore(currentScope, codeStream, codegenBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[FieldReference.WRITE], this.actualReceiverType, this.receiver.isImplicitThis(), valueRequired); - // no need for generic cast as value got dupped -} - -@Override -public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { - boolean isStatic; - // check if postIncrement is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, this.binding, valueRequired); - FieldBinding codegenBinding = this.binding.original(); - this.receiver.generateCode(currentScope, codeStream, !(isStatic = codegenBinding.isStatic())); - if (isStatic) { - if (this.syntheticAccessors == null || this.syntheticAccessors[FieldReference.READ] == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis()); - codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[FieldReference.READ], null /* default declaringClass */); - } - } else { - codeStream.dup(); - if (this.syntheticAccessors == null || this.syntheticAccessors[FieldReference.READ] == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis()); - codeStream.fieldAccess(Opcodes.OPC_getfield, codegenBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[FieldReference.READ], null /* default declaringClass */); - } - } - TypeBinding operandType; - if (this.genericCast != null) { - codeStream.checkcast(this.genericCast); - operandType = this.genericCast; - } else { - operandType = codegenBinding.type; - } - if (valueRequired) { - if (isStatic) { - switch (operandType.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2(); - break; - default : - codeStream.dup(); - break; - } - } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] - switch (operandType.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2_x1(); - break; - default : - codeStream.dup_x1(); - break; - } - } - } - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateConstant( - postIncrement.expression.constant, - this.implicitConversion); - codeStream.sendOperator(postIncrement.operator, this.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.generateImplicitConversion( - postIncrement.preAssignImplicitConversion); - fieldStore(currentScope, codeStream, codegenBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[FieldReference.WRITE], this.actualReceiverType, this.receiver.isImplicitThis(), false); -} - -/** - * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() - */ -@Override -public TypeBinding[] genericTypeArguments() { - return null; -} - -@Override -public InferenceContext18 freshInferenceContext(Scope scope) { - return null; -} - -@Override -public boolean isEquivalent(Reference reference) { - // only consider field references relative to "this": - if (this.receiver.isThis() && !(this.receiver instanceof QualifiedThisReference)) { - // current is a simple "this.f1" - char[] otherToken = null; - // matching 'reference' could be "f1" or "this.f1": - if (reference instanceof SingleNameReference) { - otherToken = ((SingleNameReference) reference).token; - } else if (reference instanceof FieldReference) { - FieldReference fr = (FieldReference) reference; - if (fr.receiver.isThis() && !(fr.receiver instanceof QualifiedThisReference)) { - otherToken = fr.token; - } - } - return otherToken != null && CharOperation.equals(this.token, otherToken); - } else { - // search deeper for "this" inside: - char[][] thisTokens = getThisFieldTokens(1); - if (thisTokens == null) { - return false; - } - // other can be "this.f1.f2", too, or "f1.f2": - char[][] otherTokens = null; - if (reference instanceof FieldReference) { - otherTokens = ((FieldReference) reference).getThisFieldTokens(1); - } else if (reference instanceof QualifiedNameReference) { - if (((QualifiedNameReference)reference).binding instanceof LocalVariableBinding) - return false; // initial variable mismatch: local (from f1.f2) vs. field (from this.f1.f2) - otherTokens = ((QualifiedNameReference) reference).tokens; - } - return CharOperation.equals(thisTokens, otherTokens); - } -} - -private char[][] getThisFieldTokens(int nestingCount) { - char[][] result = null; - if (this.receiver.isThis() && ! (this.receiver instanceof QualifiedThisReference)) { - // found an inner-most this-reference, start building the token array: - result = new char[nestingCount][]; - // fill it front to tail while traveling back out: - result[0] = this.token; - } else if (this.receiver instanceof FieldReference) { - result = ((FieldReference)this.receiver).getThisFieldTokens(nestingCount+1); - if (result != null) { - // front to tail: outermost is last: - result[result.length-nestingCount] = this.token; - } - } - return result; -} - -@Override -public boolean isSuperAccess() { - return this.receiver.isSuper(); -} - -@Override -public boolean isQualifiedSuper() { - return this.receiver.isQualifiedSuper(); -} - -@Override -public boolean isTypeAccess() { - return this.receiver != null && this.receiver.isTypeReference(); -} - -@Override -public FieldBinding lastFieldBinding() { - return this.binding; -} - -/* - * No need to emulate access to protected fields since not implicitly accessed - */ -public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return; - - // if field from parameterized type got found, use the original field at codegen time - FieldBinding codegenBinding = this.binding.original(); - if (this.binding.isPrivate()) { - if (!currentScope.enclosingSourceType().isNestmateOf(codegenBinding.declaringClass) && - (TypeBinding.notEquals(currentScope.enclosingSourceType(), codegenBinding.declaringClass)) - && this.binding.constant(currentScope) == Constant.NotAConstant) { - if (this.syntheticAccessors == null) - this.syntheticAccessors = new MethodBinding[2]; - this.syntheticAccessors[isReadAccess ? FieldReference.READ : FieldReference.WRITE] = - ((SourceTypeBinding) codegenBinding.declaringClass).addSyntheticMethod(codegenBinding, isReadAccess, false /* not super ref in remote type*/); - currentScope.problemReporter().needToEmulateFieldAccess(codegenBinding, this, isReadAccess); - return; - } - } else if (this.receiver instanceof QualifiedSuperReference) { // qualified super - // qualified super need emulation always - SourceTypeBinding destinationType = (SourceTypeBinding) (((QualifiedSuperReference) this.receiver).currentCompatibleType); - if (this.syntheticAccessors == null) - this.syntheticAccessors = new MethodBinding[2]; - this.syntheticAccessors[isReadAccess ? FieldReference.READ : FieldReference.WRITE] = destinationType.addSyntheticMethod(codegenBinding, isReadAccess, isSuperAccess()); - currentScope.problemReporter().needToEmulateFieldAccess(codegenBinding, this, isReadAccess); - return; - - } else if (this.binding.isProtected()) { - SourceTypeBinding enclosingSourceType; - if (((this.bits & ASTNode.DepthMASK) != 0) - && this.binding.declaringClass.getPackage() - != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) { - - SourceTypeBinding currentCompatibleType = - (SourceTypeBinding) enclosingSourceType.enclosingTypeAt( - (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); - if (this.syntheticAccessors == null) - this.syntheticAccessors = new MethodBinding[2]; - this.syntheticAccessors[isReadAccess ? FieldReference.READ : FieldReference.WRITE] = currentCompatibleType.addSyntheticMethod(codegenBinding, isReadAccess, isSuperAccess()); - currentScope.problemReporter().needToEmulateFieldAccess(codegenBinding, this, isReadAccess); - return; - } - } -} - -@Override -public Constant optimizedBooleanConstant() { - if (this.resolvedType == null) - return Constant.NotAConstant; - switch (this.resolvedType.id) { - case T_boolean : - case T_JavaLangBoolean : - return this.constant != Constant.NotAConstant ? this.constant : this.binding.constant(); - default : - return Constant.NotAConstant; - } -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope) - */ -@Override -public TypeBinding postConversionType(Scope scope) { - TypeBinding convertedType = this.resolvedType; - if (this.genericCast != null) - convertedType = this.genericCast; - int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; - switch (runtimeType) { - case T_boolean : - convertedType = TypeBinding.BOOLEAN; - break; - case T_byte : - convertedType = TypeBinding.BYTE; - break; - case T_short : - convertedType = TypeBinding.SHORT; - break; - case T_char : - convertedType = TypeBinding.CHAR; - break; - case T_int : - convertedType = TypeBinding.INT; - break; - case T_float : - convertedType = TypeBinding.FLOAT; - break; - case T_long : - convertedType = TypeBinding.LONG; - break; - case T_double : - convertedType = TypeBinding.DOUBLE; - break; - default : - } - if ((this.implicitConversion & TypeIds.BOXING) != 0) { - convertedType = scope.environment().computeBoxingType(convertedType); - } - return convertedType; -} - -@Override -public StringBuilder printExpression(int indent, StringBuilder output) { - return this.receiver.printExpression(0, output).append('.').append(this.token); -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - // Answer the signature type of the field. - // constants are propaged when the field is final - // and initialized with a (compile time) constant - - //always ignore receiver cast, since may affect constant pool reference - boolean receiverCast = false; - if (this.receiver instanceof CastExpression) { - this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - receiverCast = true; - } - this.actualReceiverType = this.receiver.resolveType(scope); - if (this.actualReceiverType == null) { - this.constant = Constant.NotAConstant; - return null; - } - if (receiverCast) { - // due to change of declaring class with receiver type, only identity cast should be notified - if (TypeBinding.equalsEquals(((CastExpression)this.receiver).expression.resolvedType, this.actualReceiverType)) { - scope.problemReporter().unnecessaryCast((CastExpression)this.receiver); - } - } - // the case receiverType.isArrayType and token = 'length' is handled by the scope API - FieldBinding fieldBinding = this.binding = scope.getField(this.actualReceiverType, this.token, this); - if (!fieldBinding.isValidBinding()) { - this.constant = Constant.NotAConstant; - if (this.receiver.resolvedType instanceof ProblemReferenceBinding) { - // problem already got signaled on receiver, do not report secondary problem - return null; - } - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=245007 avoid secondary errors in case of - // missing super type for anonymous classes ... - ReferenceBinding declaringClass = fieldBinding.declaringClass; - boolean avoidSecondary = declaringClass != null && - declaringClass.isAnonymousType() && - declaringClass.superclass() instanceof MissingTypeBinding; - if (!avoidSecondary) { - scope.problemReporter().invalidField(this, this.actualReceiverType); - } - if (fieldBinding instanceof ProblemFieldBinding) { - ProblemFieldBinding problemFieldBinding = (ProblemFieldBinding) fieldBinding; - FieldBinding closestMatch = problemFieldBinding.closestMatch; - switch(problemFieldBinding.problemId()) { - case ProblemReasons.InheritedNameHidesEnclosingName : - case ProblemReasons.NotVisible : - case ProblemReasons.NonStaticReferenceInConstructorInvocation : - case ProblemReasons.NonStaticReferenceInStaticContext : - if (closestMatch != null) { - fieldBinding = closestMatch; - } - } - } - if (!fieldBinding.isValidBinding()) { - return null; - } - } - // handle indirect inheritance thru variable secondary bound - // receiver may receive generic cast, as part of implicit conversion - TypeBinding oldReceiverType = this.actualReceiverType; - this.actualReceiverType = this.actualReceiverType.getErasureCompatibleType(fieldBinding.declaringClass); - this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType); - if (TypeBinding.notEquals(this.actualReceiverType, oldReceiverType) && TypeBinding.notEquals(this.receiver.postConversionType(scope), this.actualReceiverType)) { // record need for explicit cast at codegen since receiver could not handle it - this.bits |= NeedReceiverGenericCast; - } - if (isFieldUseDeprecated(fieldBinding, scope, this.bits)) { - scope.problemReporter().deprecatedField(fieldBinding, this); - } - boolean isImplicitThisRcv = this.receiver.isImplicitThis(); - this.constant = isImplicitThisRcv ? fieldBinding.constant(scope) : Constant.NotAConstant; - if (fieldBinding.isStatic()) { - // static field accessed through receiver? legal but unoptimal (optional warning) - if (!(isImplicitThisRcv - || (this.receiver instanceof NameReference - && (((NameReference) this.receiver).bits & Binding.TYPE) != 0))) { - scope.problemReporter().nonStaticAccessToStaticField(this, fieldBinding); - } - ReferenceBinding declaringClass = this.binding.declaringClass; - if (!isImplicitThisRcv - && TypeBinding.notEquals(declaringClass, this.actualReceiverType) - && declaringClass.canBeSeenBy(scope)) { - scope.problemReporter().indirectAccessToStaticField(this, fieldBinding); - } - // check if accessing enum static field in initializer - if (declaringClass.isEnum() && scope.kind != Scope.MODULE_SCOPE) { - MethodScope methodScope = scope.methodScope(); - SourceTypeBinding sourceType = scope.enclosingSourceType(); - if (this.constant == Constant.NotAConstant - && !methodScope.isStatic - && (TypeBinding.equalsEquals(sourceType, declaringClass) || TypeBinding.equalsEquals(sourceType.superclass, declaringClass)) // enum constant body - && methodScope.isInsideInitializerOrConstructor()) { - scope.problemReporter().enumStaticFieldUsedDuringInitialization(this.binding, this); - } - } - } - TypeBinding fieldType = fieldBinding.type; - if (fieldType != null) { - if ((this.bits & ASTNode.IsStrictlyAssigned) == 0) { - fieldType = fieldType.capture(scope, this.sourceStart, this.sourceEnd); // perform capture conversion if read access - } - this.resolvedType = fieldType; - if ((fieldType.tagBits & TagBits.HasMissingType) != 0) { - scope.problemReporter().invalidType(this, fieldType); - return null; - } - } - return fieldType; -} - -@Override -public void setActualReceiverType(ReferenceBinding receiverType) { - this.actualReceiverType = receiverType; -} - -@Override -public void setDepth(int depth) { - this.bits &= ~ASTNode.DepthMASK; // flush previous depth if any - if (depth > 0) { - this.bits |= (depth & 0xFF) << ASTNode.DepthSHIFT; // encoded on 8 bits - } -} - -@Override -public void setFieldIndex(int index) { - // ignored -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.receiver.traverse(visitor, scope); - } - visitor.endVisit(this, scope); -} - -@Override -public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotations) { - if (this.binding != null) { - if (supportTypeAnnotations - || ((this.binding.tagBits & TagBits.AnnotationNullMASK) != 0)) { - return this.binding; - } - } - return null; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java deleted file mode 100644 index 039e2ad..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FloatLiteral.java +++ /dev/null @@ -1,132 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.impl.FloatConstant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.util.FloatUtil; - -public class FloatLiteral extends NumberLiteral { - - float value; - -public FloatLiteral(char[] token, int s, int e) { - super(token, s, e); -} - -@Override -public void computeConstant() { - Float computedValue; - boolean containsUnderscores = CharOperation.indexOf('_', this.source) > 0; - if (containsUnderscores) { - // remove all underscores from source - this.source = CharOperation.remove(this.source, '_'); - } - try { - computedValue = Float.valueOf(String.valueOf(this.source)); - } catch (NumberFormatException e) { - // hex floating point literal - // being rejected by 1.4 libraries where Float.valueOf(...) doesn't handle hex decimal floats - try { - float v = FloatUtil.valueOfHexFloatLiteral(this.source); - if (v == Float.POSITIVE_INFINITY) { - // error: the number is too large to represent - return; - } - if (Float.isNaN(v)) { - // error: the number is too small to represent - return; - } - this.value = v; - this.constant = FloatConstant.fromValue(v); - } catch (NumberFormatException e1) { - // if the computation of the constant fails - } - return; - } - final float floatValue = computedValue.floatValue(); - if (floatValue > Float.MAX_VALUE) { - // error: the number is too large to represent - return; - } - if (floatValue < Float.MIN_VALUE) { - // see 1F6IGUU - // a true 0 only has '0' and '.' in mantissa - // 1.0e-5000d is non-zero, but underflows to 0 - boolean isHexaDecimal = false; - label : for (int i = 0; i < this.source.length; i++) { //it is welled formated so just test against '0' and potential . D d - switch (this.source[i]) { - case '0' : - case '.' : - break; - case 'x' : - case 'X' : - isHexaDecimal = true; - break; - case 'e' : - case 'E' : - case 'f' : - case 'F' : - case 'd' : - case 'D' : - if (isHexaDecimal) { - return; - } - // starting the exponent - mantissa is all zero - // no exponent - mantissa is all zero - break label; - case 'p' : - case 'P' : - break label; - default : - // error: the number is too small to represent - return; - } - } - } - this.value = floatValue; - this.constant = FloatConstant.fromValue(this.value); -} - -/** - * Code generation for float literal - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public TypeBinding literalType(BlockScope scope) { - return TypeBinding.FLOAT; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ForStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ForStatement.java deleted file mode 100644 index 0c01200..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ForStatement.java +++ /dev/null @@ -1,511 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * 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 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 415790 - [compiler][resource]Incorrect potential resource leak warning in for loop with close in try/catch - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -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.flow.LoopingFlowContext; -import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -public class ForStatement extends Statement { - - public Statement[] initializations; - public Expression condition; - public Statement[] increments; - public Statement action; - - //when there is no local declaration, there is no need of a new scope - //scope is positioned either to a new scope, or to the "upper"scope (see resolveType) - public BlockScope scope; - - private BranchLabel breakLabel, continueLabel; - - // for local variables table attributes - int preCondInitStateIndex = -1; - int preIncrementsInitStateIndex = -1; - int condIfTrueInitStateIndex = -1; - int mergedInitStateIndex = -1; - - public ForStatement( - Statement[] initializations, - Expression condition, - Statement[] increments, - Statement action, - boolean neededScope, - int s, - int e) { - - this.sourceStart = s; - this.sourceEnd = e; - this.initializations = initializations; - this.condition = condition; - this.increments = increments; - this.action = action; - // remember useful empty statement - if (action instanceof EmptyStatement) action.bits |= ASTNode.IsUsefulEmptyStatement; - if (neededScope) { - this.bits |= ASTNode.NeededScope; - } - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - this.breakLabel = new BranchLabel(); - this.continueLabel = new BranchLabel(); - int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; - - // process the initializations - if (this.initializations != null) { - for (int i = 0, count = this.initializations.length; i < count; i++) { - flowInfo = this.initializations[i].analyseCode(this.scope, flowContext, flowInfo); - } - } - this.preCondInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); - - Constant cst = this.condition == null ? null : this.condition.constant; - boolean isConditionTrue = cst == null || (cst != Constant.NotAConstant && cst.booleanValue() == true); - boolean isConditionFalse = cst != null && (cst != Constant.NotAConstant && cst.booleanValue() == false); - - cst = this.condition == null ? null : this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst == null || (cst != Constant.NotAConstant && cst.booleanValue() == true); - boolean isConditionOptimizedFalse = cst != null && (cst != Constant.NotAConstant && cst.booleanValue() == false); - - // process the condition - LoopingFlowContext condLoopContext = null; - FlowInfo condInfo = flowInfo.nullInfoLessUnconditionalCopy(); - if (this.condition != null) { - if (!isConditionTrue) { - condInfo = - this.condition.analyseCode( - this.scope, - (condLoopContext = - new LoopingFlowContext(flowContext, flowInfo, this, null, - null, this.scope, true)), - condInfo); - this.condition.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - } - } - - // process the action - LoopingFlowContext loopingContext; - UnconditionalFlowInfo actionInfo; - if (this.action == null - || (this.action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) { - if (condLoopContext != null) - condLoopContext.complainOnDeferredFinalChecks(this.scope, condInfo); - if (isConditionTrue) { - if (condLoopContext != null) { - condLoopContext.complainOnDeferredNullChecks(currentScope, - condInfo); - } - return FlowInfo.DEAD_END; - } else { - if (isConditionFalse){ - this.continueLabel = null; // for(;false;p()); - } - actionInfo = condInfo.initsWhenTrue().unconditionalCopy(); - loopingContext = - new LoopingFlowContext(flowContext, flowInfo, this, - this.breakLabel, this.continueLabel, this.scope, false); - // there is no action guarded by a preTest, so we use preTest=false - // to avoid pointless burdens of updating FlowContext.conditionalLevel - } - } - else { - loopingContext = - new LoopingFlowContext(flowContext, flowInfo, this, this.breakLabel, - this.continueLabel, this.scope, true); - FlowInfo initsWhenTrue = condInfo.initsWhenTrue(); - this.condIfTrueInitStateIndex = - currentScope.methodScope().recordInitializationStates(initsWhenTrue); - - if (isConditionFalse) { - actionInfo = FlowInfo.DEAD_END; - } else { - actionInfo = initsWhenTrue.unconditionalCopy(); - if (isConditionOptimizedFalse){ - actionInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - } - if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) { - if (this.condition != null) - this.condition.updateFlowOnBooleanResult(actionInfo, true); - actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalInits(); - } - - // code generation can be optimized when no need to continue in the loop - if ((actionInfo.tagBits & - loopingContext.initsOnContinue.tagBits & - FlowInfo.UNREACHABLE_OR_DEAD) != 0) { - this.continueLabel = null; - } - else { - if (condLoopContext != null) { - condLoopContext.complainOnDeferredFinalChecks(this.scope, - condInfo); - } - actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue); - loopingContext.complainOnDeferredFinalChecks(this.scope, - actionInfo); - } - } - // for increments - FlowInfo exitBranch = flowInfo.copy(); - // recover null inits from before condition analysis - LoopingFlowContext incrementContext = null; - if (this.continueLabel != null) { - if (this.increments != null) { - incrementContext = - new LoopingFlowContext(flowContext, flowInfo, this, null, - null, this.scope, true); - FlowInfo incrementInfo = actionInfo; - this.preIncrementsInitStateIndex = - currentScope.methodScope().recordInitializationStates(incrementInfo); - for (int i = 0, count = this.increments.length; i < count; i++) { - incrementInfo = this.increments[i]. - analyseCode(this.scope, incrementContext, incrementInfo); - } - incrementContext.complainOnDeferredFinalChecks(this.scope, - actionInfo = incrementInfo.unconditionalInits()); - } - exitBranch.addPotentialInitializationsFrom(actionInfo). - addInitializationsFrom(condInfo.initsWhenFalse()); - } else { - exitBranch.addInitializationsFrom(condInfo.initsWhenFalse()); - if (this.increments != null) { - if (initialComplaintLevel == Statement.NOT_COMPLAINED) { - currentScope.problemReporter().fakeReachable(this.increments[0]); - } - } - } - // nulls checks - if (condLoopContext != null) { - condLoopContext.complainOnDeferredNullChecks(currentScope, - actionInfo); - } - loopingContext.complainOnDeferredNullChecks(currentScope, - actionInfo); - if (incrementContext != null) { - incrementContext.complainOnDeferredNullChecks(currentScope, - actionInfo); - } - if (loopingContext.hasEscapingExceptions()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=321926 - FlowInfo loopbackFlowInfo = flowInfo.copy(); - if (this.continueLabel != null) { // we do get to the bottom - // loopback | (loopback + action): - loopbackFlowInfo = loopbackFlowInfo.mergedWith(loopbackFlowInfo.unconditionalCopy().addNullInfoFrom(actionInfo).unconditionalInits()); - } - loopingContext.simulateThrowAfterLoopBack(loopbackFlowInfo); - } - //end of loop - FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( - (loopingContext.initsOnBreak.tagBits & - FlowInfo.UNREACHABLE) != 0 ? - loopingContext.initsOnBreak : - flowInfo.addInitializationsFrom(loopingContext.initsOnBreak), // recover upstream null info - isConditionOptimizedTrue, - 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); - this.scope.checkUnclosedCloseables(mergedInfo, loopingContext, null, null); - if (this.condition != null) - this.condition.updateFlowOnBooleanResult(mergedInfo, false); - return mergedInfo; - } - /** - * For statement code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - - // generate the initializations - if (this.initializations != null) { - for (int i = 0, max = this.initializations.length; i < max; i++) { - this.initializations[i].generateCode(this.scope, codeStream); - } - } - if (containsPatternVariable()) { - this.condition.addPatternVariables(currentScope, codeStream); - } - Constant cst = this.condition == null ? null : this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedFalse = cst != null && (cst != Constant.NotAConstant && cst.booleanValue() == false); - if (isConditionOptimizedFalse) { - this.condition.generateCode(this.scope, codeStream, false); - // May loose some local variable initializations : affecting the local variable attributes - if ((this.bits & ASTNode.NeededScope) != 0) { - codeStream.exitUserScope(this.scope); - } - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - - // label management - BranchLabel actionLabel = new BranchLabel(codeStream); - actionLabel.tagBits |= BranchLabel.USED; - BranchLabel conditionLabel = new BranchLabel(codeStream); - this.breakLabel.initialize(codeStream); - if (this.continueLabel == null) { - conditionLabel.place(); - if ((this.condition != null) && (this.condition.constant == Constant.NotAConstant)) { - this.condition.generateOptimizedBoolean(this.scope, codeStream, null, this.breakLabel, true); - } - } else { - this.continueLabel.initialize(codeStream); - // jump over the actionBlock - if ((this.condition != null) - && (this.condition.constant == Constant.NotAConstant) - && !((this.action == null || this.action.isEmptyBlock()) && (this.increments == null))) { - conditionLabel.tagBits |= BranchLabel.USED; - int jumpPC = codeStream.position; - codeStream.goto_(conditionLabel); - codeStream.recordPositionsFrom(jumpPC, this.condition.sourceStart); - } - } - - // generate the loop action - if (this.action != null) { - // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect - if (this.condIfTrueInitStateIndex != -1) { - // insert all locals initialized inside the condition into the action generated prior to the condition - codeStream.addDefinitelyAssignedVariables( - currentScope, - this.condIfTrueInitStateIndex); - } - actionLabel.place(); - this.action.generateCode(this.scope, codeStream); - } else { - actionLabel.place(); - } - if (this.preIncrementsInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preIncrementsInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.preIncrementsInitStateIndex); - } - // continuation point - if (this.continueLabel != null) { - this.continueLabel.place(); - // generate the increments for next iteration - if (this.increments != null) { - for (int i = 0, max = this.increments.length; i < max; i++) { - this.increments[i].generateCode(this.scope, codeStream); - } - } - // May loose some local variable initializations : affecting the local variable attributes - // This is causing PatternMatching14Test.test039() to fail - if (this.preCondInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preCondInitStateIndex); - } - // generate the condition - conditionLabel.place(); - if ((this.condition != null) && (this.condition.constant == Constant.NotAConstant)) { - this.condition.generateOptimizedBoolean(this.scope, codeStream, actionLabel, null, true); - } else { - codeStream.goto_(actionLabel); - } - - } else { - // May loose some local variable initializations : affecting the local variable attributes - if (this.preCondInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preCondInitStateIndex); - } - } - - - // May loose some local variable initializations : affecting the local variable attributes - if ((this.bits & ASTNode.NeededScope) != 0) { - codeStream.exitUserScope(this.scope); - } - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - this.breakLabel.place(); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public StringBuilder printStatement(int tab, StringBuilder output) { - - printIndent(tab, output).append("for ("); //$NON-NLS-1$ - //inits - if (this.initializations != null) { - for (int i = 0; i < this.initializations.length; i++) { - //nice only with expressions - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.initializations[i].print(0, output); - } - } - output.append("; "); //$NON-NLS-1$ - //cond - if (this.condition != null) this.condition.printExpression(0, output); - output.append("; "); //$NON-NLS-1$ - //updates - if (this.increments != null) { - for (int i = 0; i < this.increments.length; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.increments[i].print(0, output); - } - } - output.append(") "); //$NON-NLS-1$ - //block - if (this.action == null) - output.append(';'); - else { - output.append('\n'); - this.action.printStatement(tab + 1, output); - } - return output; - } - - @Override - public LocalVariableBinding[] bindingsWhenComplete() { - return this.condition != null && this.condition.containsPatternVariable() && this.action != null && !this.action.breaksOut(null) ? - this.condition.bindingsWhenFalse() : NO_VARIABLES; - } - - @Override - public void resolve(BlockScope upperScope) { - LocalVariableBinding[] patternVariablesInTrueScope = NO_VARIABLES; - - // use the scope that will hold the init declarations - this.scope = (this.bits & ASTNode.NeededScope) != 0 ? new BlockScope(upperScope) : upperScope; - if (this.initializations != null) - for (int i = 0, length = this.initializations.length; i < length; i++) - this.initializations[i].resolve(this.scope); - if (this.condition != null) { - if ((this.bits & ASTNode.NeededScope) != 0) { - // We have created a new scope for for-inits and the condition has to be resolved in that scope. - // but any pattern variables introduced by the condition may have to survive the for's scope and - // so should be "promoted" to the parent scope - this.scope.reparentLocals(true); - } - TypeBinding type = this.condition.resolveTypeExpecting(this.scope, TypeBinding.BOOLEAN); - this.scope.reparentLocals(false); - this.condition.computeConversion(this.scope, type, type); - patternVariablesInTrueScope = this.condition.bindingsWhenTrue(); - } - if (this.increments != null) - for (int i = 0, length = this.increments.length; i < length; i++) { - this.increments[i].resolveWithBindings(patternVariablesInTrueScope, this.scope); - } - - if (this.action != null) { - this.action.resolveWithBindings(patternVariablesInTrueScope, this.scope); - } - } - - @Override - public boolean containsPatternVariable() { - return this.condition != null && this.condition.containsPatternVariable(); - } - - @Override - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - if (this.initializations != null) { - int initializationsLength = this.initializations.length; - for (int i = 0; i < initializationsLength; i++) - this.initializations[i].traverse(visitor, this.scope); - } - - if (this.condition != null) - this.condition.traverse(visitor, this.scope); - - if (this.increments != null) { - int incrementsLength = this.increments.length; - for (int i = 0; i < incrementsLength; i++) - this.increments[i].traverse(visitor, this.scope); - } - - if (this.action != null) - this.action.traverse(visitor, this.scope); - } - visitor.endVisit(this, blockScope); - } - - @Override - public boolean doesNotCompleteNormally() { - Constant cst = this.condition == null ? null : this.condition.constant; - boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true; - cst = this.condition == null ? null : this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true; - - return (isConditionTrue || isConditionOptimizedTrue) && (this.action == null || !this.action.breaksOut(null)); - } - - @Override - public boolean completesByContinue() { - return this.action.continuesAtOuterLabel(); - } - @Override - public boolean canCompleteNormally() { - Constant cst = this.condition == null ? null : this.condition.constant; - boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true; - cst = this.condition == null ? null : this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true; - - if (!(isConditionTrue || isConditionOptimizedTrue)) - return true; - if (this.action != null && this.action.breaksOut(null)) - return true; - return false; - } - - @Override - public boolean continueCompletes() { - return this.action.continuesAtOuterLabel(); - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java deleted file mode 100644 index 960d904..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java +++ /dev/null @@ -1,714 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 349326 - [1.7] new warning for missing try-with-resources - * bug 370930 - NonNull annotation not considered for enhanced for loops - * bug 365859 - [compiler][null] distinguish warnings based on flow analysis vs. null annotations - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 393719 - [compiler] inconsistent warnings on iteration variables - * Bug 411964 - [1.8][null] leverage null type annotation in foreach statement - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 453483 - [compiler][null][loop] Improve null analysis for loops - * Bug 415790 - [compiler][resource]Incorrect potential resource leak warning in for loop with close in try/catch - * Jesper S Moller - Contribution for - * bug 401853 - Eclipse Java compiler creates invalid bytecode (java.lang.VerifyError) - * bug 527554 - [18.3] Compiler support for JEP 286 Local-Variable Type - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -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.flow.LoopingFlowContext; -import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; -import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -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; - -public class ForeachStatement extends Statement { - - public LocalDeclaration elementVariable; - public int elementVariableImplicitWidening = -1; - public Expression collection; - public Statement action; - - // set the kind of foreach - private int kind; - // possible kinds of iterating behavior - private static final int ARRAY = 0; - private static final int RAW_ITERABLE = 1; - private static final int GENERIC_ITERABLE = 2; - - private TypeBinding iteratorReceiverType; - private TypeBinding collectionElementType; - - // loop labels - private BranchLabel breakLabel; - private BranchLabel continueLabel; - - public BlockScope scope; - - // secret variables for codegen - public LocalVariableBinding indexVariable; - public LocalVariableBinding collectionVariable; // to store the collection expression value - public LocalVariableBinding maxVariable; - // secret variable names - private static final char[] SecretIteratorVariableName = " iterator".toCharArray(); //$NON-NLS-1$ - private static final char[] SecretIndexVariableName = " index".toCharArray(); //$NON-NLS-1$ - private static final char[] SecretCollectionVariableName = " collection".toCharArray(); //$NON-NLS-1$ - private static final char[] SecretMaxVariableName = " max".toCharArray(); //$NON-NLS-1$ - - int postCollectionInitStateIndex = -1; - int mergedInitStateIndex = -1; - - public ForeachStatement( - LocalDeclaration elementVariable, - int start) { - - this.elementVariable = elementVariable; - this.sourceStart = start; - this.kind = -1; - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // initialize break and continue labels - this.breakLabel = new BranchLabel(); - this.continueLabel = new BranchLabel(); - int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; - - // process the element variable and collection - flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo); - FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy()); - this.collection.checkNPE(currentScope, flowContext, condInfo.copy(), 1); - LocalVariableBinding elementVarBinding = this.elementVariable.binding; - - // element variable will be assigned when iterating - condInfo.markAsDefinitelyAssigned(elementVarBinding); - - this.postCollectionInitStateIndex = currentScope.methodScope().recordInitializationStates(condInfo); - - - // process the action - LoopingFlowContext loopingContext = - new LoopingFlowContext(flowContext, flowInfo, this, this.breakLabel, - this.continueLabel, this.scope, true); - UnconditionalFlowInfo actionInfo = - condInfo.nullInfoLessUnconditionalCopy(); - actionInfo.markAsDefinitelyUnknown(elementVarBinding); - if (currentScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) { - int elementNullStatus = NullAnnotationMatching.nullStatusFromExpressionType(this.collectionElementType); - int nullStatus = NullAnnotationMatching.checkAssignment(currentScope, flowContext, elementVarBinding, null, // have no useful flowinfo for element var - elementNullStatus, this.collection, this.collectionElementType); - if ((this.kind == GENERIC_ITERABLE || this.kind == RAW_ITERABLE) && !currentScope.compilerOptions().usesNullTypeAnnotations()) { - // respect declaration annotation on Iterator.next(): - ReferenceBinding iterator = currentScope.getJavaUtilIterator(); - if (iterator != null) { - MethodBinding next = iterator.getExactMethod(TypeConstants.NEXT, Binding.NO_TYPES, currentScope.compilationUnitScope); - ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(next, currentScope); - if (next != null && ((next.tagBits & TagBits.AnnotationNullMASK) != 0)) { - nullStatus = FlowInfo.tagBitsToNullStatus(next.tagBits); - } - } - } - if ((elementVarBinding.type.tagBits & TagBits.IsBaseType) == 0) { - actionInfo.markNullStatus(elementVarBinding, nullStatus); - } - } - FlowInfo exitBranch; - if (!(this.action == null || (this.action.isEmptyBlock() - && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3))) { - - if (this.action.complainIfUnreachable(actionInfo, this.scope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) { - actionInfo = this.action.analyseCode(this.scope, loopingContext, actionInfo).unconditionalCopy(); - FakedTrackingVariable.markForeachElementVar(this.elementVariable); - // action.analyseCode() missed the following check due to identical scopes of ForeachStatement and action: - FlowInfo actionNullInfo = condInfo.copy().addNullInfoFrom(actionInfo); // previously action did not see nullinfo from condInfo - this.scope.checkUnclosedCloseables(actionNullInfo, loopingContext, null, null); - } - - // code generation can be optimized when no need to continue in the loop - exitBranch = flowInfo.unconditionalCopy(). - addInitializationsFrom(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) { - this.continueLabel = null; - } else { - actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue); - loopingContext.complainOnDeferredFinalChecks(this.scope, actionInfo); - exitBranch.addPotentialInitializationsFrom(actionInfo); - } - } else { - exitBranch = condInfo.initsWhenFalse(); - if (this.action instanceof Block && !this.action.isEmptyBlock()) { - this.scope.checkUnclosedCloseables(actionInfo, loopingContext, null, null); - } - } - - // we need the variable to iterate the collection even if the - // element variable is not used - final boolean hasEmptyAction = this.action == null - || this.action.isEmptyBlock() - || ((this.action.bits & IsUsefulEmptyStatement) != 0); - - switch(this.kind) { - case ARRAY : - if (!hasEmptyAction - || elementVarBinding.resolvedPosition != -1) { - this.collectionVariable.useFlag = LocalVariableBinding.USED; - if (this.continueLabel != null) { - this.indexVariable.useFlag = LocalVariableBinding.USED; - this.maxVariable.useFlag = LocalVariableBinding.USED; - } - } - break; - case RAW_ITERABLE : - case GENERIC_ITERABLE : - this.indexVariable.useFlag = LocalVariableBinding.USED; - break; - } - //end of loop - loopingContext.complainOnDeferredNullChecks(currentScope, actionInfo); - if (loopingContext.hasEscapingExceptions()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=321926 - FlowInfo loopbackFlowInfo = flowInfo.copy(); - if (this.continueLabel != null) { // we do get to the bottom - // loopback | (loopback + action): - loopbackFlowInfo = loopbackFlowInfo.mergedWith(loopbackFlowInfo.unconditionalCopy().addNullInfoFrom(actionInfo).unconditionalInits()); - } - loopingContext.simulateThrowAfterLoopBack(loopbackFlowInfo); - } - - FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( - (loopingContext.initsOnBreak.tagBits & - FlowInfo.UNREACHABLE) != 0 ? - loopingContext.initsOnBreak : - flowInfo.addInitializationsFrom(loopingContext.initsOnBreak), // recover upstream null info - false, - exitBranch, - false, - true /*for(;;){}while(true); unreachable(); */); - mergedInfo.resetAssignmentInfo(this.elementVariable.binding); - this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } - - /** - * For statement code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - final boolean hasEmptyAction = this.action == null - || this.action.isEmptyBlock() - || ((this.action.bits & IsUsefulEmptyStatement) != 0); - - if (hasEmptyAction - && this.elementVariable.binding.resolvedPosition == -1 - && this.kind == ARRAY) { - this.collection.generateCode(this.scope, codeStream, false); - codeStream.exitUserScope(this.scope); - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - - // generate the initializations - switch(this.kind) { - case ARRAY : - this.collection.generateCode(this.scope, codeStream, true); - codeStream.store(this.collectionVariable, true); - codeStream.addVariable(this.collectionVariable); - if (this.continueLabel != null) { - // int length = (collectionVariable = [collection]).length; - codeStream.arraylength(); - codeStream.store(this.maxVariable, false); - codeStream.addVariable(this.maxVariable); - codeStream.iconst_0(); - codeStream.store(this.indexVariable, false); - codeStream.addVariable(this.indexVariable); - } else { - // leave collectionVariable on execution stack (will be consumed when swapping condition further down) - } - break; - case RAW_ITERABLE : - case GENERIC_ITERABLE : - this.collection.generateCode(this.scope, codeStream, true); - // declaringClass.iterator(); - codeStream.invokeIterableIterator(this.iteratorReceiverType); - codeStream.store(this.indexVariable, false); - codeStream.addVariable(this.indexVariable); - break; - } - // label management - BranchLabel actionLabel = new BranchLabel(codeStream); - actionLabel.tagBits |= BranchLabel.USED; - BranchLabel conditionLabel = new BranchLabel(codeStream); - conditionLabel.tagBits |= BranchLabel.USED; - this.breakLabel.initialize(codeStream); - if (this.continueLabel == null) { - // generate the condition (swapped for optimizing) - conditionLabel.place(); - int conditionPC = codeStream.position; - switch(this.kind) { - case ARRAY : - // inline the arraylength call - // collectionVariable is already on execution stack - codeStream.arraylength(); - codeStream.ifeq(this.breakLabel); - break; - case RAW_ITERABLE : - case GENERIC_ITERABLE : - codeStream.load(this.indexVariable); - codeStream.invokeJavaUtilIteratorHasNext(); - codeStream.ifeq(this.breakLabel); - break; - } - codeStream.recordPositionsFrom(conditionPC, this.elementVariable.sourceStart); - } else { - this.continueLabel.initialize(codeStream); - this.continueLabel.tagBits |= BranchLabel.USED; - // jump over the actionBlock - codeStream.goto_(conditionLabel); - } - - // generate the loop action - actionLabel.place(); - - // generate the loop action - switch(this.kind) { - case ARRAY : - if (this.elementVariable.binding.resolvedPosition != -1) { - codeStream.load(this.collectionVariable); - if (this.continueLabel == null) { - codeStream.iconst_0(); // no continue, thus simply hardcode offset 0 - } else { - codeStream.load(this.indexVariable); - } - codeStream.arrayAt(this.collectionElementType.id); - if (this.elementVariableImplicitWidening != -1) { - codeStream.generateImplicitConversion(this.elementVariableImplicitWidening); - } - codeStream.store(this.elementVariable.binding, false); - codeStream.addVisibleLocalVariable(this.elementVariable.binding); - if (this.postCollectionInitStateIndex != -1) { - codeStream.addDefinitelyAssignedVariables( - currentScope, - this.postCollectionInitStateIndex); - } - } - break; - case RAW_ITERABLE : - case GENERIC_ITERABLE : - codeStream.load(this.indexVariable); - codeStream.invokeJavaUtilIteratorNext(); - if (this.elementVariable.binding.type.id != T_JavaLangObject) { - if (this.elementVariableImplicitWidening != -1) { - codeStream.checkcast(this.collectionElementType); - codeStream.generateImplicitConversion(this.elementVariableImplicitWidening); - } else { - codeStream.checkcast(this.elementVariable.binding.type); - } - } - if (this.elementVariable.binding.resolvedPosition == -1) { - switch (this.elementVariable.binding.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.pop2(); - break; - default: - codeStream.pop(); - break; - } - } else { - codeStream.store(this.elementVariable.binding, false); - codeStream.addVisibleLocalVariable(this.elementVariable.binding); - if (this.postCollectionInitStateIndex != -1) { - codeStream.addDefinitelyAssignedVariables( - currentScope, - this.postCollectionInitStateIndex); - } - } - break; - } - - if (!hasEmptyAction) { - this.action.generateCode(this.scope, codeStream); - } - codeStream.removeVariable(this.elementVariable.binding); - if (this.postCollectionInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postCollectionInitStateIndex); - } - // continuation point - if (this.continueLabel != null) { - this.continueLabel.place(); - int continuationPC = codeStream.position; - // generate the increments for next iteration - switch(this.kind) { - case ARRAY : - if (!hasEmptyAction || this.elementVariable.binding.resolvedPosition >= 0) { - codeStream.iinc(this.indexVariable.resolvedPosition, 1); - } - // generate the condition - conditionLabel.place(); - codeStream.load(this.indexVariable); - codeStream.load(this.maxVariable); - codeStream.if_icmplt(actionLabel); - break; - case RAW_ITERABLE : - case GENERIC_ITERABLE : - // generate the condition - conditionLabel.place(); - codeStream.load(this.indexVariable); - codeStream.invokeJavaUtilIteratorHasNext(); - codeStream.ifne(actionLabel); - break; - } - codeStream.recordPositionsFrom(continuationPC, this.elementVariable.sourceStart); - } - switch(this.kind) { - case ARRAY : - codeStream.removeVariable(this.indexVariable); - codeStream.removeVariable(this.maxVariable); - codeStream.removeVariable(this.collectionVariable); - break; - case RAW_ITERABLE : - case GENERIC_ITERABLE : - // generate the condition - codeStream.removeVariable(this.indexVariable); - break; - } - codeStream.exitUserScope(this.scope); - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - this.breakLabel.place(); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public StringBuilder printStatement(int indent, StringBuilder output) { - - printIndent(indent, output).append("for ("); //$NON-NLS-1$ - this.elementVariable.printAsExpression(0, output); - output.append(" : ");//$NON-NLS-1$ - if (this.collection != null) { - this.collection.print(0, output).append(") "); //$NON-NLS-1$ - } else { - output.append(')'); - } - //block - if (this.action == null) { - output.append(';'); - } else { - output.append('\n'); - this.action.printStatement(indent + 1, output); - } - return output; - } - - public static TypeBinding getCollectionElementType(BlockScope scope, TypeBinding collectionType) { - if (collectionType == null) return null; - - boolean isTargetJsr14 = scope.compilerOptions().targetJDK == ClassFileConstants.JDK1_4; - if (collectionType.isCapture()) { - TypeBinding upperBound = ((CaptureBinding)collectionType).firstBound; - if (upperBound != null && upperBound.isArrayType()) - collectionType = upperBound; // partially anticipating the fix for https://bugs.openjdk.java.net/browse/JDK-8013843 - } - if (collectionType.isArrayType()) { // for(E e : E[]) - return ((ArrayBinding) collectionType).elementsType(); - } else if (collectionType instanceof ReferenceBinding) { - ReferenceBinding iterableType = ((ReferenceBinding)collectionType).findSuperTypeOriginatingFrom(T_JavaLangIterable, false /*Iterable is not a class*/); - if (iterableType == null && isTargetJsr14) { - iterableType = ((ReferenceBinding)collectionType).findSuperTypeOriginatingFrom(T_JavaUtilCollection, false /*Iterable is not a class*/); - } - if (iterableType == null) return null; - - TypeBinding[] arguments = null; - switch (iterableType.kind()) { - case Binding.RAW_TYPE : // for(Object o : Iterable) - return scope.getJavaLangObject(); - - case Binding.GENERIC_TYPE : // for (T t : Iterable) - in case used inside Iterable itself - arguments = iterableType.typeVariables(); - break; - - case Binding.PARAMETERIZED_TYPE : // for(E e : Iterable) - arguments = ((ParameterizedTypeBinding)iterableType).arguments; - break; - - default: - return null; - } - // generic or parameterized case - if (arguments.length != 1) return null; // per construction can only be one - return arguments[0]; - } - return null; - } - @Override - public void resolve(BlockScope upperScope) { - // use the scope that will hold the init declarations - this.scope = new BlockScope(upperScope); - this.scope.blockStatement = this; - this.elementVariable.resolve(this.scope); // collection expression can see itemVariable - - TypeBinding elementType = this.elementVariable.type.resolvedType; - TypeBinding collectionType = this.collection == null ? null : this.collection.resolveType(upperScope); - - // Patch the resolved type - if (this.elementVariable.isTypeNameVar(upperScope)) { - if (this.elementVariable.type.dimensions() > 0 || this.elementVariable.type.extraDimensions() > 0) { - upperScope.problemReporter().varLocalCannotBeArray(this.elementVariable); - } - if (TypeBinding.equalsEquals(TypeBinding.NULL, collectionType)) { - upperScope.problemReporter().varLocalInitializedToNull(this.elementVariable); - elementType = collectionType; - } else if (TypeBinding.equalsEquals(TypeBinding.VOID, collectionType)) { - upperScope.problemReporter().varLocalInitializedToVoid(this.elementVariable); - elementType = collectionType; - } - if ((elementType = getCollectionElementType(this.scope, collectionType)) == null) { - elementType = collectionType; - } else { - elementType = this.elementVariable.patchType(elementType); - } - if (elementType instanceof ReferenceBinding) { - ReferenceBinding refBinding = (ReferenceBinding) elementType; - if (!elementType.canBeSeenBy(upperScope)) { - upperScope.problemReporter().invalidType(this.elementVariable, - new ProblemReferenceBinding( - CharOperation.splitOn('.', refBinding.shortReadableName()), - refBinding, - ProblemReasons.NotVisible)); - } - } - // additional check deferred from LocalDeclaration.resolve(): - if (this.elementVariable.binding != null && this.elementVariable.binding.isValidBinding()) { - this.elementVariable.validateNullAnnotations(this.scope); - } - } - - TypeBinding expectedCollectionType = null; - if (elementType != null && collectionType != null) { - boolean isTargetJsr14 = this.scope.compilerOptions().targetJDK == ClassFileConstants.JDK1_4; - if (collectionType.isCapture()) { - TypeBinding upperBound = ((CaptureBinding)collectionType).firstBound; - if (upperBound != null && upperBound.isArrayType()) - collectionType = upperBound; // partially anticipating the fix for https://bugs.openjdk.java.net/browse/JDK-8013843 - } - if (collectionType.isArrayType()) { // for(E e : E[]) - this.kind = ARRAY; - this.collectionElementType = ((ArrayBinding) collectionType).elementsType(); - if (!this.collectionElementType.isCompatibleWith(elementType) - && !this.scope.isBoxingCompatibleWith(this.collectionElementType, elementType)) { - this.scope.problemReporter().notCompatibleTypesErrorInForeach(this.collection, this.collectionElementType, elementType); - } else if (this.collectionElementType.needsUncheckedConversion(elementType)) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=321085 - this.scope.problemReporter().unsafeElementTypeConversion(this.collection, this.collectionElementType, elementType); - } - // in case we need to do a conversion - int compileTimeTypeID = this.collectionElementType.id; - if (elementType.isBaseType()) { - this.collection.computeConversion(this.scope, collectionType, collectionType); - if (!this.collectionElementType.isBaseType()) { - compileTimeTypeID = this.scope.environment().computeBoxingType(this.collectionElementType).id; - this.elementVariableImplicitWidening = UNBOXING; - if (elementType.isBaseType()) { - this.elementVariableImplicitWidening |= (elementType.id << 4) + compileTimeTypeID; - this.scope.problemReporter().autoboxing(this.collection, this.collectionElementType, elementType); - } - } else { - this.elementVariableImplicitWidening = (elementType.id << 4) + compileTimeTypeID; - } - } else if (this.collectionElementType.isBaseType()) { - this.collection.computeConversion(this.scope, collectionType, collectionType); - int boxedID = this.scope.environment().computeBoxingType(this.collectionElementType).id; - this.elementVariableImplicitWidening = BOXING | (compileTimeTypeID << 4) | compileTimeTypeID; // use primitive type in implicit conversion - compileTimeTypeID = boxedID; - this.scope.problemReporter().autoboxing(this.collection, this.collectionElementType, elementType); - } else { - expectedCollectionType = upperScope.createArrayType(elementType, 1); - this.collection.computeConversion(this.scope, expectedCollectionType, collectionType); - } - } else if (collectionType instanceof ReferenceBinding) { - ReferenceBinding iterableType = ((ReferenceBinding)collectionType).findSuperTypeOriginatingFrom(T_JavaLangIterable, false /*Iterable is not a class*/); - if (iterableType == null && isTargetJsr14) { - iterableType = ((ReferenceBinding)collectionType).findSuperTypeOriginatingFrom(T_JavaUtilCollection, false /*Iterable is not a class*/); - } - checkIterable: { - if (iterableType == null) break checkIterable; - - this.iteratorReceiverType = collectionType.erasure(); - if (isTargetJsr14) { - if (((ReferenceBinding)this.iteratorReceiverType).findSuperTypeOriginatingFrom(T_JavaUtilCollection, false) == null) { - this.iteratorReceiverType = iterableType; // handle indirect inheritance thru variable secondary bound - this.collection.computeConversion(this.scope, iterableType, collectionType); - } else { - this.collection.computeConversion(this.scope, collectionType, collectionType); - } - } else if (((ReferenceBinding)this.iteratorReceiverType).findSuperTypeOriginatingFrom(T_JavaLangIterable, false) == null) { - this.iteratorReceiverType = iterableType; // handle indirect inheritance thru variable secondary bound - this.collection.computeConversion(this.scope, iterableType, collectionType); - } else { - this.collection.computeConversion(this.scope, collectionType, collectionType); - } - - TypeBinding[] arguments = null; - switch (iterableType.kind()) { - case Binding.RAW_TYPE : // for(Object o : Iterable) - this.kind = RAW_ITERABLE; - this.collectionElementType = this.scope.getJavaLangObject(); - if (!this.collectionElementType.isCompatibleWith(elementType) - && !this.scope.isBoxingCompatibleWith(this.collectionElementType, elementType)) { - this.scope.problemReporter().notCompatibleTypesErrorInForeach(this.collection, this.collectionElementType, elementType); - } - // no conversion needed as only for reference types - break checkIterable; - - case Binding.GENERIC_TYPE : // for (T t : Iterable) - in case used inside Iterable itself - arguments = iterableType.typeVariables(); - break; - - case Binding.PARAMETERIZED_TYPE : // for(E e : Iterable) - arguments = ((ParameterizedTypeBinding)iterableType).arguments; - break; - - default: - break checkIterable; - } - // generic or parameterized case - if (arguments.length != 1) break checkIterable; // per construction can only be one - this.kind = GENERIC_ITERABLE; - - this.collectionElementType = arguments[0]; - if (!this.collectionElementType.isCompatibleWith(elementType) - && !this.scope.isBoxingCompatibleWith(this.collectionElementType, elementType)) { - this.scope.problemReporter().notCompatibleTypesErrorInForeach(this.collection, this.collectionElementType, elementType); - } else if (this.collectionElementType.needsUncheckedConversion(elementType)) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=393719 - this.scope.problemReporter().unsafeElementTypeConversion(this.collection, this.collectionElementType, elementType); - } - int compileTimeTypeID = this.collectionElementType.id; - // no conversion needed as only for reference types - if (elementType.isBaseType()) { - if (!this.collectionElementType.isBaseType()) { - compileTimeTypeID = this.scope.environment().computeBoxingType(this.collectionElementType).id; - this.elementVariableImplicitWidening = UNBOXING; - if (elementType.isBaseType()) { - this.elementVariableImplicitWidening |= (elementType.id << 4) + compileTimeTypeID; - } - } else { - this.elementVariableImplicitWidening = (elementType.id << 4) + compileTimeTypeID; - } - } else { - if (this.collectionElementType.isBaseType()) { - this.elementVariableImplicitWidening = BOXING | (compileTimeTypeID << 4) | compileTimeTypeID; // use primitive type in implicit conversion - } - } - } - } - switch(this.kind) { - case ARRAY : - // allocate #index secret variable (of type int) - this.indexVariable = new LocalVariableBinding(SecretIndexVariableName, TypeBinding.INT, ClassFileConstants.AccDefault, false); - this.scope.addLocalVariable(this.indexVariable); - this.indexVariable.setConstant(Constant.NotAConstant); // not inlinable - // allocate #max secret variable - this.maxVariable = new LocalVariableBinding(SecretMaxVariableName, TypeBinding.INT, ClassFileConstants.AccDefault, false); - this.scope.addLocalVariable(this.maxVariable); - this.maxVariable.setConstant(Constant.NotAConstant); // not inlinable - // add #array secret variable (of collection type) - if (expectedCollectionType == null) { - this.collectionVariable = new LocalVariableBinding(SecretCollectionVariableName, collectionType, ClassFileConstants.AccDefault, false); - } else { - this.collectionVariable = new LocalVariableBinding(SecretCollectionVariableName, expectedCollectionType, ClassFileConstants.AccDefault, false); - } - this.scope.addLocalVariable(this.collectionVariable); - this.collectionVariable.setConstant(Constant.NotAConstant); // not inlinable - break; - case RAW_ITERABLE : - case GENERIC_ITERABLE : - // allocate #index secret variable (of type Iterator) - this.indexVariable = new LocalVariableBinding(SecretIteratorVariableName, this.scope.getJavaUtilIterator(), ClassFileConstants.AccDefault, false); - this.scope.addLocalVariable(this.indexVariable); - this.indexVariable.setConstant(Constant.NotAConstant); // not inlinable - break; - default : - if (isTargetJsr14) { - this.scope.problemReporter().invalidTypeForCollectionTarget14(this.collection); - } else { - this.scope.problemReporter().invalidTypeForCollection(this.collection); - } - } - } - if (this.action != null) { - this.action.resolve(this.scope); - } - } - - @Override - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.elementVariable.traverse(visitor, this.scope); - if (this.collection != null) { - this.collection.traverse(visitor, this.scope); - } - if (this.action != null) { - this.action.traverse(visitor, this.scope); - } - } - visitor.endVisit(this, blockScope); - } - - @Override - public boolean doesNotCompleteNormally() { - return false; // may not be entered at all. - } - - @Override - public boolean canCompleteNormally() { - return true; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java deleted file mode 100644 index e61eb26..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java +++ /dev/null @@ -1,395 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Jesper S Moller - Contributions for - * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression - * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 - * Stephan Herrmann - Contribution for - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 423504 - [1.8] Implement "18.5.3 Functional Interface Parameterization Inference" - * Bug 425142 - [1.8][compiler] NPE in ConstraintTypeFormula.reduceSubType - * Bug 425153 - [1.8] Having wildcard allows incompatible types in a lambda expression - * Bug 425156 - [1.8] Lambda as an argument is flagged with incompatible error - * Bug 424403 - [1.8][compiler] Generic method call with method reference argument fails to resolve properly. - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 428352 - [1.8][compiler] Resolution errors don't always surface - * Bug 446442 - [1.8] merge null annotations from super methods - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.VANILLA_CONTEXT; - -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; -import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; -import org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; -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.TypeBindingVisitor; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -public abstract class FunctionalExpression extends Expression { - - protected TypeBinding expectedType; - public MethodBinding descriptor; - public MethodBinding binding; // Code generation binding. May include synthetics. See getMethodBinding() - protected MethodBinding actualMethodBinding; // void of synthetics. - boolean ignoreFurtherInvestigation; - protected ExpressionContext expressionContext = VANILLA_CONTEXT; - public CompilationResult compilationResult; - public BlockScope enclosingScope; - public int bootstrapMethodNumber = -1; - public boolean shouldCaptureInstance = false; // Whether the expression needs access to instance data of enclosing type - protected static IErrorHandlingPolicy silentErrorHandlingPolicy = DefaultErrorHandlingPolicies.ignoreAllProblems(); - private boolean hasReportedSamProblem = false; - public boolean hasDescripterProblem; - public boolean isSerializable; - public int ordinal; - public char[] text; // source representation of the FE - used in virgin copy construction - - public FunctionalExpression(CompilationResult compilationResult) { - this.compilationResult = compilationResult; - } - - public FunctionalExpression() { - super(); - } - - @Override - public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope scope) { - return false; - } - - public void setCompilationResult(CompilationResult compilationResult) { - this.compilationResult = compilationResult; - } - - // Return the actual (non-code generation) method binding that is void of synthetics. - public MethodBinding getMethodBinding() { - return null; - } - - @Override - public void setExpectedType(TypeBinding expectedType) { - this.expectedType = expectedType; - } - - @Override - public void setExpressionContext(ExpressionContext context) { - this.expressionContext = context; - } - - @Override - public ExpressionContext getExpressionContext() { - return this.expressionContext; - } - - @Override - public boolean isPolyExpression(MethodBinding candidate) { - return true; - } - @Override - public boolean isPolyExpression() { - return true; // always as per introduction of part D, JSR 335 - } - - @Override - public boolean isFunctionalType() { - return true; - } - - @Override - public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) { - if (targetType instanceof TypeVariableBinding) { - TypeVariableBinding typeVariable = (TypeVariableBinding) targetType; - if (method != null) { // when called from type inference - if (typeVariable.declaringElement == method) - return false; - if (method.isConstructor() && typeVariable.declaringElement == method.declaringClass) - return false; - } else { // for internal calls - if (typeVariable.declaringElement instanceof MethodBinding) - return false; - } - } - return true; - } - - @Override - public TypeBinding invocationTargetType() { - if (this.expectedType == null) return null; - // when during inference this expression mimics as an invocationSite, - // we simulate an *invocation* of this functional expression, - // where the expected type of the expression is the return type of the sam: - MethodBinding sam = this.expectedType.getSingleAbstractMethod(this.enclosingScope, true); - if (sam != null && sam.problemId() != ProblemReasons.NoSuchSingleAbstractMethod) { - if (sam.isConstructor()) - return sam.declaringClass; - else - return sam.returnType; - } - return null; - } - - @Override - public TypeBinding expectedType() { - return this.expectedType; - } - - public boolean argumentsTypeElided() { return true; /* only exception: lambda with explicit argument types. */ } - - // Notify the compilation unit that it contains some functional types, taking care not to add any transient copies. this is assumed not to be a copy - public int recordFunctionalType(Scope scope) { - while (scope != null) { - switch (scope.kind) { - case Scope.METHOD_SCOPE : - ReferenceContext context = ((MethodScope) scope).referenceContext; - if (context instanceof LambdaExpression) { - LambdaExpression expression = (LambdaExpression) context; - if (expression != expression.original) // fake universe. - return 0; - } - break; - case Scope.COMPILATION_UNIT_SCOPE : - CompilationUnitDeclaration unit = ((CompilationUnitScope) scope).referenceContext; - return unit.record(this); - } - scope = scope.parent; - } - return 0; // not reached. - } - - @Override - public TypeBinding resolveType(BlockScope blockScope) { - return resolveType(blockScope, false); - } - - public TypeBinding resolveType(BlockScope blockScope, boolean skipKosherCheck) { - this.constant = Constant.NotAConstant; - this.enclosingScope = blockScope; - MethodBinding sam = this.expectedType == null ? null : this.expectedType.getSingleAbstractMethod(blockScope, argumentsTypeElided()); - if (sam == null) { - blockScope.problemReporter().targetTypeIsNotAFunctionalInterface(this); - return null; - } - if (!sam.isValidBinding() && sam.problemId() != ProblemReasons.ContradictoryNullAnnotations) { - return reportSamProblem(blockScope, sam); - } - - this.descriptor = sam; - if (skipKosherCheck || kosherDescriptor(blockScope, sam, true)) { - if (this.expectedType instanceof IntersectionTypeBinding18) { - ReferenceBinding[] intersectingTypes = ((IntersectionTypeBinding18)this.expectedType).intersectingTypes; - for (int t = 0, max = intersectingTypes.length; t < max; t++) { - if (intersectingTypes[t].findSuperTypeOriginatingFrom(TypeIds.T_JavaIoSerializable, false /*Serializable is not a class*/) != null) { - this.isSerializable = true; - break; - } - } - } else if (this.expectedType.findSuperTypeOriginatingFrom(TypeIds.T_JavaIoSerializable, false /*Serializable is not a class*/) != null) { - this.isSerializable = true; - } - LookupEnvironment environment = blockScope.environment(); - if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { - NullAnnotationMatching.checkForContradictions(sam, this, blockScope); - } - return this.resolvedType = this.expectedType; - } - - return this.resolvedType = null; - } - - protected TypeBinding reportSamProblem(BlockScope blockScope, MethodBinding sam) { - if (this.hasReportedSamProblem) - return null; - switch (sam.problemId()) { - case ProblemReasons.NoSuchSingleAbstractMethod: - blockScope.problemReporter().targetTypeIsNotAFunctionalInterface(this); - this.hasReportedSamProblem = true; - break; - case ProblemReasons.NotAWellFormedParameterizedType: - blockScope.problemReporter().illFormedParameterizationOfFunctionalInterface(this); - this.hasReportedSamProblem = true; - break; - } - return null; - } - - static class VisibilityInspector extends TypeBindingVisitor { - - private final Scope scope; - private final boolean shouldChatter; - private boolean visible = true; - private final FunctionalExpression expression; - - public VisibilityInspector(FunctionalExpression expression, Scope scope, boolean shouldChatter) { - this.scope = scope; - this.shouldChatter = shouldChatter; - this.expression = expression; - } - - private void checkVisibility(ReferenceBinding referenceBinding) { - if (!referenceBinding.canBeSeenBy(this.scope)) { - this.visible = false; - if (this.shouldChatter) - this.scope.problemReporter().descriptorHasInvisibleType(this.expression, referenceBinding); - } - } - - @Override - public boolean visit(ReferenceBinding referenceBinding) { - checkVisibility(referenceBinding); - return true; - } - - - @Override - public boolean visit(ParameterizedTypeBinding parameterizedTypeBinding) { - checkVisibility(parameterizedTypeBinding); - return true; - } - - @Override - public boolean visit(RawTypeBinding rawTypeBinding) { - checkVisibility(rawTypeBinding); - return true; - } - - public boolean visible(TypeBinding type) { - TypeBindingVisitor.visit(this, type); - return this.visible; - } - - public boolean visible(TypeBinding[] types) { - TypeBindingVisitor.visit(this, types); - return this.visible; - } - - } - - public boolean kosherDescriptor(Scope scope, MethodBinding sam, boolean shouldChatter) { - - VisibilityInspector inspector = new VisibilityInspector(this, scope, shouldChatter); - - boolean status = true; - if (!inspector.visible(sam.returnType)) - status = false; - if (!inspector.visible(sam.parameters)) - status = false; - if (!inspector.visible(sam.thrownExceptions)) - status = false; - if (!inspector.visible(this.expectedType)) - status = false; - this.hasDescripterProblem |= !status; - return status; - } - - public int nullStatus(FlowInfo flowInfo) { - return FlowInfo.NON_NULL; - } - - public int diagnosticsSourceEnd() { - return this.sourceEnd; - } - - public MethodBinding[] getRequiredBridges() { - - class BridgeCollector { - - MethodBinding [] bridges; - MethodBinding method; - char [] selector; - LookupEnvironment environment; - Scope scope; - - BridgeCollector(ReferenceBinding functionalType, MethodBinding method) { - this.method = method; - this.selector = method.selector; - this.environment = FunctionalExpression.this.enclosingScope.environment(); - this.scope = FunctionalExpression.this.enclosingScope; - collectBridges(new ReferenceBinding[]{functionalType}); - } - - void collectBridges(ReferenceBinding[] interfaces) { - int length = interfaces == null ? 0 : interfaces.length; - for (int i = 0; i < length; i++) { - ReferenceBinding superInterface = interfaces[i]; - if (superInterface == null) - continue; - MethodBinding [] methods = superInterface.getMethods(this.selector); - for (int j = 0, count = methods == null ? 0 : methods.length; j < count; j++) { - MethodBinding inheritedMethod = methods[j]; - if (inheritedMethod == null || this.method == inheritedMethod) // descriptor declaring class may not be same functional interface target type. - continue; - if (inheritedMethod.isStatic() || inheritedMethod.redeclaresPublicObjectMethod(this.scope)) - continue; - inheritedMethod = MethodVerifier.computeSubstituteMethod(inheritedMethod, this.method, this.environment); - if (inheritedMethod == null || !MethodVerifier.isSubstituteParameterSubsignature(this.method, inheritedMethod, this.environment) || - !MethodVerifier.areReturnTypesCompatible(this.method, inheritedMethod, this.environment)) - continue; - final MethodBinding originalInherited = inheritedMethod.original(); - final MethodBinding originalOverride = this.method.original(); - if (!originalOverride.areParameterErasuresEqual(originalInherited) || TypeBinding.notEquals(originalOverride.returnType.erasure(), originalInherited.returnType.erasure())) - add(originalInherited); - } - collectBridges(superInterface.superInterfaces()); - } - } - void add(MethodBinding inheritedMethod) { - if (this.bridges == null) { - this.bridges = new MethodBinding[] { inheritedMethod }; - return; - } - int length = this.bridges.length; - for (int i = 0; i < length; i++) { - if (this.bridges[i].areParameterErasuresEqual(inheritedMethod) && TypeBinding.equalsEquals(this.bridges[i].returnType.erasure(), inheritedMethod.returnType.erasure())) - return; - } - System.arraycopy(this.bridges, 0, this.bridges = new MethodBinding[length + 1], 0, length); - this.bridges[length] = inheritedMethod; - } - MethodBinding [] getBridges () { - return this.bridges; - } - } - - ReferenceBinding functionalType; - if (this.expectedType instanceof IntersectionTypeBinding18) { - functionalType = (ReferenceBinding) ((IntersectionTypeBinding18)this.expectedType).getSAMType(this.enclosingScope); - } else { - functionalType = (ReferenceBinding) this.expectedType; - } - return new BridgeCollector(functionalType, this.descriptor).getBridges(); - } - boolean requiresBridges() { - return getRequiredBridges() != null; - } - public void cleanUp() { - // to be overridden by sub-classes - } -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java deleted file mode 100644 index 93199b0..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/GuardedPattern.java +++ /dev/null @@ -1,184 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2022, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -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.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -public class GuardedPattern extends Pattern { - - public Pattern primaryPattern; - public Expression condition; - int thenInitStateIndex1 = -1; - int thenInitStateIndex2 = -1; - public int restrictedIdentifierStart = -1; // used only for 'when' restricted keyword. - - public GuardedPattern(Pattern primaryPattern, Expression conditionalAndExpression) { - this.primaryPattern = primaryPattern; - this.condition = conditionalAndExpression; - this.sourceStart = primaryPattern.sourceStart; - this.sourceEnd = conditionalAndExpression.sourceEnd; - } - - @Override - public LocalDeclaration getPatternVariable() { - return this.primaryPattern.getPatternVariable(); - } - - @Override - public LocalVariableBinding[] bindingsWhenTrue() { - return LocalVariableBinding.merge(this.primaryPattern.bindingsWhenTrue(), - this.condition.bindingsWhenTrue()); - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - flowInfo = this.primaryPattern.analyseCode(currentScope, flowContext, flowInfo); - this.thenInitStateIndex1 = currentScope.methodScope().recordInitializationStates(flowInfo); - FlowInfo mergedFlow = this.condition.analyseCode(currentScope, flowContext, flowInfo); - mergedFlow = mergedFlow.safeInitsWhenTrue(); - this.thenInitStateIndex2 = currentScope.methodScope().recordInitializationStates(mergedFlow); - return mergedFlow; - } - - @Override - public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel) { - this.thenTarget = new BranchLabel(codeStream); - this.elseTarget = new BranchLabel(codeStream); - this.primaryPattern.generateOptimizedBoolean(currentScope, codeStream, this.thenTarget, this.elseTarget); - Constant cst = this.condition.optimizedBooleanConstant(); - - setGuardedElseTarget(currentScope, this.elseTarget); - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - this.thenTarget, - null, - cst == Constant.NotAConstant); - if (this.thenInitStateIndex2 != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex2); - codeStream.addDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex2); - } - } - - private void setGuardedElseTarget(BlockScope currentScope, BranchLabel guardedElseTarget) { - class PatternsCollector extends ASTVisitor { - BranchLabel guardedElseTarget1; - - public PatternsCollector(BranchLabel guardedElseTarget1) { - this.guardedElseTarget1 = guardedElseTarget1; - } - @Override - public boolean visit(RecordPattern recordPattern, BlockScope scope1) { - recordPattern.guardedElseTarget = this.guardedElseTarget1; - return true; - } - } - PatternsCollector patCollector = new PatternsCollector(guardedElseTarget); - this.condition.traverse(patCollector, currentScope); - } - @Override - public boolean isAlwaysTrue() { - Constant cst = this.condition.optimizedBooleanConstant(); - return cst != Constant.NotAConstant && cst.booleanValue() == true; - } - @Override - public boolean coversType(TypeBinding type) { - return this.primaryPattern.coversType(type) && isAlwaysTrue(); - } - - @Override - public boolean dominates(Pattern p) { - if (isAlwaysTrue()) - return this.primaryPattern.dominates(p); - return false; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - if (this.resolvedType != null || this.primaryPattern == null) - return this.resolvedType; - this.resolvedType = this.primaryPattern.resolveType(scope); - // The following call (as opposed to resolveType() ensures that - // the implicitConversion code is set properly and thus the correct - // unboxing calls are generated. - this.condition.resolveTypeExpectingWithBindings(this.primaryPattern.bindingsWhenTrue(), scope, TypeBinding.BOOLEAN); - Constant cst = this.condition.optimizedBooleanConstant(); - if (cst.typeID() == TypeIds.T_boolean && cst.booleanValue() == false) { - scope.problemReporter().falseLiteralInGuard(this.condition); - } - this.condition.traverse(new ASTVisitor() { - @Override - public boolean visit( - SingleNameReference ref, - BlockScope skope) { - LocalVariableBinding local = ref.localVariableBinding(); - if (local != null) { - ref.bits |= ASTNode.IsUsedInPatternGuard; - } - return false; - } - @Override - public boolean visit( - QualifiedNameReference ref, - BlockScope skope) { - if ((ref.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) { - ref.bits |= ASTNode.IsUsedInPatternGuard; - } - return false; - } - }, scope); - return this.resolvedType = this.primaryPattern.resolvedType; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - this.primaryPattern.print(indent, output).append(" when "); //$NON-NLS-1$ - return this.condition.print(indent, output); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.primaryPattern != null) - this.primaryPattern.traverse(visitor, scope); - if (this.condition != null) - this.condition.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } - @Override - public void suspendVariables(CodeStream codeStream, BlockScope scope) { - codeStream.removeNotDefinitelyAssignedVariables(scope, this.thenInitStateIndex1); - this.primaryPattern.suspendVariables(codeStream, scope); - } - @Override - public void resumeVariables(CodeStream codeStream, BlockScope scope) { - codeStream.addDefinitelyAssignedVariables(scope, this.thenInitStateIndex2); - this.primaryPattern.resumeVariables(codeStream, scope); - } - @Override - protected boolean isPatternTypeCompatible(TypeBinding other, BlockScope scope) { - return this.primaryPattern.isPatternTypeCompatible(other, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IJavadocTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IJavadocTypeReference.java deleted file mode 100644 index 5c22566..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IJavadocTypeReference.java +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019 Red Hat Inc. and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat Inc. - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -/** - * Interface to allow Javadoc parser to collect both JavaSingleTypeReference and JavaQualifiedTypeReferences - * - * @author jjohnstn - */ -public interface IJavadocTypeReference { - - public int getTagSourceStart(); - public int getTagSourceEnd(); - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IPolyExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IPolyExpression.java deleted file mode 100644 index 8bd42cc..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IPolyExpression.java +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -/** - Contract to be implemented by all poly expressions and potential poly expressions for uniform integration into overload resolution and type inference. - Additional contracts may be imposed by {@link Invocation} and {@link InvocationSite}. For most contracts "default" implementations are furnished by - {@link Expression} or {@link Statement} or by {@link ASTNode} and the poly expression should suitably override where required. - - @see PolyTypeBinding - @see ExpressionContext -*/ -public interface IPolyExpression { - - // Expression context manipulation - public void setExpressionContext(ExpressionContext context); - public ExpressionContext getExpressionContext(); - - // Target type injection. - public void setExpectedType(TypeBinding targetType); - public TypeBinding invocationTargetType(); - - // Compatibility checks. - public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope); - public boolean isCompatibleWith(TypeBinding targetType, final Scope scope); - public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope scope); - public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope skope); - - // Pertinence checks. - public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method); - - // Polyness checks - public boolean isPolyExpression(MethodBinding candidate); - public boolean isPolyExpression(); - public boolean isFunctionalType(); - public Expression[] getPolyExpressions(); - - - /* Resolution: A poly expression must be prepared to be resolved multiple times and should manage matters in a side effect free fashion. - Typically, in invocation contexts, there is an initial resolution, multiple tentative resolutions and then a final resolution against - the ultimate target type. - */ - public TypeBinding resolveType(BlockScope blockScope); - // Resolve expression tentatively - should have no lingering side-effects that may impact final resolution ! - public Expression resolveExpressionExpecting(TypeBinding targetType, Scope scope, InferenceContext18 inferenceContext); - -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IfStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IfStatement.java deleted file mode 100644 index 3293087..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IfStatement.java +++ /dev/null @@ -1,362 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * 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 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class IfStatement extends Statement { - - //this class represents the case of only one statement in - //either else and/or then branches. - - public Expression condition; - public Statement thenStatement; - public Statement elseStatement; - - // for local variables table attributes - int thenInitStateIndex = -1; - int elseInitStateIndex = -1; - int mergedInitStateIndex = -1; - -public IfStatement(Expression condition, Statement thenStatement, int sourceStart, int sourceEnd) { - this.condition = condition; - this.thenStatement = thenStatement; - // remember useful empty statement - if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatement; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; -} - -public IfStatement(Expression condition, Statement thenStatement, Statement elseStatement, int sourceStart, int sourceEnd) { - this.condition = condition; - this.thenStatement = thenStatement; - // remember useful empty statement - if (thenStatement instanceof EmptyStatement) thenStatement.bits |= IsUsefulEmptyStatement; - this.elseStatement = elseStatement; - if (elseStatement instanceof IfStatement) elseStatement.bits |= IsElseIfStatement; - if (elseStatement instanceof EmptyStatement) elseStatement.bits |= IsUsefulEmptyStatement; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // process the condition - FlowInfo conditionFlowInfo = this.condition.analyseCode(currentScope, flowContext, flowInfo); - int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; - - FieldBinding[] nullCheckedFields = null; - if (currentScope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled && this.condition instanceof EqualExpression) { // simple checks only - nullCheckedFields = flowContext.nullCheckedFields(); // store before info expires - } - - Constant cst = this.condition.optimizedBooleanConstant(); - this.condition.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - - flowContext.conditionalLevel++; - - // process the THEN part - FlowInfo thenFlowInfo = conditionFlowInfo.safeInitsWhenTrue(); - if (isConditionOptimizedFalse) { - thenFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - FlowInfo elseFlowInfo = conditionFlowInfo.initsWhenFalse().copy(); - if (isConditionOptimizedTrue) { - elseFlowInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - if (((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) && - ((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)) { - // Mark then block as unreachable - // No need if the whole if-else construct itself lies in unreachable code - this.bits |= ASTNode.IsThenStatementUnreachable; - } else if (((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) && - ((elseFlowInfo.tagBits & FlowInfo.UNREACHABLE) != 0)) { - // Mark else block as unreachable - // 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 (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() - this.bits &= ~ASTNode.IsThenStatementUnreachable; - } - } - this.condition.updateFlowOnBooleanResult(thenFlowInfo, true); - thenFlowInfo = this.thenStatement.analyseCode(currentScope, flowContext, thenFlowInfo); - if (!(this.thenStatement instanceof Block)) - flowContext.expireNullCheckedFieldInfo(); - } - // any null check from the condition is now expired - flowContext.expireNullCheckedFieldInfo(); - // code gen: optimizing the jump around the ELSE part - if ((thenFlowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) { - this.bits |= ASTNode.ThenExit; - } - - // process the ELSE part - if (this.elseStatement != null) { - // signal else clause unnecessarily nested, tolerate else-if code pattern - if (thenFlowInfo == FlowInfo.DEAD_END - && (this.bits & IsElseIfStatement) == 0 // else of an else-if - && !(this.elseStatement instanceof IfStatement)) { - currentScope.problemReporter().unnecessaryElse(this.elseStatement); - } - // Save info for code gen - this.elseInitStateIndex = currentScope.methodScope().recordInitializationStates(elseFlowInfo); - if (isConditionOptimizedTrue || ((this.bits & ASTNode.IsElseStatementUnreachable) != 0)) { - 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() - this.bits &= ~ASTNode.IsElseStatementUnreachable; - } - } - this.condition.updateFlowOnBooleanResult(elseFlowInfo, false); - elseFlowInfo = this.elseStatement.analyseCode(currentScope, flowContext, elseFlowInfo); - if (!(this.elseStatement instanceof Block)) - flowContext.expireNullCheckedFieldInfo(); - } - if (nullCheckedFields != null) { - for (FieldBinding fieldBinding : nullCheckedFields) { - if (fieldBinding.closeTracker != null) { - LocalVariableBinding trackerBinding = fieldBinding.closeTracker.binding; - int closeStatus = thenFlowInfo.nullStatus(trackerBinding); - if (closeStatus == FlowInfo.NON_NULL || closeStatus == FlowInfo.POTENTIALLY_NON_NULL) { - elseFlowInfo.markNullStatus(trackerBinding, closeStatus); - } - } - } - } - // process AutoCloseable resources closed in only one branch: - currentScope.correlateTrackingVarsIfElse(thenFlowInfo, elseFlowInfo); - // merge THEN & ELSE initializations - FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranchesIfElse( - thenFlowInfo, - isConditionOptimizedTrue, - elseFlowInfo, - isConditionOptimizedFalse, - true /*if(true){ return; } fake-reachable(); */, - flowInfo, - this, - reportDeadCodeForKnownPattern); - this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); - flowContext.conditionalLevel--; - return mergedInfo; -} -/** - * If code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - BranchLabel endifLabel = new BranchLabel(codeStream); - - // optimizing the then/else part code gen - Constant cst; - boolean hasThenPart = - !(((cst = this.condition.optimizedBooleanConstant()) != Constant.NotAConstant - && cst.booleanValue() == false) - || this.thenStatement == null - || this.thenStatement.isEmptyBlock()); - boolean hasElsePart = - !((cst != Constant.NotAConstant && cst.booleanValue() == true) - || this.elseStatement == null - || this.elseStatement.isEmptyBlock()); - if (hasThenPart) { - BranchLabel falseLabel = null; - // generate boolean condition only if needed - if (cst != Constant.NotAConstant && cst.booleanValue() == true) { - this.condition.generateCode(currentScope, codeStream, false); - } else { - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - null, - hasElsePart ? (falseLabel = new BranchLabel(codeStream)) : endifLabel, - true/*cst == Constant.NotAConstant*/); - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.thenInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex); - } - // generate then statement - this.thenStatement.generateCode(currentScope, codeStream); - // jump around the else statement - if (hasElsePart) { - if ((this.bits & ASTNode.ThenExit) == 0) { - this.thenStatement.branchChainTo(endifLabel); - int position = codeStream.position; - codeStream.goto_(endifLabel); - //goto is pointing to the last line of the thenStatement - codeStream.recordPositionsFrom(position, this.thenStatement.sourceEnd); - // generate else statement - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.elseInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - this.elseInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.elseInitStateIndex); - } - if (falseLabel != null) falseLabel.place(); - this.elseStatement.generateCode(currentScope, codeStream); - } - } else if (hasElsePart) { - // generate boolean condition only if needed - if (cst != Constant.NotAConstant && cst.booleanValue() == false) { - this.condition.generateCode(currentScope, codeStream, false); - } else { - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - endifLabel, - null, - true/*cst == Constant.NotAConstant*/); - } - // generate else statement - // May loose some local variable initializations : affecting the local variable attributes - if (this.elseInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - this.elseInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.elseInitStateIndex); - } - this.elseStatement.generateCode(currentScope, codeStream); - } else { - // generate condition side-effects - if (this.condition.containsPatternVariable()) { - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - endifLabel, - null, - cst == Constant.NotAConstant); - } else { - this.condition.generateCode(currentScope, codeStream, false); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables( - currentScope, - this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - endifLabel.place(); - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - - - -@Override -public StringBuilder printStatement(int indent, StringBuilder output) { - printIndent(indent, output).append("if ("); //$NON-NLS-1$ - this.condition.printExpression(0, output).append(")\n"); //$NON-NLS-1$ - this.thenStatement.printStatement(indent + 2, output); - if (this.elseStatement != null) { - output.append('\n'); - printIndent(indent, output); - output.append("else\n"); //$NON-NLS-1$ - this.elseStatement.printStatement(indent + 2, output); - } - return output; -} - -@Override -public LocalVariableBinding[] bindingsWhenComplete() { - if (!this.condition.containsPatternVariable() || doesNotCompleteNormally()) - return NO_VARIABLES; - if (this.thenStatement != null && this.thenStatement.doesNotCompleteNormally()) - return this.condition.bindingsWhenFalse(); - if (this.elseStatement != null && this.elseStatement.doesNotCompleteNormally()) - return this.condition.bindingsWhenTrue(); - return NO_VARIABLES; -} -@Override -public void resolve(BlockScope scope) { - TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); - this.condition.computeConversion(scope, type, type); - - if (this.thenStatement != null) { - this.thenStatement.resolveWithBindings(this.condition.bindingsWhenTrue(), scope); - } - if (this.elseStatement != null) { - this.elseStatement.resolveWithBindings(this.condition.bindingsWhenFalse(), scope); - } -} - -@Override -public boolean containsPatternVariable() { - return this.condition.containsPatternVariable(); -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) { - this.condition.traverse(visitor, blockScope); - if (this.thenStatement != null) - this.thenStatement.traverse(visitor, blockScope); - if (this.elseStatement != null) - this.elseStatement.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); -} - -@Override -public boolean doesNotCompleteNormally() { - return this.thenStatement != null && this.thenStatement.doesNotCompleteNormally() && this.elseStatement != null && this.elseStatement.doesNotCompleteNormally(); -} -@Override -public boolean completesByContinue() { - return this.thenStatement != null && this.thenStatement.completesByContinue() || this.elseStatement != null && this.elseStatement.completesByContinue(); -} -@Override -public boolean canCompleteNormally() { - return ((this.thenStatement == null || this.thenStatement.canCompleteNormally()) || - (this.elseStatement == null || this.elseStatement.canCompleteNormally())); -} -@Override -public boolean continueCompletes() { - return this.thenStatement != null && this.thenStatement.continueCompletes() || - this.elseStatement != null && this.elseStatement.continueCompletes(); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ImportReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ImportReference.java deleted file mode 100644 index 09602ac..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ImportReference.java +++ /dev/null @@ -1,107 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class ImportReference extends ASTNode { - - public char[][] tokens; - public long[] sourcePositions; //each entry is using the code : (start<<32) + end - public int declarationEnd; // doesn't include an potential trailing comment - public int declarationSourceStart; - public int declarationSourceEnd; - public int modifiers; // 1.5 addition for static imports - public Annotation[] annotations; - // star end position - public int trailingStarPosition; - - public ImportReference( - char[][] tokens, - long[] sourcePositions, - boolean onDemand, - int modifiers) { - - this.tokens = tokens; - this.sourcePositions = sourcePositions; - if (onDemand) { - this.bits |= ASTNode.OnDemand; - } - this.sourceEnd = (int) (sourcePositions[sourcePositions.length-1] & 0x00000000FFFFFFFF); - this.sourceStart = (int) (sourcePositions[0] >>> 32); - this.modifiers = modifiers; - } - - public boolean isStatic() { - return (this.modifiers & ClassFileConstants.AccStatic) != 0; - } - - public char[][] getImportName() { - return this.tokens; - } - - public char[] getSimpleName() { - return this.tokens[this.tokens.length - 1]; - } - - public void checkPackageConflict(CompilationUnitScope scope) { - ModuleBinding module = scope.module(); - PackageBinding visiblePackage = module.getVisiblePackage(this.tokens); - if (visiblePackage instanceof SplitPackageBinding) { - Set declaringMods = new HashSet<>(); - for (PackageBinding incarnation : ((SplitPackageBinding) visiblePackage).incarnations) { - if (incarnation.enclosingModule != module && module.canAccess(incarnation)) - declaringMods.add(incarnation.enclosingModule); - } - if (!declaringMods.isEmpty()) { - CompilerOptions compilerOptions = scope.compilerOptions(); - boolean inJdtDebugCompileMode = compilerOptions.enableJdtDebugCompileMode; - if (!inJdtDebugCompileMode) { - scope.problemReporter().conflictingPackagesFromOtherModules(this, declaringMods); - } - } - } - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - - return print(indent, output, true); - } - - public StringBuilder print(int tab, StringBuilder output, boolean withOnDemand) { - - /* when withOnDemand is false, only the name is printed */ - for (int i = 0; i < this.tokens.length; i++) { - if (i > 0) output.append('.'); - output.append(this.tokens[i]); - } - if (withOnDemand && ((this.bits & ASTNode.OnDemand) != 0)) { - output.append(".*"); //$NON-NLS-1$ - } - return output; - } - - public void traverse(ASTVisitor visitor, CompilationUnitScope scope) { - // annotations are traversed during the compilation unit traversal using a class scope - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Initializer.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Initializer.java deleted file mode 100644 index 90c7e46..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Initializer.java +++ /dev/null @@ -1,163 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - *Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 429813 - [1.8][dom ast] IMethodBinding#getJavaElement() should return IMethod for lambda - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.parser.*; - -public class Initializer extends FieldDeclaration { - - public Block block; - public int lastVisibleFieldID; - public int bodyStart; - public int bodyEnd; - - private MethodBinding methodBinding; - - public Initializer(Block block, int modifiers) { - this.block = block; - this.modifiers = modifiers; - - if (block != null) { - this.declarationSourceStart = this.sourceStart = block.sourceStart; - } - } - - @Override - public FlowInfo analyseCode( - MethodScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - if (this.block != null) { - return this.block.analyseCode(currentScope, flowContext, flowInfo); - } - return flowInfo; - } - - /** - * Code generation for a non-static initializer: - * standard block code gen - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - if (this.block != null) this.block.generateCode(currentScope, codeStream); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind() - */ - @Override - public int getKind() { - return INITIALIZER; - } - - @Override - public boolean isStatic() { - - return (this.modifiers & ClassFileConstants.AccStatic) != 0; - } - - public void parseStatements( - Parser parser, - TypeDeclaration typeDeclaration, - CompilationUnitDeclaration unit) { - - //fill up the method body with statement - parser.parse(this, typeDeclaration, unit); - } - - @Override - public StringBuilder printStatement(int indent, StringBuilder output) { - - if (this.modifiers != 0) { - printIndent(indent, output); - printModifiers(this.modifiers, output); - if (this.annotations != null) { - printAnnotations(this.annotations, output); - output.append(' '); - } - output.append("{\n"); //$NON-NLS-1$ - if (this.block != null) { - this.block.printBody(indent, output); - } - printIndent(indent, output).append('}'); - return output; - } else if (this.block != null) { - this.block.printStatement(indent, output); - } else { - printIndent(indent, output).append("{}"); //$NON-NLS-1$ - } - return output; - } - - @Override - public void resolve(MethodScope scope) { - - FieldBinding previousField = scope.initializedField; - int previousFieldID = scope.lastVisibleFieldID; - try { - scope.initializedField = null; - scope.lastVisibleFieldID = this.lastVisibleFieldID; - if (isStatic()) { - ReferenceBinding declaringType = scope.enclosingSourceType(); - if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK16) { - if (declaringType.isNestedType() && !declaringType.isStatic()) - scope.problemReporter().innerTypesCannotDeclareStaticInitializers( - declaringType, - this); - } - } - if (this.block != null) this.block.resolve(scope); - } finally { - scope.initializedField = previousField; - scope.lastVisibleFieldID = previousFieldID; - } - } - - /** Method used only by DOM to support bindings of initializers. */ - public MethodBinding getMethodBinding() { - if (this.methodBinding == null) { - Scope scope = this.block.scope; - this.methodBinding = isStatic() - ? new MethodBinding(ClassFileConstants.AccStatic, CharOperation.NO_CHAR, TypeBinding.VOID, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, scope.enclosingSourceType()) - : new MethodBinding(0, CharOperation.NO_CHAR, TypeBinding.VOID, Binding.NO_PARAMETERS, Binding.NO_EXCEPTIONS, scope.enclosingSourceType()); - } - return this.methodBinding; - } - - @Override - public void traverse(ASTVisitor visitor, MethodScope scope) { - if (visitor.visit(this, scope)) { - if (this.block != null) this.block.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java deleted file mode 100644 index a2cc487..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/InstanceOfExpression.java +++ /dev/null @@ -1,332 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 383368 - [compiler][null] syntactic null analysis for field references - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" - * Bug 466713 - Null Annotations: NullPointerException using as Type Param - * Andy Clement - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class InstanceOfExpression extends OperatorExpression { - - public Expression expression; - public TypeReference type; - public LocalDeclaration elementVariable; - public Pattern pattern; - static final char[] SECRET_EXPRESSION_VALUE = " secretExpressionValue".toCharArray(); //$NON-NLS-1$ - - private LocalVariableBinding secretExpressionValue = null; - -public InstanceOfExpression(Expression expression, TypeReference type) { - this.expression = expression; - this.type = type; - type.bits |= IgnoreRawTypeCheck; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=282141 - this.bits |= INSTANCEOF << OperatorSHIFT; - this.sourceStart = expression.sourceStart; - this.sourceEnd = type.sourceEnd; -} -public InstanceOfExpression(Expression expression, Pattern pattern) { - this.expression = expression; - this.pattern = pattern; - this.elementVariable = pattern.getPatternVariable(); - this.type = pattern.getType(); - this.type.bits |= IgnoreRawTypeCheck; - this.bits |= INSTANCEOF << OperatorSHIFT; - this.sourceStart = expression.sourceStart; - this.sourceEnd = this.pattern.sourceEnd; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - LocalVariableBinding local = this.expression.localVariableBinding(); - FlowInfo initsWhenTrue = null; - if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) { - flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo). - unconditionalInits(); - initsWhenTrue = flowInfo.copy(); - initsWhenTrue.markAsComparedEqualToNonNull(local); - flowContext.recordUsingNullReference(currentScope, local, - this.expression, FlowContext.CAN_ONLY_NULL | FlowContext.IN_INSTANCEOF, flowInfo); - // no impact upon enclosing try context - flowInfo = FlowInfo.conditional(initsWhenTrue.copy(), flowInfo.copy()); - } else if (this.expression instanceof Reference) { - if (currentScope.compilerOptions().enableSyntacticNullAnalysisForFields) { - FieldBinding field = ((Reference)this.expression).lastFieldBinding(); - if (field != null && (field.type.tagBits & TagBits.IsBaseType) == 0) { - flowContext.recordNullCheckedFieldReference((Reference) this.expression, 1); - } - } - } - if (initsWhenTrue == null) { - flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo). - unconditionalInits(); - } - if (this.pattern != null) { - FlowInfo patternFlow = this.pattern.analyseCode(currentScope, flowContext, (initsWhenTrue == null) ? flowInfo : initsWhenTrue); - initsWhenTrue = initsWhenTrue == null ? patternFlow : initsWhenTrue.addInitializationsFrom(patternFlow); - } - return (initsWhenTrue == null) ? flowInfo : - FlowInfo.conditional(initsWhenTrue, flowInfo.copy()); -} -/** - * Code generation for instanceOfExpression - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean -*/ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - if (this.elementVariable != null && this.elementVariable.binding != null) { - this.elementVariable.binding.modifiers &= ~ExtraCompilerModifiers.AccOutOfFlowScope; - } - addPatternVariables(currentScope, codeStream); - - int pc = codeStream.position; - - this.expression.generateCode(currentScope, codeStream, true); - if (this.secretExpressionValue != null) { - codeStream.store(this.secretExpressionValue, true); - codeStream.addVariable(this.secretExpressionValue); - } - codeStream.instance_of(this.type, this.type.resolvedType); - if (this.pattern != null) { - BranchLabel falseLabel = new BranchLabel(codeStream); - BranchLabel trueLabel = new BranchLabel(codeStream); - BranchLabel continueLabel = new BranchLabel(codeStream); - codeStream.ifeq(falseLabel); - - if (this.secretExpressionValue != null) { - codeStream.load(this.secretExpressionValue); - codeStream.removeVariable(this.secretExpressionValue); - } else { - this.expression.generateCode(currentScope, codeStream, true); - } - this.pattern.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel); - - trueLabel.place(); - codeStream.iconst_1(); - codeStream.goto_(continueLabel); - falseLabel.place(); - for (LocalVariableBinding binding : this.pattern.bindingsWhenTrue()) { - binding.recordInitializationEndPC(codeStream.position); - } - codeStream.iconst_0(); - continueLabel.place(); - - } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - codeStream.pop(); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} -@Override -public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - // a label valued to nil means: by default we fall through the case... - // both nil means we leave the value on the stack - - if (this.elementVariable == null && this.pattern == null) { - super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - return; - } - addPatternVariables(currentScope, codeStream); - - int pc = codeStream.position; - - this.expression.generateCode(currentScope, codeStream, true); - if (this.secretExpressionValue != null) { - codeStream.store(this.secretExpressionValue, true); - codeStream.addVariable(this.secretExpressionValue); - } - - BranchLabel nextSibling = falseLabel != null ? falseLabel : new BranchLabel(codeStream); - codeStream.instance_of(this.type, this.type.resolvedType); - codeStream.ifeq(nextSibling); - if (this.secretExpressionValue != null) { - codeStream.load(this.secretExpressionValue); - codeStream.removeVariable(this.secretExpressionValue); - } else { - this.expression.generateCode(currentScope, codeStream, true); - } - - if (this.pattern instanceof RecordPattern) { - this.pattern.generateOptimizedBoolean(currentScope, codeStream, trueLabel, nextSibling); - } else { - codeStream.checkcast(this.type, this.type.resolvedType, codeStream.position); - codeStream.store(this.elementVariable.binding, false); - } - - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - codeStream.pop(); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - - int position = codeStream.position; - if (valueRequired) { - if (falseLabel == null) { - if (trueLabel != null) { - // Implicit falling through the FALSE case - codeStream.goto_(trueLabel); - } - } else { - if (trueLabel == null) { - // Implicit falling through the TRUE case - } else { - // No implicit fall through TRUE/FALSE --> should never occur - } - } - } - codeStream.recordPositionsFrom(position, this.sourceEnd); - - if (nextSibling != falseLabel) - nextSibling.place(); -} - -@Override -public StringBuilder printExpressionNoParenthesis(int indent, StringBuilder output) { - this.expression.printExpression(indent, output).append(" instanceof "); //$NON-NLS-1$ - return this.pattern == null ? this.type.print(0, output) : this.pattern.printExpression(0, output); -} - -@Override -public void addPatternVariables(BlockScope currentScope, CodeStream codeStream) { - for (LocalVariableBinding local: bindingsWhenTrue()) { - codeStream.addVisibleLocalVariable(local); - } -} -@Override -public LocalVariableBinding[] bindingsWhenTrue() { - return this.pattern != null ? this.pattern.bindingsWhenTrue() : NO_VARIABLES; -} -@Override -public boolean containsPatternVariable() { - return this.elementVariable != null || this.pattern != null; -} -@Override -public LocalDeclaration getPatternVariable() { - return this.elementVariable; -} -@Override -public TypeBinding resolveType(BlockScope scope) { - this.constant = Constant.NotAConstant; - - TypeBinding checkedType = this.type.resolveType(scope, true /* check bounds*/); - if (this.expression instanceof CastExpression) { - ((CastExpression) this.expression).setInstanceofType(checkedType); // for cast expression we need to know instanceof type to not tag unnecessary when needed - } - TypeBinding expressionType = this.expression.resolveType(scope); - if (this.pattern != null) { - this.pattern.setExpressionContext(ExpressionContext.INSTANCEOF_CONTEXT); - this.pattern.setExpectedType(this.expression.resolvedType); - this.pattern.resolveType(scope); - - if ((this.expression.bits & ASTNode.RestrictiveFlagMASK) != Binding.LOCAL) { - // reevaluation may double jeopardize as side effects may recur, compute once and cache - LocalVariableBinding local = - new LocalVariableBinding( - InstanceOfExpression.SECRET_EXPRESSION_VALUE, - TypeBinding.wellKnownType(scope, T_JavaLangObject), // good enough, no need for sharper type. - ClassFileConstants.AccDefault, - false); - local.setConstant(Constant.NotAConstant); - local.useFlag = LocalVariableBinding.USED; - scope.addLocalVariable(local); - this.secretExpressionValue = local; - if (expressionType != TypeBinding.NULL) - this.secretExpressionValue.type = expressionType; - } - } - if (expressionType != null && checkedType != null && this.type.hasNullTypeAnnotation(AnnotationPosition.ANY)) { - // don't complain if the entire operation is redundant anyway - if (!expressionType.isCompatibleWith(checkedType) || NullAnnotationMatching.analyse(checkedType, expressionType, -1).isAnyMismatch()) - scope.problemReporter().nullAnnotationUnsupportedLocation(this.type); - } - - if (expressionType == null || checkedType == null) - return null; - - if (!checkedType.isReifiable()) { - CompilerOptions options = scope.compilerOptions(); - // Report same as before for older compliances - if (options.complianceLevel < ClassFileConstants.JDK16) { - scope.problemReporter().illegalInstanceOfGenericType(checkedType, this); - } else { - if (expressionType != TypeBinding.NULL) { - boolean isLegal = checkCastTypesCompatibility(scope, checkedType, expressionType, this.expression, true); - if (!isLegal || (this.bits & ASTNode.UnsafeCast) != 0) { - scope.problemReporter().unsafeCastInInstanceof(this.expression, checkedType, expressionType); - } - } - } - } else if (checkedType.isValidBinding()) { - // if not a valid binding, an error has already been reported for unresolved type - if ((expressionType != TypeBinding.NULL && expressionType.isBaseType()) // disallow autoboxing - || checkedType.isBaseType() - || !checkCastTypesCompatibility(scope, checkedType, expressionType, null, true)) { - scope.problemReporter().notCompatibleTypesError(this, expressionType, checkedType); - } - } - - return this.resolvedType = TypeBinding.BOOLEAN; -} -@Override -public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { - if (!castType.isReifiable()) - return CastExpression.checkUnsafeCast(this, scope, castType, expressionType, match, isNarrowing); - else - return super.checkUnsafeCast(scope, castType, expressionType, match, isNarrowing); -} -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#tagAsUnnecessaryCast(Scope,TypeBinding) - */ - -@Override -public void tagAsUnnecessaryCast(Scope scope, TypeBinding castType) { - // null is not instanceof Type, recognize direct scenario - if (this.expression.resolvedType != TypeBinding.NULL) - scope.problemReporter().unnecessaryInstanceof(this, castType); -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.expression.traverse(visitor, scope); - if (this.pattern != null) { - this.pattern.traverse(visitor, scope); - } else { - this.type.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java deleted file mode 100644 index 05cff9b..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IntLiteral.java +++ /dev/null @@ -1,183 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.IntConstant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; - -public class IntLiteral extends NumberLiteral { - private static final char[] HEXA_MIN_VALUE = "0x80000000".toCharArray(); //$NON-NLS-1$ - private static final char[] HEXA_MINUS_ONE_VALUE = "0xffffffff".toCharArray(); //$NON-NLS-1$ - private static final char[] OCTAL_MIN_VALUE = "020000000000".toCharArray(); //$NON-NLS-1$ - private static final char[] OCTAL_MINUS_ONE_VALUE = "037777777777".toCharArray(); //$NON-NLS-1$ - private static final char[] DECIMAL_MIN_VALUE = "2147483648".toCharArray(); //$NON-NLS-1$ - private static final char[] DECIMAL_MAX_VALUE = "2147483647".toCharArray(); //$NON-NLS-1$ - - private final char[] reducedForm; // no underscores - - public int value; - - //used for ++ and -- - public static final IntLiteral One = new IntLiteral(new char[]{'1'}, null, 0, 0, 1, IntConstant.fromValue(1)); - - public static IntLiteral buildIntLiteral(char[] token, int s, int e) { - // remove '_' and prefix '0' first - char[] intReducedToken = removePrefixZerosAndUnderscores(token, false); - switch(intReducedToken.length) { - case 10 : - // 0x80000000 - if (CharOperation.equals(intReducedToken, HEXA_MIN_VALUE)) { - return new IntLiteralMinValue(token, intReducedToken != token ? intReducedToken : null, s, e); - } - break; - case 12 : - // 020000000000 - if (CharOperation.equals(intReducedToken, OCTAL_MIN_VALUE)) { - return new IntLiteralMinValue(token, intReducedToken != token ? intReducedToken : null, s, e); - } - break; - } - return new IntLiteral(token, intReducedToken != token ? intReducedToken : null, s, e); - } -IntLiteral(char[] token, char[] reducedForm, int start, int end) { - super(token, start, end); - this.reducedForm = reducedForm; -} -IntLiteral(char[] token, char[] reducedForm, int start, int end, int value, Constant constant) { - super(token, start, end); - this.reducedForm = reducedForm; - this.value = value; - this.constant = constant; -} -@Override -public void computeConstant() { - char[] token = this.reducedForm != null ? this.reducedForm : this.source; - int tokenLength = token.length; - int radix = 10; - int j = 0; - if (token[0] == '0') { - if (tokenLength == 1) { - this.constant = IntConstant.fromValue(0); - return; - } - if ((token[1] == 'x') || (token[1] == 'X')) { - radix = 16; - j = 2; - } else if ((token[1] == 'b') || (token[1] == 'B')) { - radix = 2; - j = 2; - } else { - radix = 8; - j = 1; - } - } - switch(radix) { - case 2 : - if ((tokenLength - 2) > 32) { - // remove 0b or 0B - return; /*constant stays null*/ - } - computeValue(token, tokenLength, radix, j); - return; - case 16 : - if (tokenLength <= 10) { - if (CharOperation.equals(token, HEXA_MINUS_ONE_VALUE)) { - this.constant = IntConstant.fromValue(-1); - return; - } - computeValue(token, tokenLength, radix, j); - return; - } - break; - case 10 : - if (tokenLength > DECIMAL_MAX_VALUE.length - || (tokenLength == DECIMAL_MAX_VALUE.length - && CharOperation.compareTo(token, DECIMAL_MAX_VALUE) > 0)) { - return; /*constant stays null*/ - } - computeValue(token, tokenLength, radix, j); - break; - case 8 : - if (tokenLength <= 12) { - if (tokenLength == 12 && token[j] > '4') { - return; /*constant stays null*/ - } - if (CharOperation.equals(token, OCTAL_MINUS_ONE_VALUE)) { - this.constant = IntConstant.fromValue(-1); - return; - } - computeValue(token, tokenLength, radix, j); - return; - } - break; - } -} -private void computeValue(char[] token, int tokenLength, int radix, int j) { - int digitValue; - int computedValue = 0; - while (j < tokenLength) { - if ((digitValue = ScannerHelper.digit(token[j++],radix)) < 0) { - return; /*constant stays null*/ - } - computedValue = (computedValue * radix) + digitValue ; - } - this.constant = IntConstant.fromValue(computedValue); -} -public IntLiteral convertToMinValue() { - if (((this.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) { - return this; - } - char[] token = this.reducedForm != null ? this.reducedForm : this.source; - switch(token.length) { - case 10 : - // 2147483648 - if (CharOperation.equals(token, DECIMAL_MIN_VALUE)) { - return new IntLiteralMinValue(this.source, this.reducedForm, this.sourceStart, this.sourceEnd); - } - break; - } - return this; -} -/** - * Code generation for long literal - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public TypeBinding literalType(BlockScope scope) { - return TypeBinding.INT; -} -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java deleted file mode 100644 index 5dfed33..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IntLiteralMinValue.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.impl.*; - -public class IntLiteralMinValue extends IntLiteral { - - final static char[] CharValue = new char[]{'-','2','1','4','7','4','8','3','6','4','8'}; - -public IntLiteralMinValue(char[] token, char[] reducedToken, int start, int end) { - super(token, reducedToken, start, end, Integer.MIN_VALUE, IntConstant.fromValue(Integer.MIN_VALUE)); -} - -@Override -public void computeConstant(){ - /*precomputed at creation time*/ } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java deleted file mode 100644 index 40dc3e7..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/IntersectionCastTypeReference.java +++ /dev/null @@ -1,195 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011, 2014 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 409236 - [1.8][compiler] Type annotations on intersection cast types dropped by code generator - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.HashMap; -import java.util.Map; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -@SuppressWarnings({"rawtypes"}) -public class IntersectionCastTypeReference extends TypeReference { - public TypeReference[] typeReferences; - - public IntersectionCastTypeReference(TypeReference[] typeReferences) { - this.typeReferences = typeReferences; - this.sourceStart = typeReferences[0].sourceStart; - int length = typeReferences.length; - this.sourceEnd = typeReferences[length - 1].sourceEnd; - for (int i = 0, max = typeReferences.length; i < max; i++) { - if ((typeReferences[i].bits & ASTNode.HasTypeAnnotations) != 0) { - this.bits |= ASTNode.HasTypeAnnotations; - break; - } - } - } - - @Override - public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { - throw new UnsupportedOperationException(); // no syntax for this. - } - - @Override - public char[] getLastToken() { - return null; - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope) - */ - @Override - protected TypeBinding getTypeBinding(Scope scope) { - return null; // not supported here - combined with resolveType(...) - } - - @Override - public TypeReference[] getTypeReferences() { - return this.typeReferences; - } - - @Override - public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) { - - int length = this.typeReferences.length; - ReferenceBinding[] intersectingTypes = new ReferenceBinding[length]; - boolean hasError = false; - - int typeCount = 0; - nextType: - for (int i = 0; i < length; i++) { - final TypeReference typeReference = this.typeReferences[i]; - TypeBinding type = typeReference.resolveType(scope, checkBounds, location); - if (type == null || ((type.tagBits & TagBits.HasMissingType) != 0)) { - hasError = true; - continue; - } - if (i == 0) { - if (type.isBaseType()) { // rejected in grammar for i > 0 - scope.problemReporter().onlyReferenceTypesInIntersectionCast(typeReference); - hasError = true; - continue; - } - if (type.isArrayType()) { // javac rejects the pedantic cast: (X[] & Serializable & Cloneable) new X[0], what is good for the goose ... - scope.problemReporter().illegalArrayTypeInIntersectionCast(typeReference); - hasError = true; - continue; - } - } else if (!type.isInterface()) { - scope.problemReporter().boundMustBeAnInterface(typeReference, type); - hasError = true; - continue; - } - for (int j = 0; j < typeCount; j++) { - final ReferenceBinding priorType = intersectingTypes[j]; - if (TypeBinding.equalsEquals(priorType, type)) { - scope.problemReporter().duplicateBoundInIntersectionCast(typeReference); - hasError = true; - continue; - } - if (!priorType.isInterface()) - continue; - if (TypeBinding.equalsEquals(type.findSuperTypeOriginatingFrom(priorType), priorType)) { - intersectingTypes[j] = (ReferenceBinding) type; - continue nextType; - } - if (TypeBinding.equalsEquals(priorType.findSuperTypeOriginatingFrom(type), type)) - continue nextType; - } - intersectingTypes[typeCount++] = (ReferenceBinding) type; - } - - if (hasError) { - return null; - } - if (typeCount != length) { - if (typeCount == 1) { - return this.resolvedType = intersectingTypes[0]; - } - System.arraycopy(intersectingTypes, 0, intersectingTypes = new ReferenceBinding[typeCount], 0, typeCount); - } - IntersectionTypeBinding18 intersectionType = (IntersectionTypeBinding18) scope.environment().createIntersectionType18(intersectingTypes); - // check for parameterized interface collisions (when different parameterizations occur) - ReferenceBinding itsSuperclass = null; - ReferenceBinding[] interfaces = intersectingTypes; - ReferenceBinding firstType = intersectingTypes[0]; - if (firstType.isClass()) { - itsSuperclass = firstType.superclass(); - System.arraycopy(intersectingTypes, 1, interfaces = new ReferenceBinding[typeCount - 1], 0, typeCount - 1); - } - - Map invocations = new HashMap(2); - nextInterface: for (int i = 0, interfaceCount = interfaces.length; i < interfaceCount; i++) { - ReferenceBinding one = interfaces[i]; - if (one == null) continue nextInterface; - if (itsSuperclass != null && scope.hasErasedCandidatesCollisions(itsSuperclass, one, invocations, intersectionType, this)) - continue nextInterface; - nextOtherInterface: for (int j = 0; j < i; j++) { - ReferenceBinding two = interfaces[j]; - if (two == null) continue nextOtherInterface; - if (scope.hasErasedCandidatesCollisions(one, two, invocations, intersectionType, this)) - continue nextInterface; - } - } - if ((intersectionType.tagBits & TagBits.HierarchyHasProblems) != 0) - return null; - - return (this.resolvedType = intersectionType); - } - - @Override - public char[][] getTypeName() { - // we need to keep a return value that is a char[][] - return this.typeReferences[0].getTypeName(); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - int length = this.typeReferences == null ? 0 : this.typeReferences.length; - for (int i = 0; i < length; i++) { - this.typeReferences[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - throw new UnsupportedOperationException("Unexpected traversal request: IntersectionTypeReference in class scope"); //$NON-NLS-1$ - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - int length = this.typeReferences == null ? 0 : this.typeReferences.length; - printIndent(indent, output); - for (int i = 0; i < length; i++) { - this.typeReferences[i].printExpression(0, output); - if (i != length - 1) { - output.append(" & "); //$NON-NLS-1$ - } - } - return output; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Invocation.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Invocation.java deleted file mode 100644 index 2e84117..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Invocation.java +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013, 2014 GK Software AG. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Stephan Herrmann - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -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.ParameterizedMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -/** - * Abstraction for invocation AST nodes that can trigger overload resolution possibly involving type inference -*/ -public interface Invocation extends InvocationSite { - - Expression[] arguments(); - - /** Answer the resolved method binding of this invocation */ - MethodBinding binding(); - - /** - * Register the given inference context, which produced the given method as its intermediate result. - * Later when the same method is selected as the most specific method, the inference context - * for this pair (Invocation x MethodBinding) can be looked up using {@link #getInferenceContext(ParameterizedMethodBinding)} - * to continue the type inference. - */ - void registerInferenceContext(ParameterizedGenericMethodBinding method, InferenceContext18 infCtx18); - - /** - * Retrieve an inference context for the given method. - * @param method an intermediate resolved candidate for this invocation - * return the associated inference context. - */ - InferenceContext18 getInferenceContext(ParameterizedMethodBinding method); - - /** Discard any state from type inference when compilation is done. */ - void cleanUpInferenceContexts(); - - /** Record result against target type */ - void registerResult(TypeBinding targetType, MethodBinding method); - - /** Resource leak analysis: track the case that a resource is passed as an argument to an invocation. */ - default FlowInfo handleResourcePassedToInvocation(BlockScope currentScope, MethodBinding methodBinding, Expression argument, int rank, - FlowContext flowContext, FlowInfo flowInfo) { - if (currentScope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled) { - FakedTrackingVariable trackVar = FakedTrackingVariable.getCloseTrackingVariable(argument, flowInfo, flowContext, true); - if (trackVar != null) { - if (methodBinding.ownsParameter(rank)) { - trackVar.markOwnedByOutside(flowInfo, flowContext); - } else if (methodBinding.notownsParameter(rank)) { - // ignore, no relevant change - } else { - trackVar.markAsShared(); - } - } - } else { - // insert info that it *may* be closed (by the target constructor, i.e.) - return FakedTrackingVariable.markPassedToOutside(currentScope, argument, flowInfo, flowContext, false); - } - return flowInfo; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Javadoc.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Javadoc.java deleted file mode 100644 index 8b16c46..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Javadoc.java +++ /dev/null @@ -1,1275 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.parser.JavadocTagConstants; - -/** - * Node representing a structured Javadoc comment - */ -public class Javadoc extends ASTNode { - - public JavadocSingleNameReference[] paramReferences; // @param - public JavadocSingleTypeReference[] paramTypeParameters; // @param - public TypeReference[] exceptionReferences; // @throws, @exception - public JavadocReturnStatement returnStatement; // @return - public Expression[] seeReferences; // @see - public IJavadocTypeReference[] usesReferences; // @uses - public IJavadocTypeReference[] providesReferences; // @provides - public long[] inheritedPositions = null; - // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51600 - // Store param references for tag with invalid syntax - public JavadocSingleNameReference[] invalidParameters; // @param - // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=153399 - // Store value tag positions - public long valuePositions = -1; - - public Javadoc(int sourceStart, int sourceEnd) { - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - this.bits |= ASTNode.ResolveJavadoc; - } - /** - * Returns whether a type can be seen at a given visibility level or not. - * - * @param visibility Level of visiblity allowed to see references - * @param modifiers modifiers of java element to be seen - * @return true if the type can be seen, false otherwise - */ - boolean canBeSeen(int visibility, int modifiers) { - if (modifiers < 0) return true; - switch (modifiers & ExtraCompilerModifiers.AccVisibilityMASK) { - case ClassFileConstants.AccPublic : - return true; - case ClassFileConstants.AccProtected: - return (visibility != ClassFileConstants.AccPublic); - case ClassFileConstants.AccDefault: - return (visibility == ClassFileConstants.AccDefault || visibility == ClassFileConstants.AccPrivate); - case ClassFileConstants.AccPrivate: - return (visibility == ClassFileConstants.AccPrivate); - } - return true; - } - - /* - * Search node with a given staring position in javadoc objects arrays. - */ - public ASTNode getNodeStartingAt(int start) { - int length = 0; - // parameters array - if (this.paramReferences != null) { - length = this.paramReferences.length; - for (int i=0; i\n"); //$NON-NLS-1$ - } - } - if (this.returnStatement != null) { - printIndent(indent + 1, output).append(" * @"); //$NON-NLS-1$ - this.returnStatement.print(indent, output).append('\n'); - } - if (this.exceptionReferences != null) { - for (int i = 0, length = this.exceptionReferences.length; i < length; i++) { - printIndent(indent + 1, output).append(" * @throws "); //$NON-NLS-1$ - this.exceptionReferences[i].print(indent, output).append('\n'); - } - } - if (this.seeReferences != null) { - for (int i = 0, length = this.seeReferences.length; i < length; i++) { - printIndent(indent + 1, output).append(" * @see "); //$NON-NLS-1$ - this.seeReferences[i].print(indent, output).append('\n'); - } - } - printIndent(indent, output).append(" */\n"); //$NON-NLS-1$ - return output; - } - - /* - * Resolve type javadoc - */ - public void resolve(ClassScope scope) { - if ((this.bits & ASTNode.ResolveJavadoc) == 0) { - return; - } - - this.bits &= ~ASTNode.ResolveJavadoc;// avoid double resolution - - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=247037, @inheritDoc tag cannot - // be used in the documentation comment for a class or interface. - if (this.inheritedPositions != null) { - int length = this.inheritedPositions.length; - for (int i = 0; i < length; ++i) { - int start = (int) (this.inheritedPositions[i] >>> 32); - int end = (int) this.inheritedPositions[i]; - scope.problemReporter().javadocUnexpectedTag(start, end); - } - } - // @param tags - int paramTagsSize = this.paramReferences == null ? 0 : this.paramReferences.length; - for (int i = 0; i < paramTagsSize; i++) { - if(scope.referenceContext.nRecordComponents > 0) { - break; - } - JavadocSingleNameReference param = this.paramReferences[i]; - scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd); - } - resolveTypeParameterTags(scope, true); - - // @return tags - if (this.returnStatement != null) { - scope.problemReporter().javadocUnexpectedTag(this.returnStatement.sourceStart, this.returnStatement.sourceEnd); - } - - // @throws/@exception tags - int throwsTagsLength = this.exceptionReferences == null ? 0 : this.exceptionReferences.length; - for (int i = 0; i < throwsTagsLength; i++) { - TypeReference typeRef = this.exceptionReferences[i]; - int start, end; - if (typeRef instanceof JavadocSingleTypeReference) { - JavadocSingleTypeReference singleRef = (JavadocSingleTypeReference) typeRef; - start = singleRef.tagSourceStart; - end = singleRef.tagSourceEnd; - } else if (typeRef instanceof JavadocQualifiedTypeReference) { - JavadocQualifiedTypeReference qualifiedRef = (JavadocQualifiedTypeReference) typeRef; - start = qualifiedRef.tagSourceStart; - end = qualifiedRef.tagSourceEnd; - } else { - start = typeRef.sourceStart; - end = typeRef.sourceEnd; - } - scope.problemReporter().javadocUnexpectedTag(start, end); - } - - // @see tags - int seeTagsLength = this.seeReferences == null ? 0 : this.seeReferences.length; - for (int i = 0; i < seeTagsLength; i++) { - resolveReference(this.seeReferences[i], scope); - } - - // @value tag - boolean source15 = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; - if (!source15 && this.valuePositions != -1) { - scope.problemReporter().javadocUnexpectedTag((int)(this.valuePositions>>>32), (int) this.valuePositions); - } - } - - /* - * Resolve compilation unit javadoc - */ - public void resolve(CompilationUnitScope unitScope) { - if ((this.bits & ASTNode.ResolveJavadoc) == 0) { - return; - } - // Do nothing - This is to mimic the SDK's javadoc tool behavior, which neither - // sanity checks nor generates documentation using comments at the CU scope - // (unless the unit happens to be package-info.java - in which case we don't come here.) - } - - /* - * Resolve module info javadoc - */ - public void resolve(ModuleScope moduleScope) { - if ((this.bits & ASTNode.ResolveJavadoc) == 0) { - return; - } - - this.bits &= ~ASTNode.ResolveJavadoc;// avoid double resolution - - // @see tags - int seeTagsLength = this.seeReferences == null ? 0 : this.seeReferences.length; - for (int i = 0; i < seeTagsLength; i++) { - // Resolve reference - resolveReference(this.seeReferences[i], moduleScope); - } - - resolveUsesTags(moduleScope, true); - resolveProvidesTags(moduleScope, true); - } - - /* - * Resolve method javadoc - */ - public void resolve(MethodScope methScope) { - if ((this.bits & ASTNode.ResolveJavadoc) == 0) { - return; - } - - this.bits &= ~ASTNode.ResolveJavadoc;// avoid double resolution - - // get method declaration - AbstractMethodDeclaration methDecl = methScope.referenceMethod(); - boolean overriding = methDecl == null /* field declaration */ || methDecl.binding == null /* compiler error */ - ? false : - !methDecl.binding.isStatic() && ((methDecl.binding.modifiers & (ExtraCompilerModifiers.AccImplementing | ExtraCompilerModifiers.AccOverriding)) != 0); - - // @see tags - int seeTagsLength = this.seeReferences == null ? 0 : this.seeReferences.length; - boolean superRef = false; - for (int i = 0; i < seeTagsLength; i++) { - - // Resolve reference - resolveReference(this.seeReferences[i], methScope); - - // see whether we can have a super reference - if (methDecl != null && !superRef) { - if (!methDecl.isConstructor()) { - if (overriding && this.seeReferences[i] instanceof JavadocMessageSend) { - JavadocMessageSend messageSend = (JavadocMessageSend) this.seeReferences[i]; - // if binding is valid then look if we have a reference to an overriden method/constructor - if (messageSend.binding != null && messageSend.binding.isValidBinding() && messageSend.actualReceiverType instanceof ReferenceBinding) { - ReferenceBinding methodReceiverType = (ReferenceBinding) messageSend.actualReceiverType; - TypeBinding superType = methDecl.binding.declaringClass.findSuperTypeOriginatingFrom(methodReceiverType); - if (superType != null && TypeBinding.notEquals(superType.original(), methDecl.binding.declaringClass) && CharOperation.equals(messageSend.selector, methDecl.selector)) { - if (methScope.environment().methodVerifier().doesMethodOverride(methDecl.binding, messageSend.binding.original())) { - superRef = true; - } - } - } - } - } else if (this.seeReferences[i] instanceof JavadocAllocationExpression) { - JavadocAllocationExpression allocationExpr = (JavadocAllocationExpression) this.seeReferences[i]; - // if binding is valid then look if we have a reference to an overriden method/constructor - if (allocationExpr.binding != null && allocationExpr.binding.isValidBinding()) { - ReferenceBinding allocType = (ReferenceBinding) allocationExpr.resolvedType.original(); - ReferenceBinding superType = (ReferenceBinding) methDecl.binding.declaringClass.findSuperTypeOriginatingFrom(allocType); - if (superType != null && TypeBinding.notEquals(superType.original(), methDecl.binding.declaringClass)) { - MethodBinding superConstructor = methScope.getConstructor(superType, methDecl.binding.parameters, allocationExpr); - if (superConstructor.isValidBinding() && superConstructor.original() == allocationExpr.binding.original()) { - MethodBinding current = methDecl.binding; - // work 'against' better inference in 1.8 (otherwise comparing (G with G) would fail): - if (methScope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_8 - && current.typeVariables != Binding.NO_TYPE_VARIABLES) - { - current = current.asRawMethod(methScope.environment()); - } - if (superConstructor.areParametersEqual(current)) { - superRef = true; - } - } - } - } - } - } - } - - // Look at @Override annotations - if (!superRef && methDecl != null && methDecl.annotations != null) { - int length = methDecl.annotations.length; - for (int i=0; i>> 32); - int end = (int) this.inheritedPositions[i]; - methScope.problemReporter().javadocUnexpectedTag(start, end); - } - } - - // @param tags - CompilerOptions compilerOptions = methScope.compilerOptions(); - resolveParamTags(methScope, reportMissing, compilerOptions.reportUnusedParameterIncludeDocCommentReference /* considerParamRefAsUsage*/); - resolveTypeParameterTags(methScope, reportMissing && compilerOptions.reportMissingJavadocTagsMethodTypeParameters); - - // @return tags - if (this.returnStatement == null) { - if (reportMissing && methDecl != null) { - if (methDecl.isMethod()) { - MethodDeclaration meth = (MethodDeclaration) methDecl; - if (meth.binding.returnType != TypeBinding.VOID) { - // method with return should have @return tag - methScope.problemReporter().javadocMissingReturnTag(meth.returnType.sourceStart, meth.returnType.sourceEnd, methDecl.binding.modifiers); - } - } - } - } else { - this.returnStatement.resolve(methScope); - } - - // @throws/@exception tags - resolveThrowsTags(methScope, reportMissing); - - // @value tag - boolean source15 = compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5; - if (!source15 && methDecl != null && this.valuePositions != -1) { - methScope.problemReporter().javadocUnexpectedTag((int)(this.valuePositions>>>32), (int) this.valuePositions); - } - - // Resolve param tags with invalid syntax - int length = this.invalidParameters == null ? 0 : this.invalidParameters.length; - for (int i = 0; i < length; i++) { - this.invalidParameters[i].resolve(methScope, false, false); - } - } - - private void resolveReference(Expression reference, Scope scope) { - - // Perform resolve - int problemCount = scope.referenceContext().compilationResult().problemCount; - switch (scope.kind) { - case Scope.METHOD_SCOPE: - reference.resolveType((MethodScope)scope); - break; - case Scope.CLASS_SCOPE: - reference.resolveType((ClassScope)scope); - break; - } - boolean hasProblems = scope.referenceContext().compilationResult().problemCount > problemCount; - - // Verify field references - boolean source15 = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; - int scopeModifiers = -1; - if (reference instanceof JavadocFieldReference) { - JavadocFieldReference fieldRef = (JavadocFieldReference) reference; - - // Verify if this is a method reference - // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=51911 - if (fieldRef.methodBinding != null) { - // cannot refer to method for @value tag - if (fieldRef.tagValue == JavadocTagConstants.TAG_VALUE_VALUE) { - if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers(); - scope.problemReporter().javadocInvalidValueReference(fieldRef.sourceStart, fieldRef.sourceEnd, scopeModifiers); - } - else if (fieldRef.actualReceiverType != null) { - if (scope.kind != Scope.MODULE_SCOPE && scope.enclosingSourceType().isCompatibleWith(fieldRef.actualReceiverType)) { - fieldRef.bits |= ASTNode.SuperAccess; - } - ReferenceBinding resolvedType = (ReferenceBinding) fieldRef.actualReceiverType; - if (CharOperation.equals(resolvedType.sourceName(), fieldRef.token)) { - fieldRef.methodBinding = scope.getConstructor(resolvedType, Binding.NO_TYPES, fieldRef); - } else { - fieldRef.methodBinding = scope.findMethod(resolvedType, fieldRef.token, Binding.NO_TYPES, fieldRef, false); - } - } - } - - // Verify whether field ref should be static or not (for @value tags) - else if (source15 && fieldRef.binding != null && fieldRef.binding.isValidBinding()) { - if (fieldRef.tagValue == JavadocTagConstants.TAG_VALUE_VALUE && !fieldRef.binding.isStatic()) { - if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers(); - scope.problemReporter().javadocInvalidValueReference(fieldRef.sourceStart, fieldRef.sourceEnd, scopeModifiers); - } - } - - // Verify type references - if (!hasProblems && fieldRef.binding != null && fieldRef.binding.isValidBinding() && fieldRef.actualReceiverType instanceof ReferenceBinding) { - ReferenceBinding resolvedType = (ReferenceBinding) fieldRef.actualReceiverType; - verifyTypeReference(fieldRef, fieldRef.receiver, scope, source15, resolvedType, fieldRef.binding.modifiers); - } - - // That's it for field references - return; - } - - // Verify type references - if (!hasProblems && (reference instanceof JavadocSingleTypeReference || reference instanceof JavadocQualifiedTypeReference) && reference.resolvedType instanceof ReferenceBinding) { - ReferenceBinding resolvedType = (ReferenceBinding) reference.resolvedType; - verifyTypeReference(reference, reference, scope, source15, resolvedType, resolvedType.modifiers); - } - - if (!hasProblems && (reference instanceof JavadocModuleReference)) { - JavadocModuleReference ref= (JavadocModuleReference)reference; - ref.resolve(scope); - ModuleReference mRef = ref.getModuleReference(); - if (mRef != null) { - ModuleBinding mType = mRef.resolve(scope); - if (mType != null && verifyModuleReference(reference, reference, scope, source15, mType, mType.modifiers)) { - TypeReference tRef= ref.getTypeReference(); - if ((tRef instanceof JavadocSingleTypeReference || tRef instanceof JavadocQualifiedTypeReference) && tRef.resolvedType instanceof ReferenceBinding) { - ReferenceBinding resolvedType = (ReferenceBinding) tRef.resolvedType; - verifyTypeReference(reference, reference, scope, source15, resolvedType, resolvedType.modifiers); - } - } - } - } - - // Verify that message reference are not used for @value tags - if (reference instanceof JavadocMessageSend) { - JavadocMessageSend msgSend = (JavadocMessageSend) reference; - - // tag value - if (source15 && msgSend.tagValue == JavadocTagConstants.TAG_VALUE_VALUE) { // cannot refer to method for @value tag - if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers(); - scope.problemReporter().javadocInvalidValueReference(msgSend.sourceStart, msgSend.sourceEnd, scopeModifiers); - } - - // Verify type references - if (!hasProblems && msgSend.binding != null && msgSend.binding.isValidBinding() && msgSend.actualReceiverType instanceof ReferenceBinding) { - ReferenceBinding resolvedType = (ReferenceBinding) msgSend.actualReceiverType; - verifyTypeReference(msgSend, msgSend.receiver, scope, source15, resolvedType, msgSend.binding.modifiers); - } - } - - // Verify that constructor reference are not used for @value tags - else if (reference instanceof JavadocAllocationExpression) { - JavadocAllocationExpression alloc = (JavadocAllocationExpression) reference; - - // tag value - if (source15 && alloc.tagValue == JavadocTagConstants.TAG_VALUE_VALUE) { // cannot refer to method for @value tag - if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers(); - scope.problemReporter().javadocInvalidValueReference(alloc.sourceStart, alloc.sourceEnd, scopeModifiers); - } - - // Verify type references - if (!hasProblems && alloc.binding != null && alloc.binding.isValidBinding() && alloc.resolvedType instanceof ReferenceBinding) { - ReferenceBinding resolvedType = (ReferenceBinding) alloc.resolvedType; - verifyTypeReference(alloc, alloc.type, scope, source15, resolvedType, alloc.binding.modifiers); - } - } - - // Verify that there's no type variable reference - // (javadoc does not accept them and this is not a referenced bug or requested enhancement) - else if (reference instanceof JavadocSingleTypeReference && reference.resolvedType != null && reference.resolvedType.isTypeVariable()) { - scope.problemReporter().javadocInvalidReference(reference.sourceStart, reference.sourceEnd); - } - } - - /* - * Resolve @param tags while method scope - */ - private void resolveParamTags(MethodScope scope, boolean reportMissing, boolean considerParamRefAsUsage) { - AbstractMethodDeclaration methodDecl = scope.referenceMethod(); - int paramTagsSize = this.paramReferences == null ? 0 : this.paramReferences.length; - - // If no referenced method (field initializer for example) then report a problem for each param tag - if (methodDecl == null) { - for (int i = 0; i < paramTagsSize; i++) { - JavadocSingleNameReference param = this.paramReferences[i]; - scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd); - } - return; - } - - // If no param tags then report a problem for each method argument - int argumentsSize = methodDecl.arguments == null ? 0 : methodDecl.arguments.length; - if (paramTagsSize == 0) { - if (reportMissing) { - for (int i = 0; i < argumentsSize; i++) { - Argument arg = methodDecl.arguments[i]; - scope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, methodDecl.binding.modifiers); - } - } - } else { - LocalVariableBinding[] bindings = new LocalVariableBinding[paramTagsSize]; - int maxBindings = 0; - - // Scan all @param tags - for (int i = 0; i < paramTagsSize; i++) { - JavadocSingleNameReference param = this.paramReferences[i]; - param.resolve(scope, true, considerParamRefAsUsage); - if (param.binding != null && param.binding.isValidBinding()) { - // Verify duplicated tags - boolean found = false; - for (int j = 0; j < maxBindings && !found; j++) { - if (bindings[j] == param.binding) { - scope.problemReporter().javadocDuplicatedParamTag(param.token, param.sourceStart, param.sourceEnd, methodDecl.binding.modifiers); - found = true; - } - } - if (!found) { - bindings[maxBindings++] = (LocalVariableBinding) param.binding; - } - } - } - - // Look for undocumented arguments - if (reportMissing) { - for (int i = 0; i < argumentsSize; i++) { - Argument arg = methodDecl.arguments[i]; - boolean found = false; - for (int j = 0; j < maxBindings; j++) { - LocalVariableBinding binding = bindings[j]; - if (arg.binding == binding) { - found = true; - break; - } - } - if (!found) { - scope.problemReporter().javadocMissingParamTag(arg.name, arg.sourceStart, arg.sourceEnd, methodDecl.binding.modifiers); - } - } - } - } - } - - /* - * Resolve @uses tags while block scope - */ - private void resolveUsesTags(BlockScope scope, boolean reportMissing) { - ModuleDeclaration moduleDecl = (ModuleDeclaration)scope.referenceContext(); - int usesTagsSize = this.usesReferences == null ? 0 : this.usesReferences.length; - - // If no referenced module then report a problem for each uses tag - if (moduleDecl == null) { - for (int i = 0; i < usesTagsSize; i++) { - IJavadocTypeReference uses = this.usesReferences[i]; - scope.problemReporter().javadocUnexpectedTag(uses.getTagSourceStart(), uses.getTagSourceEnd()); - } - return; - } - - // If no uses tags then report a problem for each uses reference - int usesSize = moduleDecl.usesCount; - if (usesTagsSize == 0) { - if (reportMissing) { - for (int i = 0; i < usesSize; i++) { - UsesStatement uses = moduleDecl.uses[i]; - scope.problemReporter().javadocMissingUsesTag(uses.serviceInterface, uses.sourceStart, uses.sourceEnd, moduleDecl.binding.modifiers); - } - } - } else { - TypeBinding[] bindings = new TypeBinding[usesTagsSize]; - int maxBindings = 0; - - // Scan all @uses tags - for (int i = 0; i < usesTagsSize; i++) { - TypeReference usesRef = (TypeReference)this.usesReferences[i]; - try { - usesRef.resolve(scope); - if (usesRef.resolvedType != null && usesRef.resolvedType.isValidBinding()) { - // Verify duplicated tags - boolean found = false; - for (int j = 0; j < maxBindings && !found; j++) { - if (bindings[j].equals(usesRef.resolvedType)) { - scope.problemReporter().javadocDuplicatedUsesTag(usesRef.sourceStart, usesRef.sourceEnd); - found = true; - } - } - if (!found) { - bindings[maxBindings++] = usesRef.resolvedType; - } - } - } catch (Exception e) { - scope.problemReporter().javadocInvalidUsesClass(usesRef.sourceStart, usesRef.sourceEnd); - } - } - - // Look for undocumented uses - if (reportMissing) { - for (int i = 0; i < usesSize; i++) { - UsesStatement uses = moduleDecl.uses[i]; - boolean found = false; - for (int j = 0; j < maxBindings && !found; j++) { - TypeBinding binding = bindings[j]; - if (uses.serviceInterface.getTypeBinding(scope).equals(binding)) { - found = true; - } - } - if (!found) { - scope.problemReporter().javadocMissingUsesTag(uses.serviceInterface, uses.sourceStart, uses.sourceEnd, moduleDecl.binding.modifiers); - } - } - } - } - } - - /* - * Resolve @provides tags while block scope - */ - private void resolveProvidesTags(BlockScope scope, boolean reportMissing) { - ModuleDeclaration moduleDecl = (ModuleDeclaration)scope.referenceContext(); - int providesTagsSize = this.providesReferences == null ? 0 : this.providesReferences.length; - - // If no referenced module then report a problem for each uses tag - if (moduleDecl == null) { - for (int i = 0; i < providesTagsSize; i++) { - IJavadocTypeReference provides = this.providesReferences[i]; - scope.problemReporter().javadocUnexpectedTag(provides.getTagSourceStart(), provides.getTagSourceEnd()); - } - return; - } - - // If no uses tags then report a problem for each uses reference - int providesSize = moduleDecl.servicesCount; - if (providesTagsSize == 0) { - if (reportMissing) { - for (int i = 0; i < providesSize; i++) { - ProvidesStatement provides = moduleDecl.services[i]; - scope.problemReporter().javadocMissingProvidesTag(provides.serviceInterface, provides.sourceStart, provides.sourceEnd, moduleDecl.binding.modifiers); - } - } - } else { - TypeBinding[] bindings = new TypeBinding[providesTagsSize]; - int maxBindings = 0; - - // Scan all @provides tags - for (int i = 0; i < providesTagsSize; i++) { - TypeReference providesRef = (TypeReference)this.providesReferences[i]; - try { - providesRef.resolve(scope); - if (providesRef.resolvedType != null && providesRef.resolvedType.isValidBinding()) { - // Verify duplicated tags - boolean found = false; - for (int j = 0; j < maxBindings && !found; j++) { - if (bindings[j].equals(providesRef.resolvedType)) { - scope.problemReporter().javadocDuplicatedProvidesTag(providesRef.sourceStart, providesRef.sourceEnd); - found = true; - } - } - if (!found) { - bindings[maxBindings++] = providesRef.resolvedType; - } - } - } catch (Exception e) { - scope.problemReporter().javadocInvalidProvidesClass(providesRef.sourceStart, providesRef.sourceEnd); - } - } - - // Look for undocumented uses - if (reportMissing) { - for (int i = 0; i < providesSize; i++) { - ProvidesStatement provides = moduleDecl.services[i]; - boolean found = false; - for (int j = 0; j < maxBindings && !found; j++) { - TypeBinding binding = bindings[j]; - if (provides.serviceInterface.getTypeBinding(scope).equals(binding)) { - found = true; - } - } - if (!found) { - scope.problemReporter().javadocMissingProvidesTag(provides.serviceInterface, provides.sourceStart, provides.sourceEnd, moduleDecl.binding.modifiers); - } - } - } - } - } - - /* - * Resolve @param tags for type parameters - */ - private void resolveTypeParameterTags(Scope scope, boolean reportMissing) { - int paramTypeParamLength = this.paramTypeParameters == null ? 0 : this.paramTypeParameters.length; - int paramReferencesLength = this.paramReferences == null ? 0 : this.paramReferences.length; - - // Get declaration infos - TypeParameter[] parameters = null; - TypeVariableBinding[] typeVariables = null; - RecordComponent[] recordParameters = null; - int modifiers = -1; - switch (scope.kind) { - case Scope.METHOD_SCOPE: - AbstractMethodDeclaration methodDeclaration = ((MethodScope)scope).referenceMethod(); - // If no referenced method (field initializer for example) then report a problem for each param tag - if (methodDeclaration == null) { - for (int i = 0; i < paramTypeParamLength; i++) { - JavadocSingleTypeReference param = this.paramTypeParameters[i]; - scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd); - } - return; - } - parameters = methodDeclaration.typeParameters(); - typeVariables = methodDeclaration.binding.typeVariables; - modifiers = methodDeclaration.binding.modifiers; - break; - case Scope.CLASS_SCOPE: - TypeDeclaration typeDeclaration = ((ClassScope) scope).referenceContext; - parameters = typeDeclaration.typeParameters; - typeVariables = typeDeclaration.binding.typeVariables; - modifiers = typeDeclaration.binding.modifiers; - recordParameters = typeDeclaration.recordComponents; - break; - } - - // If no type variables then report a problem for each param type parameter tag - if ((recordParameters == null || recordParameters.length == 0) - && (typeVariables == null || typeVariables.length == 0)) { - for (int i = 0; i < paramTypeParamLength; i++) { - JavadocSingleTypeReference param = this.paramTypeParameters[i]; - scope.problemReporter().javadocUnexpectedTag(param.tagSourceStart, param.tagSourceEnd); - } - return; - } - - // If no param tags then report a problem for each record parameter - if (recordParameters != null) { - reportMissing = reportMissing && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; - int recordParametersLength = recordParameters.length; - String argNames[] = new String[paramReferencesLength]; - if (paramReferencesLength == 0) { - if (reportMissing) { - for (int i = 0, l=recordParametersLength; i= ClassFileConstants.JDK1_5; - int typeParametersLength = parameters.length; - if (paramTypeParamLength == 0) { - if (reportMissing) { - for (int i = 0, l=typeParametersLength; i= 0;) { - computedCompoundName[--idx] = topLevelType.fPackage.compoundName[i]; - } - - if (scope.kind != Scope.MODULE_SCOPE) { - ClassScope topLevelScope = scope.classScope(); - // when scope is not on compilation unit type, then inner class may not be visible... - if (topLevelScope.parent.kind != Scope.COMPILATION_UNIT_SCOPE || - !CharOperation.equals(topLevelType.sourceName, topLevelScope.referenceContext.name)) { - topLevelScope = topLevelScope.outerMostClassScope(); - if (typeReference instanceof JavadocSingleTypeReference) { - // inner class single reference can only be done in same unit - if ((!source15 && depth == 1) || TypeBinding.notEquals(topLevelType, topLevelScope.referenceContext.binding)) { - // search for corresponding import - boolean hasValidImport = false; - if (source15) { - CompilationUnitScope unitScope = topLevelScope.compilationUnitScope(); - ImportBinding[] imports = unitScope.imports; - int length = imports == null ? 0 : imports.length; - mainLoop: for (int i=0; i= 0;) { - if (CharOperation.equals(imports[i].compoundName[j], computedCompoundName[j])) { - if (j == 0) { - hasValidImport = true; - ImportReference importReference = imports[i].reference; - if (importReference != null) { - importReference.bits |= ASTNode.Used; - } - break mainLoop; - } - } else { - break; - } - } - } - } - if (!hasValidImport) { - if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers(); - scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers); - } - } else { - if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers(); - scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers); - return; - } - } - } - } - if (typeReference instanceof JavadocQualifiedTypeReference && !scope.isDefinedInSameUnit(resolvedType)) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=222188 - // partially qualified references from a different CU should be warned - char[][] typeRefName = ((JavadocQualifiedTypeReference) typeReference).getTypeName(); - int skipLength = 0; - if (topLevelScope.getCurrentPackage() == resolvedType.getPackage() - && typeRefName.length < computedCompoundName.length) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=221539: references can be partially qualified - // in same package and hence if the package name is not given, ignore package name check - skipLength = resolvedType.fPackage.compoundName.length; - } - boolean valid = true; - if (typeRefName.length == computedCompoundName.length - skipLength) { - checkQualification: for (int i = 0; i < typeRefName.length; i++) { - if (!CharOperation.equals(typeRefName[i], computedCompoundName[i + skipLength])) { - valid = false; - break checkQualification; - } - } - } else { - valid = false; - } - // report invalid reference - if (!valid) { - if (scopeModifiers == -1) scopeModifiers = scope.getDeclarationModifiers(); - scope.problemReporter().javadocInvalidMemberTypeQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers); - return; - } - } - } - } - /* - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=286918 - * - * We are concerned only about the Single type references (i.e. without any package) If they are not in default package, - * then report an error. References with qualified yet incorrect names would have already been taken care of. - */ - if (scope.referenceCompilationUnit().isPackageInfo() && typeReference instanceof JavadocSingleTypeReference) { - if (resolvedType.fPackage.compoundName.length > 0) { - scope.problemReporter().javadocInvalidReference(typeReference.sourceStart, typeReference.sourceEnd); - return; // Not really needed - just in case more code added in future - } - } - } - } - - private boolean verifyModuleReference(Expression reference, Expression typeReference, Scope scope, boolean source15, ModuleBinding moduleType, int modifiers) { - boolean bindingFound = false; - if (moduleType!= null && moduleType.isValidBinding()) { - int scopeModifiers = -1; - - ModuleBinding mBinding = scope.module(); - - if (mBinding == null) { - scope.problemReporter().javadocInvalidModuleQualification(typeReference.sourceStart, typeReference.sourceEnd, scopeModifiers); - return bindingFound; - } - - if (mBinding.equals(moduleType)) { - bindingFound = true; - } else { - ModuleBinding[] bindings = mBinding.getAllRequiredModules(); - for (ModuleBinding binding : bindings) { - if (moduleType.equals(binding)) { - bindingFound = true; - break; - } - } - } - - if (!bindingFound) { - if (!canBeSeen(scope.compilerOptions().reportInvalidJavadocTagsVisibility, moduleType.modifiers)) { - scope.problemReporter().javadocHiddenReference(typeReference.sourceStart, typeReference.sourceEnd, scope, moduleType.modifiers); - return bindingFound; - } - } - } - return bindingFound; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.paramReferences != null) { - for (int i = 0, length = this.paramReferences.length; i < length; i++) { - this.paramReferences[i].traverse(visitor, scope); - } - } - if (this.paramTypeParameters != null) { - for (int i = 0, length = this.paramTypeParameters.length; i < length; i++) { - this.paramTypeParameters[i].traverse(visitor, scope); - } - } - if (this.returnStatement != null) { - this.returnStatement.traverse(visitor, scope); - } - if (this.exceptionReferences != null) { - for (int i = 0, length = this.exceptionReferences.length; i < length; i++) { - this.exceptionReferences[i].traverse(visitor, scope); - } - } - if (this.seeReferences != null) { - for (int i = 0, length = this.seeReferences.length; i < length; i++) { - this.seeReferences[i].traverse(visitor, scope); - } - } - } - visitor.endVisit(this, scope); - } - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.paramReferences != null) { - for (int i = 0, length = this.paramReferences.length; i < length; i++) { - this.paramReferences[i].traverse(visitor, scope); - } - } - if (this.paramTypeParameters != null) { - for (int i = 0, length = this.paramTypeParameters.length; i < length; i++) { - this.paramTypeParameters[i].traverse(visitor, scope); - } - } - if (this.returnStatement != null) { - this.returnStatement.traverse(visitor, scope); - } - if (this.exceptionReferences != null) { - for (int i = 0, length = this.exceptionReferences.length; i < length; i++) { - this.exceptionReferences[i].traverse(visitor, scope); - } - } - if (this.seeReferences != null) { - for (int i = 0, length = this.seeReferences.length; i < length; i++) { - this.seeReferences[i].traverse(visitor, scope); - } - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java deleted file mode 100644 index d0c1c6d..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocAllocationExpression.java +++ /dev/null @@ -1,203 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class JavadocAllocationExpression extends AllocationExpression { - - public int tagSourceStart, tagSourceEnd; - public int tagValue, memberStart; - public char[][] qualification; - - public JavadocAllocationExpression(int start, int end) { - this.sourceStart = start; - this.sourceEnd = end; - this.bits |= InsideJavadoc; - } - public JavadocAllocationExpression(long pos) { - this((int) (pos >>> 32), (int) pos); - } - - TypeBinding internalResolveType(Scope scope) { - - // Propagate the type checking to the arguments, and check if the constructor is defined. - this.constant = Constant.NotAConstant; - if (this.type == null) { - this.resolvedType = scope.enclosingSourceType(); - } else if (scope.kind == Scope.CLASS_SCOPE) { - this.resolvedType = this.type.resolveType((ClassScope)scope); - } else { - this.resolvedType = this.type.resolveType((BlockScope)scope, true /* check bounds*/); - } - - // buffering the arguments' types - this.argumentTypes = Binding.NO_PARAMETERS; - boolean hasTypeVarArgs = false; - if (this.arguments != null) { - this.argumentsHaveErrors = false; - int length = this.arguments.length; - this.argumentTypes = new TypeBinding[length]; - for (int i = 0; i < length; i++) { - Expression argument = this.arguments[i]; - if (scope.kind == Scope.CLASS_SCOPE) { - this.argumentTypes[i] = argument.resolveType((ClassScope)scope); - } else { - this.argumentTypes[i] = argument.resolveType((BlockScope)scope); - } - if (this.argumentTypes[i] == null) { - this.argumentsHaveErrors = true; - } else if (!hasTypeVarArgs) { - hasTypeVarArgs = this.argumentTypes[i].isTypeVariable(); - } - } - if (this.argumentsHaveErrors) { - return null; - } - } - - // check resolved type - if (this.resolvedType == null) { - return null; - } - this.resolvedType = scope.environment().convertToRawType(this.type.resolvedType, true /*force the conversion of enclosing types*/); - SourceTypeBinding enclosingType = scope.enclosingSourceType(); - if (enclosingType == null ? false : enclosingType.isCompatibleWith(this.resolvedType)) { - this.bits |= ASTNode.SuperAccess; - } - - ReferenceBinding allocationType = (ReferenceBinding) this.resolvedType; - this.binding = scope.getConstructor(allocationType, this.argumentTypes, this); - if (!this.binding.isValidBinding()) { - ReferenceBinding enclosingTypeBinding = allocationType; - MethodBinding contructorBinding = this.binding; - while (!contructorBinding.isValidBinding() && (enclosingTypeBinding.isMemberType() || enclosingTypeBinding.isLocalType())) { - enclosingTypeBinding = enclosingTypeBinding.enclosingType(); - contructorBinding = scope.getConstructor(enclosingTypeBinding, this.argumentTypes, this); - } - if (contructorBinding.isValidBinding()) { - this.binding = contructorBinding; - } - } - if (!this.binding.isValidBinding()) { - // First try to search a method instead - MethodBinding methodBinding = scope.getMethod(this.resolvedType, this.resolvedType.sourceName(), this.argumentTypes, this); - if (methodBinding.isValidBinding()) { - this.binding = methodBinding; - } else { - if (this.binding.declaringClass == null) { - this.binding.declaringClass = allocationType; - } - scope.problemReporter().javadocInvalidConstructor(this, this.binding, scope.getDeclarationModifiers()); - } - return this.resolvedType; - } else if (this.binding.isVarargs()) { - int length = this.argumentTypes.length; - if (!(this.binding.parameters.length == length && this.argumentTypes[length-1].isArrayType())) { - MethodBinding problem = new ProblemMethodBinding(this.binding, this.binding.selector, this.argumentTypes, ProblemReasons.NotFound); - scope.problemReporter().javadocInvalidConstructor(this, problem, scope.getDeclarationModifiers()); - } - } else if (hasTypeVarArgs) { - MethodBinding problem = new ProblemMethodBinding(this.binding, this.binding.selector, this.argumentTypes, ProblemReasons.NotFound); - scope.problemReporter().javadocInvalidConstructor(this, problem, scope.getDeclarationModifiers()); - } else if (this.binding instanceof ParameterizedMethodBinding) { - ParameterizedMethodBinding paramMethodBinding = (ParameterizedMethodBinding) this.binding; - if (paramMethodBinding.hasSubstitutedParameters()) { - int length = this.argumentTypes.length; - for (int i=0; i 1) { // accept qualified member class constructor reference => see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=103304 - ReferenceBinding enclosingTypeBinding = allocationType; - if (this.type instanceof JavadocQualifiedTypeReference && ((JavadocQualifiedTypeReference)this.type).tokens.length != length) { - scope.problemReporter().javadocInvalidMemberTypeQualification(this.memberStart+1, this.sourceEnd, scope.getDeclarationModifiers()); - } else { - int idx = length; - while (idx > 0 && CharOperation.equals(this.qualification[--idx], enclosingTypeBinding.sourceName) && (enclosingTypeBinding = enclosingTypeBinding.enclosingType()) != null) { - // verify that each qualification token matches enclosing types - } - if (idx > 0 || enclosingTypeBinding != null) { - scope.problemReporter().javadocInvalidMemberTypeQualification(this.memberStart+1, this.sourceEnd, scope.getDeclarationModifiers()); - } - } - } - } - if (isMethodUseDeprecated(this.binding, scope, true, this)) { - scope.problemReporter().javadocDeprecatedMethod(this.binding, this, scope.getDeclarationModifiers()); - } - return allocationType; - } - - @Override - public boolean isSuperAccess() { - return (this.bits & ASTNode.SuperAccess) != 0; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - return internalResolveType(scope); - } - - @Override - public TypeBinding resolveType(ClassScope scope) { - return internalResolveType(scope); - } - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.typeArguments != null) { - for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) { - this.typeArguments[i].traverse(visitor, scope); - } - } - if (this.type != null) { // enum constant scenario - this.type.traverse(visitor, scope); - } - if (this.arguments != null) { - for (int i = 0, argumentsLength = this.arguments.length; i < argumentsLength; i++) - this.arguments[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.typeArguments != null) { - for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) { - this.typeArguments[i].traverse(visitor, scope); - } - } - if (this.type != null) { // enum constant scenario - this.type.traverse(visitor, scope); - } - if (this.arguments != null) { - for (int i = 0, argumentsLength = this.arguments.length; i < argumentsLength; i++) - this.arguments[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java deleted file mode 100644 index de95a42..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocArgumentExpression.java +++ /dev/null @@ -1,136 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class JavadocArgumentExpression extends Expression { - public char[] token; - public Argument argument; - - public JavadocArgumentExpression(char[] name, int startPos, int endPos, TypeReference typeRef) { - this.token = name; - this.sourceStart = startPos; - this.sourceEnd = endPos; - long pos = (((long) startPos) << 32) + endPos; - this.argument = new Argument(name, pos, typeRef, ClassFileConstants.AccDefault); - this.bits |= InsideJavadoc; - } - - /* - * Resolves type on a Block or Class scope. - */ - private TypeBinding internalResolveType(Scope scope) { - this.constant = Constant.NotAConstant; - if (this.resolvedType != null) // is a shared type reference which was already resolved - return this.resolvedType.isValidBinding() ? this.resolvedType : null; // already reported error - - if (this.argument != null) { - TypeReference typeRef = this.argument.type; - if (typeRef != null) { - this.resolvedType = typeRef.getTypeBinding(scope); - typeRef.resolvedType = this.resolvedType; - // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=195374 - // reproduce javadoc 1.3.1 / 1.4.2 behavior - if (this.resolvedType == null) { - return null; - } - if (typeRef instanceof SingleTypeReference && - this.resolvedType.leafComponentType().enclosingType() != null && - scope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_4) { - scope.problemReporter().javadocInvalidMemberTypeQualification(this.sourceStart, this.sourceEnd, scope.getDeclarationModifiers()); - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=228648 - // do not return now but report unresolved reference as expected depending on compliance settings - } else if (typeRef instanceof QualifiedTypeReference) { - TypeBinding enclosingType = this.resolvedType.leafComponentType().enclosingType(); - if (enclosingType != null) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=233187 - // inner type references should be fully qualified - int compoundLength = 2; - while ((enclosingType = enclosingType.enclosingType()) != null) compoundLength++; - int typeNameLength = typeRef.getTypeName().length; - if (typeNameLength != compoundLength && typeNameLength != (compoundLength+this.resolvedType.getPackage().compoundName.length)) { - scope.problemReporter().javadocInvalidMemberTypeQualification(typeRef.sourceStart, typeRef.sourceEnd, scope.getDeclarationModifiers()); - } - } - } - if (!this.resolvedType.isValidBinding()) { - scope.problemReporter().javadocInvalidType(typeRef, this.resolvedType, scope.getDeclarationModifiers()); - return null; - } - if (isTypeUseDeprecated(this.resolvedType, scope)) { - scope.problemReporter().javadocDeprecatedType(this.resolvedType, typeRef, scope.getDeclarationModifiers()); - } - return this.resolvedType = scope.environment().convertToRawType(this.resolvedType, true /*force the conversion of enclosing types*/); - } - } - return null; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - if (this.argument == null) { - if (this.token != null) { - output.append(this.token); - } - } - else { - this.argument.print(indent, output); - } - return output; - } - - @Override - public void resolve(BlockScope scope) { - if (this.argument != null) { - this.argument.resolve(scope); - } - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - return internalResolveType(scope); - } - - @Override - public TypeBinding resolveType(ClassScope scope) { - return internalResolveType(scope); - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) { - if (this.argument != null) { - this.argument.traverse(visitor, blockScope); - } - } - visitor.endVisit(this, blockScope); - } - @Override - public void traverse(ASTVisitor visitor, ClassScope blockScope) { - if (visitor.visit(this, blockScope)) { - if (this.argument != null) { - this.argument.traverse(visitor, blockScope); - } - } - visitor.endVisit(this, blockScope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocArrayQualifiedTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocArrayQualifiedTypeReference.java deleted file mode 100644 index e4400ae..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocArrayQualifiedTypeReference.java +++ /dev/null @@ -1,56 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - - - -public class JavadocArrayQualifiedTypeReference extends ArrayQualifiedTypeReference { - - public int tagSourceStart, tagSourceEnd; - - public JavadocArrayQualifiedTypeReference(JavadocQualifiedTypeReference typeRef, int dim) { - super(typeRef.tokens, dim, typeRef.sourcePositions); - } - - @Override - protected void reportInvalidType(Scope scope) { - scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); - } - @Override - protected void reportDeprecatedType(TypeBinding type, Scope scope) { - scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers()); - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocArraySingleTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocArraySingleTypeReference.java deleted file mode 100644 index 9892955..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocArraySingleTypeReference.java +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2007 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - - -public class JavadocArraySingleTypeReference extends ArrayTypeReference { - - public JavadocArraySingleTypeReference(char[] name, int dim, long pos) { - super(name, dim, pos); - this.bits |= InsideJavadoc; - } - - @Override - protected void reportInvalidType(Scope scope) { - scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); - } - @Override - protected void reportDeprecatedType(TypeBinding type, Scope scope) { - scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers()); - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java deleted file mode 100644 index 962f0bf..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocFieldReference.java +++ /dev/null @@ -1,166 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for bug 185682 - Increment/decrement operators mark local variables as read - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class JavadocFieldReference extends FieldReference { - - public int tagSourceStart, tagSourceEnd; - public int tagValue; - public MethodBinding methodBinding; - - public JavadocFieldReference(char[] source, long pos) { - super(source, pos); - this.bits |= InsideJavadoc; - } - - /* - public Binding getBinding() { - if (this.methodBinding != null) { - return this.methodBinding; - } - return this.binding; - } - */ - - /* - * Resolves type on a Block or Class scope. - */ - protected TypeBinding internalResolveType(Scope scope) { - - this.constant = Constant.NotAConstant; - if (this.receiver == null) { - this.actualReceiverType = scope.enclosingReceiverType(); - } else if (scope.kind == Scope.CLASS_SCOPE) { - this.actualReceiverType = this.receiver.resolveType((ClassScope) scope); - } else { - this.actualReceiverType = this.receiver.resolveType((BlockScope)scope); - } - if (this.actualReceiverType == null) { - return null; - } - - Binding fieldBinding = (this.receiver != null && this.receiver.isThis()) - ? scope.classScope().getBinding(this.token, this.bits & RestrictiveFlagMASK, this, true /*resolve*/) - : scope.getField(this.actualReceiverType, this.token, this); - if (!fieldBinding.isValidBinding()) { - // implicit lookup may discover issues due to static/constructor contexts. javadoc must be resilient - switch (fieldBinding.problemId()) { - case ProblemReasons.NonStaticReferenceInConstructorInvocation: - case ProblemReasons.NonStaticReferenceInStaticContext: - case ProblemReasons.InheritedNameHidesEnclosingName : - FieldBinding closestMatch = ((ProblemFieldBinding)fieldBinding).closestMatch; - if (closestMatch != null) { - fieldBinding = closestMatch; // ignore problem if can reach target field through it - } - } - } - // When there's no valid field binding, try to resolve possible method reference without parenthesis - if (!fieldBinding.isValidBinding() || !(fieldBinding instanceof FieldBinding)) { - if (this.receiver.resolvedType instanceof ProblemReferenceBinding) { - // problem already got signaled on receiver, do not report secondary problem - return null; - } - if (this.actualReceiverType instanceof ReferenceBinding) { - ReferenceBinding refBinding = (ReferenceBinding) this.actualReceiverType; - char[] selector = this.token; - MethodBinding possibleMethod = null; - if (CharOperation.equals(this.actualReceiverType.sourceName(), selector)) { - possibleMethod = scope.getConstructor(refBinding, Binding.NO_TYPES, this); - } else { - possibleMethod = this.receiver.isThis() - ? scope.getImplicitMethod(selector, Binding.NO_TYPES, this) - : scope.getMethod(refBinding, selector, Binding.NO_TYPES, this); - } - if (possibleMethod.isValidBinding()) { - this.methodBinding = possibleMethod; - } else { - ProblemMethodBinding problemMethodBinding = (ProblemMethodBinding) possibleMethod; - if (problemMethodBinding.closestMatch == null) { - if (fieldBinding.isValidBinding()) { - // When the binding is not on a field (e.g. local variable), we need to create a problem field binding to report the correct problem - // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=254825 - fieldBinding = new ProblemFieldBinding(refBinding, fieldBinding.readableName(), ProblemReasons.NotFound); - } - scope.problemReporter().javadocInvalidField(this, fieldBinding, this.actualReceiverType, scope.getDeclarationModifiers()); - } else { - this.methodBinding = problemMethodBinding.closestMatch; - } - } - } - return null; - } - this.binding = (FieldBinding) fieldBinding; - - if (isFieldUseDeprecated(this.binding, scope, this.bits)) { - scope.problemReporter().javadocDeprecatedField(this.binding, this, scope.getDeclarationModifiers()); - } - return this.resolvedType = this.binding.type; - } - - @Override - public boolean isSuperAccess() { - return (this.bits & ASTNode.SuperAccess) != 0; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - - if (this.receiver != null) { - this.receiver.printExpression(0, output); - } - output.append('#').append(this.token); - return output; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - return internalResolveType(scope); - } - - @Override - public TypeBinding resolveType(ClassScope scope) { - return internalResolveType(scope); - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - - if (visitor.visit(this, scope)) { - if (this.receiver != null) { - this.receiver.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - - if (visitor.visit(this, scope)) { - if (this.receiver != null) { - this.receiver.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java deleted file mode 100644 index 384916a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocImplicitTypeReference.java +++ /dev/null @@ -1,145 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class JavadocImplicitTypeReference extends TypeReference { - - public char[] token; - - public JavadocImplicitTypeReference(char[] name, int pos) { - super(); - this.token = name; - this.sourceStart = pos; - this.sourceEnd = pos; - } - - @Override - public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { - return null; - } - - @Override - protected TypeBinding getTypeBinding(Scope scope) { - this.constant = Constant.NotAConstant; - return this.resolvedType = scope.enclosingReceiverType(); - } - - @Override - public char[] getLastToken() { - return this.token; - } - - @Override - public char[][] getTypeName() { - if (this.token != null) { - char[][] tokens = { this.token }; - return tokens; - } - return null; - } - @Override - public boolean isThis() { - return true; - } - - /* - * Resolves type on a Block, Class or CompilationUnit scope. - * We need to modify resoling behavior to avoid raw type creation. - */ - @Override - protected TypeBinding internalResolveType(Scope scope, int location) { - // handle the error here - this.constant = Constant.NotAConstant; - if (this.resolvedType != null) { // is a shared type reference which was already resolved - if (this.resolvedType.isValidBinding()) { - return this.resolvedType; - } else { - switch (this.resolvedType.problemId()) { - case ProblemReasons.NotFound : - case ProblemReasons.NotVisible : - TypeBinding type = this.resolvedType.closestMatch(); - return type; - default : - return null; - } - } - } - boolean hasError; - TypeBinding type = this.resolvedType = getTypeBinding(scope); - if (type == null) { - return null; // detected cycle while resolving hierarchy - } else if ((hasError = !type.isValidBinding())== true) { - reportInvalidType(scope); - switch (type.problemId()) { - case ProblemReasons.NotFound : - case ProblemReasons.NotVisible : - type = type.closestMatch(); - if (type == null) return null; - break; - default : - return null; - } - } - if (type.isArrayType() && ((ArrayBinding) type).leafComponentType == TypeBinding.VOID) { - scope.problemReporter().cannotAllocateVoidArray(this); - return null; - } - if (isTypeUseDeprecated(type, scope)) { - reportDeprecatedType(type, scope); - } - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=209936 - // raw convert all enclosing types when dealing with Javadoc references - if (type.isGenericType() || type.isParameterizedType()) { - type = scope.environment().convertToRawType(type, true /*force the conversion of enclosing types*/); - } - - if (hasError) { - // do not store the computed type, keep the problem type instead - return type; - } - return this.resolvedType = type; - } - - @Override - protected void reportInvalidType(Scope scope) { - scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); - } - @Override - protected void reportDeprecatedType(TypeBinding type, Scope scope) { - scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers()); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - return new StringBuilder(); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java deleted file mode 100644 index 71cd1be..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocMessageSend.java +++ /dev/null @@ -1,249 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - - -public class JavadocMessageSend extends MessageSend { - - public int tagSourceStart, tagSourceEnd; - public int tagValue; - - public JavadocMessageSend(char[] name, long pos) { - this.selector = name; - this.nameSourcePosition = pos; - this.sourceStart = (int) (this.nameSourcePosition >>> 32); - this.sourceEnd = (int) this.nameSourcePosition; - this.bits |= InsideJavadoc; - } - public JavadocMessageSend(char[] name, long pos, JavadocArgumentExpression[] arguments) { - this(name, pos); - this.arguments = arguments; - } - - /* - * Resolves type on a Block or Class scope. - */ - private TypeBinding internalResolveType(Scope scope) { - // Answer the signature return type - // Base type promotion - this.constant = Constant.NotAConstant; - if (this.receiver == null) { - this.actualReceiverType = scope.enclosingReceiverType(); - } else if (scope.kind == Scope.CLASS_SCOPE) { - this.actualReceiverType = this.receiver.resolveType((ClassScope) scope); - } else { - this.actualReceiverType = this.receiver.resolveType((BlockScope) scope); - } - - // will check for null after args are resolved - - boolean hasArgsTypeVar = false; - if (this.arguments != null) { - this.argumentsHaveErrors = false; // typeChecks all arguments - int length = this.arguments.length; - this.argumentTypes = new TypeBinding[length]; - for (int i = 0; i < length; i++){ - Expression argument = this.arguments[i]; - if (scope.kind == Scope.CLASS_SCOPE) { - this.argumentTypes[i] = argument.resolveType((ClassScope)scope); - } else { - this.argumentTypes[i] = argument.resolveType((BlockScope)scope); - } - if (this.argumentTypes[i] == null) { - this.argumentsHaveErrors = true; - } else if (!hasArgsTypeVar) { - hasArgsTypeVar = this.argumentTypes[i].isTypeVariable(); - } - } - if (this.argumentsHaveErrors) { - return null; - } - } - - // check receiver type - if (this.actualReceiverType == null) { - return null; - } - this.actualReceiverType = scope.environment().convertToRawType(this.receiver.resolvedType, true /*force the conversion of enclosing types*/); - ReferenceBinding enclosingType = scope.enclosingReceiverType(); - if (enclosingType==null ? false : enclosingType.isCompatibleWith(this.actualReceiverType)) { - this.bits |= ASTNode.SuperAccess; - } - - // base type cannot receive any message - if (this.actualReceiverType.isBaseType()) { - scope.problemReporter().javadocErrorNoMethodFor(this, this.actualReceiverType, this.argumentTypes, scope.getDeclarationModifiers()); - return null; - } - this.binding = scope.getMethod(this.actualReceiverType, this.selector, this.argumentTypes, this); - if (!this.binding.isValidBinding()) { - // Try method in enclosing types - TypeBinding enclosingTypeBinding = this.actualReceiverType; - MethodBinding methodBinding = this.binding; - while (!methodBinding.isValidBinding() && (enclosingTypeBinding.isMemberType() || enclosingTypeBinding.isLocalType())) { - enclosingTypeBinding = enclosingTypeBinding.enclosingType(); - methodBinding = scope.getMethod(enclosingTypeBinding, this.selector, this.argumentTypes, this); - } - if (methodBinding.isValidBinding()) { - this.binding = methodBinding; - } else { - // Try to search a constructor instead - enclosingTypeBinding = this.actualReceiverType; - MethodBinding contructorBinding = this.binding; - if (!contructorBinding.isValidBinding() && CharOperation.equals(this.selector, enclosingTypeBinding.shortReadableName())) { - contructorBinding = scope.getConstructor((ReferenceBinding)enclosingTypeBinding, this.argumentTypes, this); - } - while (!contructorBinding.isValidBinding() && (enclosingTypeBinding.isMemberType() || enclosingTypeBinding.isLocalType())) { - enclosingTypeBinding = enclosingTypeBinding.enclosingType(); - if (CharOperation.equals(this.selector, enclosingTypeBinding.shortReadableName())) { - contructorBinding = scope.getConstructor((ReferenceBinding)enclosingTypeBinding, this.argumentTypes, this); - } - } - if (contructorBinding.isValidBinding()) { - this.binding = contructorBinding; - } - } - } - if (!this.binding.isValidBinding()) { - // implicit lookup may discover issues due to static/constructor contexts. javadoc must be resilient - switch (this.binding.problemId()) { - case ProblemReasons.NonStaticReferenceInConstructorInvocation: - case ProblemReasons.NonStaticReferenceInStaticContext: - case ProblemReasons.InheritedNameHidesEnclosingName : - case ProblemReasons.Ambiguous: - MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; - if (closestMatch != null) { - this.binding = closestMatch; // ignore problem if can reach target method through it - } - } - } - if (!this.binding.isValidBinding()) { - if (this.receiver.resolvedType instanceof ProblemReferenceBinding) { - // problem already got signaled on receiver, do not report secondary problem - return null; - } - if (this.binding.declaringClass == null) { - if (this.actualReceiverType instanceof ReferenceBinding) { - this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType; - } else { - scope.problemReporter().javadocErrorNoMethodFor(this, this.actualReceiverType, this.argumentTypes, scope.getDeclarationModifiers()); - return null; - } - } - scope.problemReporter().javadocInvalidMethod(this, this.binding, scope.getDeclarationModifiers()); - // record the closest match, for clients who may still need hint about possible method match - if (this.binding instanceof ProblemMethodBinding) { - MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; - if (closestMatch != null) this.binding = closestMatch; - } - return this.resolvedType = this.binding == null ? null : this.binding.returnType; - } else if (hasArgsTypeVar) { - MethodBinding problem = new ProblemMethodBinding(this.binding, this.selector, this.argumentTypes, ProblemReasons.NotFound); - scope.problemReporter().javadocInvalidMethod(this, problem, scope.getDeclarationModifiers()); - } else if (this.binding.isVarargs()) { - int length = this.argumentTypes.length; - if (!(this.binding.parameters.length == length && this.argumentTypes[length-1].isArrayType())) { - MethodBinding problem = new ProblemMethodBinding(this.binding, this.selector, this.argumentTypes, ProblemReasons.NotFound); - scope.problemReporter().javadocInvalidMethod(this, problem, scope.getDeclarationModifiers()); - } - } else { - int length = this.argumentTypes.length; - for (int i=0; i 0) output.append(", "); //$NON-NLS-1$ - this.arguments[i].printExpression(0, output); - } - } - return output.append(')'); - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - return internalResolveType(scope); - } - - @Override - public TypeBinding resolveType(ClassScope scope) { - return internalResolveType(scope); - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) { - if (this.receiver != null) { - this.receiver.traverse(visitor, blockScope); - } - if (this.arguments != null) { - int argumentsLength = this.arguments.length; - for (int i = 0; i < argumentsLength; i++) - this.arguments[i].traverse(visitor, blockScope); - } - } - visitor.endVisit(this, blockScope); - } - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.receiver != null) { - this.receiver.traverse(visitor, scope); - } - if (this.arguments != null) { - int argumentsLength = this.arguments.length; - for (int i = 0; i < argumentsLength; i++) - this.arguments[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocModuleReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocModuleReference.java deleted file mode 100644 index 8ca795f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocModuleReference.java +++ /dev/null @@ -1,194 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020, 2022 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - - -public class JavadocModuleReference extends Expression implements IJavadocTypeReference { - - public int tagSourceStart, tagSourceEnd; - public TypeReference typeReference; - public ModuleReference moduleReference; - public ModuleBinding moduleBinding; - - public JavadocModuleReference(char[][] sources, long[] pos, int tagStart, int tagEnd) { - super(); - this.moduleReference = new ModuleReference(sources, pos); - this.tagSourceStart = tagStart; - this.tagSourceEnd = tagEnd; - this.sourceStart = this.moduleReference.sourceStart; - this.sourceEnd = this.moduleReference.sourceEnd; - this.bits |= ASTNode.InsideJavadoc; - } - - public JavadocModuleReference(ModuleReference moduleRef, int tagStart, int tagEnd) { - super(); - this.moduleReference = moduleRef; - this.tagSourceStart = tagStart; - this.tagSourceEnd = tagEnd; - this.sourceStart = this.moduleReference.sourceStart; - this.sourceEnd = this.moduleReference.sourceEnd; - this.bits |= ASTNode.InsideJavadoc; - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - @Override - public int getTagSourceStart() { - return this.tagSourceStart; - } - - @Override - public int getTagSourceEnd() { - return this.tagSourceEnd; - } - - public TypeReference getTypeReference() { - return this.typeReference; - } - - public void setTypeReference(TypeReference typeReference) { - this.typeReference = typeReference; - if (this.typeReference != null) { - this.sourceEnd = this.typeReference.sourceEnd; - } - } - - public ModuleReference getModuleReference() { - return this.moduleReference; - } - - public void setModuleReference(ModuleReference moduleReference) { - this.moduleReference = moduleReference; - this.sourceStart = this.moduleReference.sourceStart; - this.sourceStart = this.moduleReference.sourceEnd; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - if (this.moduleReference != null) { - output.append(this.moduleReference.moduleName); - } - output.append('/'); - if (this.typeReference != null) { - this.typeReference.printExpression(indent, output); - } - return output; - } - - public ModuleBinding resolve(Scope scope) { - ModuleBinding modBinding = this.moduleReference.resolve(scope); - if (modBinding != null - && !modBinding.isUnnamed() - && modBinding.isValidBinding()) { - this.moduleBinding = modBinding; - } else { - reportInvalidModule(scope); - } - return this.moduleBinding; - } - - private ModuleBinding resolveModule(BlockScope scope) { - return this.resolve((Scope)scope); - } - - private ModuleBinding resolveModule(ClassScope scope) { - return this.resolve(scope); - } - - @Override - public TypeBinding resolveType(BlockScope blockScope) { - this.resolveModule(blockScope); - TypeBinding tBinding= null; - if (this.moduleBinding != null - && this.typeReference != null) { - tBinding = this.typeReference.resolveType(blockScope); - PackageBinding pBinding = null; - if (tBinding!= null) { - if (tBinding.isValidBinding()) { - pBinding = tBinding.getPackage(); - } else { - return tBinding; - } - } else { - if(this.typeReference.resolvedType != null && !this.typeReference.resolvedType.isValidBinding()) { - if (this.typeReference instanceof JavadocSingleTypeReference) { - pBinding = ((JavadocSingleTypeReference)this.typeReference).packageBinding; - } else if (this.typeReference instanceof JavadocQualifiedTypeReference) { - pBinding = ((JavadocQualifiedTypeReference)this.typeReference).packageBinding; - } - } - } - if (pBinding != null && !this.moduleBinding.equals(pBinding.enclosingModule)) { - reportInvalidType(blockScope); - tBinding = null; - } - } - return tBinding; - } - - @Override - public TypeBinding resolveType(ClassScope classScope) { - this.resolveModule(classScope); - TypeBinding tBinding= null; - if (this.moduleBinding != null - && this.typeReference != null) { - tBinding = this.typeReference.resolveType(classScope, -1); - PackageBinding pBinding = null; - if (tBinding!= null) { - if (tBinding.isValidBinding()) { - pBinding = tBinding.getPackage(); - } else { - return tBinding; - } - } else { - if(this.resolvedType != null && !this.resolvedType.isValidBinding()) { - if (this.typeReference instanceof JavadocSingleTypeReference) { - pBinding = ((JavadocSingleTypeReference)this.typeReference).packageBinding; - } else if (this.typeReference instanceof JavadocQualifiedTypeReference) { - pBinding = ((JavadocQualifiedTypeReference)this.typeReference).packageBinding; - } - } - } - if (pBinding != null && !this.moduleBinding.equals(pBinding.enclosingModule)) { - reportInvalidType(classScope); - tBinding = null; - } - } - return tBinding; - } - - protected void reportInvalidModule(Scope scope) { - scope.problemReporter().javadocInvalidModule(this.moduleReference); - } - - protected void reportInvalidType(Scope scope) { - scope.problemReporter().javadocInvalidMemberTypeQualification(this.typeReference.sourceStart, this.typeReference.sourceEnd, scope.getDeclarationModifiers()); - } -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java deleted file mode 100644 index ae71c80..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocQualifiedTypeReference.java +++ /dev/null @@ -1,140 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2022 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.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.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - - -public class JavadocQualifiedTypeReference extends QualifiedTypeReference implements IJavadocTypeReference { - - public int tagSourceStart, tagSourceEnd; - public PackageBinding packageBinding; - public ModuleBinding moduleBinding; - private final boolean canBeModule; - - public JavadocQualifiedTypeReference(char[][] sources, long[] pos, int tagStart, int tagEnd) { - this(sources, pos, tagStart, tagEnd, false); - } - - public JavadocQualifiedTypeReference(char[][] sources, long[] pos, int tagStart, int tagEnd, boolean canBeModule) { - super(sources, pos); - this.tagSourceStart = tagStart; - this.tagSourceEnd = tagEnd; - this.bits |= ASTNode.InsideJavadoc; - this.canBeModule = canBeModule; - } - - /* - * We need to modify resolving behavior to handle package references - */ - private TypeBinding internalResolveType(Scope scope, boolean checkBounds) { - // handle the error here - this.constant = Constant.NotAConstant; - if (this.resolvedType != null) // is a shared type reference which was already resolved - return this.resolvedType.isValidBinding() ? this.resolvedType : this.resolvedType.closestMatch(); // already reported error - - TypeBinding type = this.resolvedType = getTypeBinding(scope); - // End resolution when getTypeBinding(scope) returns null. This may happen in - // certain circumstances, typically when an illegal access is done on a type - // variable (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=204749) - if (type == null) return null; - if (!type.isValidBinding()) { - Binding binding = scope.getTypeOrPackage(this.tokens); - if (binding instanceof PackageBinding) { - this.packageBinding = (PackageBinding) binding; - // Valid package references are allowed in Javadoc (https://bugs.eclipse.org/bugs/show_bug.cgi?id=281609) - } else { - Binding modBinding = null; - if (this.canBeModule) { - char[] moduleName = CharOperation.concatWith(this.tokens, '.'); - modBinding = scope.environment().getModule(moduleName); - } - if (modBinding instanceof ModuleBinding - && !((ModuleBinding)modBinding).isUnnamed() - && modBinding.isValidBinding()) { - this.moduleBinding = (ModuleBinding) modBinding; - } else { - reportInvalidType(scope); - } - } - return null; - } - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=209936 - // raw convert all enclosing types when dealing with Javadoc references - if (type.isGenericType() || type.isParameterizedType()) { - this.resolvedType = scope.environment().convertToRawType(type, true /*force the conversion of enclosing types*/); - } - return this.resolvedType; - } - @Override - protected void reportDeprecatedType(TypeBinding type, Scope scope) { - scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers()); - } - - @Override - protected void reportDeprecatedType(TypeBinding type, Scope scope, int index) { - scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers(), index); - } - - @Override - protected void reportInvalidType(Scope scope) { - scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); - } - @Override - public TypeBinding resolveType(BlockScope blockScope, boolean checkBounds, int location) { - return internalResolveType(blockScope, checkBounds); - } - - @Override - public TypeBinding resolveType(ClassScope classScope, int location) { - return internalResolveType(classScope, false); - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - @Override - public int getTagSourceStart() { - return this.tagSourceStart; - } - - @Override - public int getTagSourceEnd() { - return this.tagSourceEnd; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocReturnStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocReturnStatement.java deleted file mode 100644 index 36e1867..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocReturnStatement.java +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.*; - - -public class JavadocReturnStatement extends ReturnStatement { - - public JavadocReturnStatement(int s, int e) { - super(null, s, e); - this.bits |= (ASTNode.InsideJavadoc | ASTNode.Empty); - } - - @Override - public void resolve(BlockScope scope) { - MethodScope methodScope = scope.methodScope(); - MethodBinding methodBinding = null; - TypeBinding methodType = - (methodScope.referenceContext instanceof AbstractMethodDeclaration) - ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding) == null - ? null - : methodBinding.returnType) - : TypeBinding.VOID; - if (methodType == null || methodType == TypeBinding.VOID) { - scope.problemReporter().javadocUnexpectedTag(this.sourceStart, this.sourceEnd); - } else if ((this.bits & ASTNode.Empty) != 0) { - scope.problemReporter().javadocEmptyReturnTag(this.sourceStart, this.sourceEnd, scope.getDeclarationModifiers()); - } - } - - @Override - public StringBuilder printStatement(int tab, StringBuilder output) { - printIndent(tab, output).append("return"); //$NON-NLS-1$ - if ((this.bits & ASTNode.Empty) == 0) - output.append(' ').append(" "); //$NON-NLS-1$ - return output; - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocSingleNameReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocSingleNameReference.java deleted file mode 100644 index a59e0a2..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocSingleNameReference.java +++ /dev/null @@ -1,77 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class JavadocSingleNameReference extends SingleNameReference { - - public int tagSourceStart, tagSourceEnd; - - public JavadocSingleNameReference(char[] source, long pos, int tagStart, int tagEnd) { - super(source, pos); - this.tagSourceStart = tagStart; - this.tagSourceEnd = tagEnd; - this.bits |= InsideJavadoc; - } - - @Override - public void resolve(BlockScope scope) { - resolve(scope, true, scope.compilerOptions().reportUnusedParameterIncludeDocCommentReference); - } - - /** - * Resolve without warnings - */ - public void resolve(BlockScope scope, boolean warn, boolean considerParamRefAsUsage) { - - LocalVariableBinding variableBinding = scope.findVariable(this.token, this); - if (variableBinding != null && variableBinding.isValidBinding() && ((variableBinding.tagBits & TagBits.IsArgument) != 0)) { - this.binding = variableBinding; - if (considerParamRefAsUsage) { - variableBinding.useFlag = LocalVariableBinding.USED; - } - return; - } - if (warn) { - try { - MethodScope methScope = (MethodScope) scope; - scope.problemReporter().javadocUndeclaredParamTagName(this.token, this.sourceStart, this.sourceEnd, methScope.referenceMethod().modifiers); - } - catch (Exception e) { - scope.problemReporter().javadocUndeclaredParamTagName(this.token, this.sourceStart, this.sourceEnd, -1); - } - } - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java deleted file mode 100644 index f5ca09a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/JavadocSingleTypeReference.java +++ /dev/null @@ -1,160 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2022 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -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.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - - -public class JavadocSingleTypeReference extends SingleTypeReference implements IJavadocTypeReference { - - public int tagSourceStart, tagSourceEnd; - public PackageBinding packageBinding; - public ModuleBinding moduleBinding; - private final boolean canBeModule; - - public JavadocSingleTypeReference(char[] source, long pos, int tagStart, int tagEnd) { - this(source, pos, tagStart, tagEnd, false); - } - - public JavadocSingleTypeReference(char[] source, long pos, int tagStart, int tagEnd, boolean canBeModule) { - super(source, pos); - this.tagSourceStart = tagStart; - this.tagSourceEnd = tagEnd; - this.bits |= ASTNode.InsideJavadoc; - this.canBeModule = canBeModule; - } - - /* - * We need to modify resolving behavior to handle package references - */ - @Override - protected TypeBinding internalResolveType(Scope scope, int location) { - // handle the error here - this.constant = Constant.NotAConstant; - if (this.resolvedType != null) { // is a shared type reference which was already resolved - if (this.resolvedType.isValidBinding()) { - return this.resolvedType; - } else { - switch (this.resolvedType.problemId()) { - case ProblemReasons.NotFound : - case ProblemReasons.NotVisible : - case ProblemReasons.InheritedNameHidesEnclosingName : - TypeBinding type = this.resolvedType.closestMatch(); - return type; - default : - return null; - } - } - } - this.resolvedType = getTypeBinding(scope); - if (this.resolvedType instanceof LocalTypeBinding) { - // scope grants access to local types within this method, which, however, are illegal in javadoc - LocalTypeBinding localType = (LocalTypeBinding) this.resolvedType; - if (localType.scope != null && localType.scope.parent == scope) { - this.resolvedType = new ProblemReferenceBinding(new char[][] { localType.sourceName }, - (ReferenceBinding) this.resolvedType, ProblemReasons.NotFound); - } - } - // End resolution when getTypeBinding(scope) returns null. This may happen in - // certain circumstances, typically when an illegal access is done on a type - // variable (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=204749) - if (this.resolvedType == null) return null; - - if (!this.resolvedType.isValidBinding()) { - char[][] tokens = { this.token }; - Binding binding = scope.getTypeOrPackage(tokens); - if (binding instanceof PackageBinding) { - this.packageBinding = (PackageBinding) binding; - // Valid package references are allowed in Javadoc (https://bugs.eclipse.org/bugs/show_bug.cgi?id=281609) - } else { - Binding modBinding = null; - if (this.canBeModule) { - modBinding = scope.environment().getModule(this.token); - } - if (modBinding instanceof ModuleBinding - && !((ModuleBinding)modBinding).isUnnamed() - && modBinding.isValidBinding()) { - this.moduleBinding = (ModuleBinding) modBinding; - } else { - if (this.resolvedType.problemId() == ProblemReasons.NonStaticReferenceInStaticContext) { - TypeBinding closestMatch = this.resolvedType.closestMatch(); - if (closestMatch != null && closestMatch.isTypeVariable()) { - this.resolvedType = closestMatch; // ignore problem as we want report specific javadoc one instead - return this.resolvedType; - } - } - reportInvalidType(scope); - } - } - return null; - } - if (isTypeUseDeprecated(this.resolvedType, scope)) - reportDeprecatedType(this.resolvedType, scope); - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=209936 - // raw convert all enclosing types when dealing with Javadoc references - if (this.resolvedType.isGenericType() || this.resolvedType.isParameterizedType()) { - this.resolvedType = scope.environment().convertToRawType(this.resolvedType, true /*force the conversion of enclosing types*/); - } - return this.resolvedType; - } - @Override - protected void reportDeprecatedType(TypeBinding type, Scope scope) { - scope.problemReporter().javadocDeprecatedType(type, this, scope.getDeclarationModifiers()); - } - - @Override - protected void reportInvalidType(Scope scope) { - scope.problemReporter().javadocInvalidType(this, this.resolvedType, scope.getDeclarationModifiers()); - } - - /* (non-Javadoc) - * Redefine to capture javadoc specific signatures - * @see org.eclipse.jdt.internal.compiler.ast.ASTNode#traverse(org.eclipse.jdt.internal.compiler.ASTVisitor, org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - @Override - public int getTagSourceStart() { - return this.tagSourceStart; - } - - @Override - public int getTagSourceEnd() { - return this.tagSourceEnd; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java deleted file mode 100644 index 6facbe1..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LabeledStatement.java +++ /dev/null @@ -1,177 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class LabeledStatement extends Statement { - - public Statement statement; - public char[] label; - public BranchLabel targetLabel; - public int labelEnd; - - // for local variables table attributes - int mergedInitStateIndex = -1; - - /** - * LabeledStatement constructor comment. - */ - public LabeledStatement(char[] label, Statement statement, long labelPosition, int sourceEnd) { - - this.statement = statement; - // remember useful empty statement - if (statement instanceof EmptyStatement) statement.bits |= IsUsefulEmptyStatement; - this.label = label; - this.sourceStart = (int)(labelPosition >>> 32); - this.labelEnd = (int) labelPosition; - this.sourceEnd = sourceEnd; - } - - @Override - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - // need to stack a context to store explicit label, answer inits in case of normal completion merged - // with those relative to the exit path from break statement occurring inside the labeled statement. - if (this.statement == null) { - return flowInfo; - } else { - LabelFlowContext labelContext; - FlowInfo statementInfo, mergedInfo; - statementInfo = this.statement.analyseCode( - currentScope, - (labelContext = - new LabelFlowContext( - flowContext, - this, - this.label, - (this.targetLabel = new BranchLabel()), - currentScope)), - flowInfo); - boolean reinjectNullInfo = (statementInfo.tagBits & FlowInfo.UNREACHABLE) != 0 && - (labelContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) == 0; - mergedInfo = statementInfo.mergedWith(labelContext.initsOnBreak); - if (reinjectNullInfo) { - // an embedded loop has had no chance to reinject forgotten null info - ((UnconditionalFlowInfo)mergedInfo).addNullInfoFrom(flowInfo.unconditionalFieldLessCopy()). - addNullInfoFrom(labelContext.initsOnBreak.unconditionalFieldLessCopy()); - } - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); - if ((this.bits & ASTNode.LabelUsed) == 0) { - currentScope.problemReporter().unusedLabel(this); - } - return mergedInfo; - } - } - - @Override - public ASTNode concreteStatement() { - - // return statement.concreteStatement(); // for supporting nested labels: a:b:c: someStatement (see 21912) - return this.statement; - } - - /** - * Code generation for labeled statement - * - * may not need actual source positions recording - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - if (this.targetLabel != null) { - this.targetLabel.initialize(codeStream); - if (this.statement != null) { - this.statement.generateCode(currentScope, codeStream); - } - this.targetLabel.place(); - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public StringBuilder printStatement(int tab, StringBuilder output) { - - printIndent(tab, output).append(this.label).append(": "); //$NON-NLS-1$ - if (this.statement == null) - output.append(';'); - else - this.statement.printStatement(0, output); - return output; - } - - @Override - public void resolve(BlockScope scope) { - - if (this.statement != null) { - this.statement.resolve(scope); - } - } - - - @Override - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - if (this.statement != null) this.statement.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); - } - - @Override - public boolean doesNotCompleteNormally() { - if (this.statement.breaksOut(this.label)) - return false; - return this.statement.doesNotCompleteNormally(); - } - - @Override - public boolean completesByContinue() { - return this.statement instanceof ContinueStatement; // NOT this.statement.continuesAtOuterLabel - } - - @Override - public boolean canCompleteNormally() { - if (this.statement.canCompleteNormally()) - return true; - return this.statement.breaksOut(this.label); - } - - @Override - public boolean continueCompletes() { - return this.statement instanceof ContinueStatement; // NOT this.statement.continuesAtOuterLabel - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java deleted file mode 100644 index 778cdda..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java +++ /dev/null @@ -1,1603 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Jesper S Moller - Contributions for - * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression - * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment - * Bug 416885 - [1.8][compiler]IncompatibleClassChange error (edit) - * Stephan Herrmann - Contribution for - * bug 401030 - [1.8][null] Null analysis support for lambda methods. - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 423504 - [1.8] Implement "18.5.3 Functional Interface Parameterization Inference" - * Bug 425142 - [1.8][compiler] NPE in ConstraintTypeFormula.reduceSubType - * Bug 425153 - [1.8] Having wildcard allows incompatible types in a lambda expression - * Bug 424205 - [1.8] Cannot infer type for diamond type with lambda on method invocation - * Bug 425798 - [1.8][compiler] Another NPE in ConstraintTypeFormula.reduceSubType - * Bug 425156 - [1.8] Lambda as an argument is flagged with incompatible error - * Bug 424403 - [1.8][compiler] Generic method call with method reference argument fails to resolve properly. - * Bug 426563 - [1.8] AIOOBE when method with error invoked with lambda expression as argument - * Bug 420525 - [1.8] [compiler] Incorrect error "The type Integer does not define sum(Object, Object) that is applicable here" - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 428294 - [1.8][compiler] Type mismatch: cannot convert from List to Collection - * Bug 428786 - [1.8][compiler] Inference needs to compute the "ground target type" when reducing a lambda compatibility constraint - * Bug 428980 - [1.8][null] simple expression as lambda body doesn't leverage null annotation on argument - * Bug 429430 - [1.8] Lambdas and method reference infer wrong exception type with generics (RuntimeException instead of IOException) - * Bug 432110 - [1.8][compiler] nested lambda type incorrectly inferred vs javac - * Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables - * Bug 441693 - [1.8][null] Bogus warning for type argument annotated with @NonNull - * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression - * Bug 453483 - [compiler][null][loop] Improve null analysis for loops - * Bug 455723 - Nonnull argument not correctly inferred in loop - * Bug 463728 - [1.8][compiler][inference] Ternary operator in lambda derives wrong type - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.INVOCATION_CONTEXT; - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jdt.core.compiler.CategorizedProblem; -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ClassFile; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.flow.ExceptionHandlingFlowContext; -import org.eclipse.jdt.internal.compiler.flow.ExceptionInferenceFlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; -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.Substitution; -import org.eclipse.jdt.internal.compiler.lookup.Substitution.NullSubstitution; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; -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.WildcardBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope.Substitutor; -import org.eclipse.jdt.internal.compiler.parser.Parser; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit; -import org.eclipse.jdt.internal.compiler.problem.AbortMethod; -import org.eclipse.jdt.internal.compiler.problem.AbortType; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; - -@SuppressWarnings({"rawtypes", "unchecked"}) -public class LambdaExpression extends FunctionalExpression implements IPolyExpression, ReferenceContext, ProblemSeverities { - public Argument [] arguments; - private TypeBinding [] argumentTypes; - public int arrowPosition; - public Statement body; - public boolean hasParentheses; - public MethodScope scope; - boolean voidCompatible = true; - boolean valueCompatible = false; - boolean returnsValue; - private final boolean requiresGenericSignature; - boolean returnsVoid; - public LambdaExpression original = this; - private boolean committed = false; - public SyntheticArgumentBinding[] outerLocalVariables = NO_SYNTHETIC_ARGUMENTS; - public Map mapSyntheticEnclosingTypes = new HashMap<>(); - public boolean hasOuterClassMemberReference = false; - private int outerLocalVariablesSlotSize = 0; - private boolean assistNode = false; - private boolean hasIgnoredMandatoryErrors = false; - private ReferenceBinding classType; - private Set thrownExceptions; - private static final SyntheticArgumentBinding [] NO_SYNTHETIC_ARGUMENTS = new SyntheticArgumentBinding[0]; - private static final Block NO_BODY = new Block(0); - private HashMap copiesPerTargetType; - protected Expression [] resultExpressions = NO_EXPRESSIONS; - public InferenceContext18 inferenceContext; // when performing tentative resolve keep a back reference to the driving context - private Map localTypes; // support look-up of a local type from this lambda copy - public boolean argumentsTypeVar = false; - int firstLocalLocal; // analysis index of first local variable (if any) post parameter(s) in the lambda; ("local local" as opposed to "outer local") - - - public LambdaExpression(CompilationResult compilationResult, boolean assistNode, boolean requiresGenericSignature) { - super(compilationResult); - this.assistNode = assistNode; - this.requiresGenericSignature = requiresGenericSignature; - setArguments(NO_ARGUMENTS); - setBody(NO_BODY); - } - - public LambdaExpression(CompilationResult compilationResult, boolean assistNode) { - this(compilationResult, assistNode, false); - } - - public void setArguments(Argument [] arguments) { - this.arguments = arguments != null ? arguments : ASTNode.NO_ARGUMENTS; - this.argumentTypes = new TypeBinding[arguments != null ? arguments.length : 0]; - } - - public Argument [] arguments() { - return this.arguments; - } - - public TypeBinding[] argumentTypes() { - return this.argumentTypes; - } - - public void setBody(Statement body) { - this.body = body == null ? NO_BODY : body; - } - - public Statement body() { - return this.body; - } - - public Expression[] resultExpressions() { - return this.resultExpressions; - } - - public void setArrowPosition(int arrowPosition) { - this.arrowPosition = arrowPosition; - } - - public int arrowPosition() { - return this.arrowPosition; - } - - protected FunctionalExpression original() { - return this.original; - } - - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - if (this.shouldCaptureInstance) { - this.binding.modifiers &= ~ClassFileConstants.AccStatic; - } else { - this.binding.modifiers |= ClassFileConstants.AccStatic; - } - SourceTypeBinding sourceType = currentScope.enclosingSourceType(); - boolean firstSpill = !(this.binding instanceof SyntheticMethodBinding); - this.binding = sourceType.addSyntheticMethod(this); - int pc = codeStream.position; - StringBuilder signature = new StringBuilder(); - signature.append('('); - if (this.shouldCaptureInstance) { - codeStream.aload_0(); - signature.append(sourceType.signature()); - } - for (int i = 0, length = this.outerLocalVariables == null ? 0 : this.outerLocalVariables.length; i < length; i++) { - SyntheticArgumentBinding syntheticArgument = this.outerLocalVariables[i]; - if (this.shouldCaptureInstance && firstSpill) { // finally block handling results in extra spills, avoid side effect. - syntheticArgument.resolvedPosition++; - } - signature.append(syntheticArgument.type.signature()); - Object[] path; - Binding target; - if (syntheticArgument.actualOuterLocalVariable != null) { - LocalVariableBinding capturedOuterLocal = syntheticArgument.actualOuterLocalVariable; - path = currentScope.getEmulationPath(capturedOuterLocal); - target = capturedOuterLocal; - } else { - path = currentScope.getEmulationPath( - (ReferenceBinding) syntheticArgument.type, - false /*not only exact match (that is, allow compatible)*/, - false); - target = syntheticArgument.type; - } - codeStream.generateOuterAccess(path, this, target, currentScope); - } - signature.append(')'); - if (this.expectedType instanceof IntersectionTypeBinding18) { - signature.append(((IntersectionTypeBinding18)this.expectedType).getSAMType(currentScope).signature()); - } else { - signature.append(this.expectedType.signature()); - } - int invokeDynamicNumber = codeStream.classFile.recordBootstrapMethod(this); - codeStream.invokeDynamic(invokeDynamicNumber, (this.shouldCaptureInstance ? 1 : 0) + this.outerLocalVariablesSlotSize, 1, this.descriptor.selector, signature.toString().toCharArray(), - this.resolvedType.id, this.resolvedType); - if (!valueRequired) - codeStream.pop(); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public boolean kosherDescriptor(Scope currentScope, MethodBinding sam, boolean shouldChatter) { - if (sam.typeVariables != Binding.NO_TYPE_VARIABLES) { - if (shouldChatter) - currentScope.problemReporter().lambdaExpressionCannotImplementGenericMethod(this, sam); - return false; - } - return super.kosherDescriptor(currentScope, sam, shouldChatter); - } - - public void resolveTypeWithBindings(LocalVariableBinding[] bindings, BlockScope blockScope, boolean skipKosherCheck) { - blockScope.include(bindings); - try { - this.resolveType(blockScope, skipKosherCheck); - } finally { - blockScope.exclude(bindings); - } - } - - /* This code is arranged so that we can continue with as much analysis as possible while avoiding - * mine fields that would result in a slew of spurious messages. This method is a merger of: - * @see org.eclipse.jdt.internal.compiler.lookup.MethodScope.createMethod(AbstractMethodDeclaration) - * @see org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.resolveTypesFor(MethodBinding) - * @see org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.resolve(ClassScope) - */ - @Override - public TypeBinding resolveType(BlockScope blockScope, boolean skipKosherCheck) { - - boolean argumentsTypeElided = argumentsTypeElided(); - int argumentsLength = this.arguments == null ? 0 : this.arguments.length; - - if (this.constant != Constant.NotAConstant) { - this.constant = Constant.NotAConstant; - this.enclosingScope = blockScope; - if (this.original == this) - this.ordinal = recordFunctionalType(blockScope); - - if (!argumentsTypeElided) { - for (int i = 0; i < argumentsLength; i++) - this.argumentTypes[i] = this.arguments[i].type.resolveType(blockScope, true /* check bounds*/); - } - if (this.expectedType == null && this.expressionContext == INVOCATION_CONTEXT) { - return new PolyTypeBinding(this); - } - } - - MethodScope methodScope = blockScope.methodScope(); - this.scope = new MethodScope(blockScope, this, methodScope.isStatic, methodScope.lastVisibleFieldID); - this.scope.isConstructorCall = methodScope.isConstructorCall; - - super.resolveType(blockScope, skipKosherCheck); // compute & capture interface function descriptor. - - final boolean haveDescriptor = this.descriptor != null; - - if (!skipKosherCheck && (!haveDescriptor || this.descriptor.typeVariables != Binding.NO_TYPE_VARIABLES)) // already complained in kosher* - return this.resolvedType = null; - - this.binding = new MethodBinding(ClassFileConstants.AccPrivate | ClassFileConstants.AccSynthetic | ExtraCompilerModifiers.AccUnresolved, - CharOperation.concat(TypeConstants.ANONYMOUS_METHOD, Integer.toString(this.ordinal).toCharArray()), // will be fixed up later. - haveDescriptor ? this.descriptor.returnType : TypeBinding.VOID, - Binding.NO_PARAMETERS, // for now. - haveDescriptor ? this.descriptor.thrownExceptions : Binding.NO_EXCEPTIONS, - blockScope.enclosingSourceType()); - this.binding.typeVariables = Binding.NO_TYPE_VARIABLES; - - MethodScope enm = this.scope.namedMethodScope(); - MethodBinding enmb = enm == null ? null : enm.referenceMethodBinding(); - if (enmb != null && enmb.isViewedAsDeprecated()) { - this.binding.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly; - this.binding.tagBits |= enmb.tagBits & TagBits.AnnotationTerminallyDeprecated; - } - - boolean argumentsHaveErrors = false; - if (haveDescriptor) { - int parametersLength = this.descriptor.parameters.length; - if (parametersLength != argumentsLength) { - this.scope.problemReporter().lambdaSignatureMismatched(this); - if (argumentsTypeElided || this.original != this) // no interest in continuing to error check copy. - return this.resolvedType = null; // FUBAR, bail out ... - else { - this.resolvedType = null; // continue to type check. - argumentsHaveErrors = true; - } - } - } - - TypeBinding[] newParameters = new TypeBinding[argumentsLength]; - - AnnotationBinding [][] parameterAnnotations = null; - for (int i = 0; i < argumentsLength; i++) { - Argument argument = this.arguments[i]; - if (argument.isVarArgs()) { - if (i == argumentsLength - 1) { - this.binding.modifiers |= ClassFileConstants.AccVarargs; - } else { - this.scope.problemReporter().illegalVarargInLambda(argument); - argumentsHaveErrors = true; - } - } - - TypeBinding argumentType; - final TypeBinding expectedParameterType = haveDescriptor && i < this.descriptor.parameters.length ? this.descriptor.parameters[i] : null; - argumentType = argumentsTypeElided ? expectedParameterType : this.argumentTypes[i]; - if (argumentType == null) { - argumentsHaveErrors = true; - } else if (argumentType == TypeBinding.VOID) { - this.scope.problemReporter().argumentTypeCannotBeVoid(this, argument); - argumentsHaveErrors = true; - } else { - if (!argumentType.isValidBinding()) { - this.binding.tagBits |= TagBits.HasUnresolvedArguments; - } - if ((argumentType.tagBits & TagBits.HasMissingType) != 0) { - this.binding.tagBits |= TagBits.HasMissingType; - } - } - } - if (!argumentsTypeElided && !argumentsHaveErrors) { - ReferenceBinding groundType = null; - ReferenceBinding expectedSAMType = null; - if (this.expectedType instanceof IntersectionTypeBinding18) - expectedSAMType = (ReferenceBinding) ((IntersectionTypeBinding18) this.expectedType).getSAMType(blockScope); - else if (this.expectedType instanceof ReferenceBinding) - expectedSAMType = (ReferenceBinding) this.expectedType; - if (expectedSAMType != null) - groundType = findGroundTargetType(blockScope, this.expectedType, expectedSAMType, argumentsTypeElided); - - if (groundType != null) { - this.descriptor = groundType.getSingleAbstractMethod(blockScope, true); - if (!this.descriptor.isValidBinding()) { - reportSamProblem(blockScope, this.descriptor); - } else { - if (groundType != expectedSAMType) { //$IDENTITY-COMPARISON$ - if (!groundType.isCompatibleWith(expectedSAMType, this.scope)) { // the ground has shifted, are we still on firm grounds ? - blockScope.problemReporter().typeMismatchError(groundType, this.expectedType, this, null); // report deliberately against block scope so as not to blame the lambda. - return null; - } - } - this.resolvedType = groundType; - } - } else { - this.binding = new ProblemMethodBinding(TypeConstants.ANONYMOUS_METHOD, null, ProblemReasons.NotAWellFormedParameterizedType); - reportSamProblem(blockScope, this.binding); - return this.resolvedType = null; - } - } - boolean parametersHaveErrors = false; - boolean genericSignatureNeeded = this.requiresGenericSignature || blockScope.compilerOptions().generateGenericSignatureForLambdaExpressions; - TypeBinding[] expectedParameterTypes = new TypeBinding[argumentsLength]; - for (int i = 0; i < argumentsLength; i++) { - Argument argument = this.arguments[i]; - TypeBinding argumentType; - final TypeBinding expectedParameterType = haveDescriptor && i < this.descriptor.parameters.length ? this.descriptor.parameters[i] : null; - argumentType = argumentsTypeElided ? expectedParameterType : this.argumentTypes[i]; - expectedParameterTypes[i] = expectedParameterType; - if (argumentType != null && argumentType != TypeBinding.VOID) { - if (haveDescriptor && expectedParameterType != null && argumentType.isValidBinding() && TypeBinding.notEquals(argumentType, expectedParameterType)) { - if (expectedParameterType.isProperType(true)) { - if (!isOnlyWildcardMismatch(expectedParameterType, argumentType)) { - this.scope.problemReporter().lambdaParameterTypeMismatched(argument, argument.type, expectedParameterType); - parametersHaveErrors = true; // continue to type check, but don't signal success - } - } - } - if (genericSignatureNeeded) { - TypeBinding leafType = argumentType.leafComponentType(); - if (leafType instanceof ReferenceBinding && (((ReferenceBinding) leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0) - this.binding.modifiers |= ExtraCompilerModifiers.AccGenericSignature; - } - newParameters[i] = argument.bind(this.scope, argumentType, false); - if (argument.annotations != null) { - this.binding.tagBits |= TagBits.HasParameterAnnotations; - if (parameterAnnotations == null) { - parameterAnnotations = new AnnotationBinding[argumentsLength][]; - for (int j = 0; j < i; j++) { - parameterAnnotations[j] = Binding.NO_ANNOTATIONS; - } - } - parameterAnnotations[i] = argument.binding.getAnnotations(); - } else if (parameterAnnotations != null) { - parameterAnnotations[i] = Binding.NO_ANNOTATIONS; - } - } - } - if (this.argumentsTypeVar) { - for (int i = 0; i < argumentsLength; ++i) { - this.arguments[i].type.resolvedType = expectedParameterTypes[i]; - } - } - // only assign parameters if no problems are found - if (!argumentsHaveErrors) { - this.binding.parameters = newParameters; - if (parameterAnnotations != null) - this.binding.setParameterAnnotations(parameterAnnotations); - } - - if (!argumentsTypeElided && !argumentsHaveErrors && this.binding.isVarargs()) { - if (!this.binding.parameters[this.binding.parameters.length - 1].isReifiable()) { - this.scope.problemReporter().possibleHeapPollutionFromVararg(this.arguments[this.arguments.length - 1]); - } - } - - ReferenceBinding [] exceptions = this.binding.thrownExceptions; - int exceptionsLength = exceptions.length; - for (int i = 0; i < exceptionsLength; i++) { - ReferenceBinding exception = exceptions[i]; - if ((exception.tagBits & TagBits.HasMissingType) != 0) { - this.binding.tagBits |= TagBits.HasMissingType; - } - if (genericSignatureNeeded) - this.binding.modifiers |= (exception.modifiers & ExtraCompilerModifiers.AccGenericSignature); - } - - TypeBinding returnType = this.binding.returnType; - if (returnType != null) { - if ((returnType.tagBits & TagBits.HasMissingType) != 0) { - this.binding.tagBits |= TagBits.HasMissingType; - } - if (genericSignatureNeeded) { - TypeBinding leafType = returnType.leafComponentType(); - if (leafType instanceof ReferenceBinding && (((ReferenceBinding) leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0) - this.binding.modifiers |= ExtraCompilerModifiers.AccGenericSignature; - } - } // TODO (stephan): else? (can that happen?) - - if (haveDescriptor && !argumentsHaveErrors && blockScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) { - if (!argumentsTypeElided) { - AbstractMethodDeclaration.createArgumentBindings(this.arguments, this.binding, this.scope); // includes validation - // no application of null-ness default, hence also no warning regarding redundant null annotation - mergeParameterNullAnnotations(blockScope); - } - this.binding.tagBits |= (this.descriptor.tagBits & TagBits.AnnotationNullMASK); - } - - this.binding.modifiers &= ~ExtraCompilerModifiers.AccUnresolved; - - this.firstLocalLocal = this.scope.outerMostMethodScope().analysisIndex; - if (this.body instanceof Expression && ((Expression) this.body).isTrulyExpression()) { - Expression expression = (Expression) this.body; - new ReturnStatement(expression, expression.sourceStart, expression.sourceEnd, true).resolve(this.scope); // :-) ;-) - if (expression.resolvedType == TypeBinding.VOID && !expression.statementExpression()) - this.scope.problemReporter().invalidExpressionAsStatement(expression); - } else { - this.body.resolve(this.scope); - /* At this point, shape analysis is complete for ((see returnsExpression(...)) - - a lambda with an expression body, - - a lambda with a block body in which we saw a return statement naked or otherwise. - */ - if (!this.returnsVoid && !this.returnsValue) - this.valueCompatible = this.body.doesNotCompleteNormally(); - } - if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { - this.scope.problemReporter().missingTypeInLambda(this, this.binding); - } - if (this.shouldCaptureInstance && this.scope.isConstructorCall) { - this.scope.problemReporter().fieldsOrThisBeforeConstructorInvocation(this); - } - // beyond this point ensure that all local type bindings are their final binding: - updateLocalTypes(); - if (this.original == this) { - this.committed = true; // the original has been resolved - } - return (argumentsHaveErrors || parametersHaveErrors) ? null : this.resolvedType; - } - - // check if the given types are parameterized types and if their type arguments - // differ only in a wildcard - // ? and ? extends Object - private boolean isOnlyWildcardMismatch(TypeBinding expected, TypeBinding argument) { - boolean onlyWildcardMismatch = false; - if (expected.isParameterizedType() && argument.isParameterizedType()) { - TypeBinding[] expectedArgs = ((ParameterizedTypeBinding)expected).typeArguments(); - TypeBinding[] args = ((ParameterizedTypeBinding)argument).typeArguments(); - if (args.length != expectedArgs.length) - return false; - for (int j = 0; j < args.length; j++) { - if (TypeBinding.notEquals(expectedArgs[j], args[j])) { - if (expectedArgs[j].isWildcard() && args[j].isUnboundWildcard()) { - WildcardBinding wc = (WildcardBinding)expectedArgs[j]; - TypeBinding bound = wc.allBounds(); - if (bound != null && wc.boundKind == Wildcard.EXTENDS && bound.id == TypeIds.T_JavaLangObject) - onlyWildcardMismatch = true; - } else { - onlyWildcardMismatch = false; - break; - } - } - } - } - return onlyWildcardMismatch; - } - private ReferenceBinding findGroundTargetType(BlockScope blockScope, TypeBinding targetType, TypeBinding expectedSAMType, boolean argumentTypesElided) { - - if (expectedSAMType instanceof IntersectionTypeBinding18) - expectedSAMType = ((IntersectionTypeBinding18) expectedSAMType).getSAMType(blockScope); - - if (expectedSAMType instanceof ReferenceBinding && expectedSAMType.isValidBinding()) { - ParameterizedTypeBinding withWildCards = InferenceContext18.parameterizedWithWildcard(expectedSAMType); - if (withWildCards != null) { - if (!argumentTypesElided) { - InferenceContext18 freshInferenceContext = new InferenceContext18(blockScope); - try { - return freshInferenceContext.inferFunctionalInterfaceParameterization(this, blockScope, withWildCards); - } finally { - freshInferenceContext.cleanUp(); - } - } else { - return withWildCards.getNonWildcardParameterization(blockScope); - } - } - if (targetType instanceof ReferenceBinding) - return (ReferenceBinding) targetType; - } - return null; - } - - @Override - public boolean argumentsTypeElided() { - return (this.arguments.length > 0 && this.arguments[0].hasElidedType()) || this.argumentsTypeVar; - } - - private void analyzeExceptions() { - ExceptionHandlingFlowContext ehfc; - CompilerOptions compilerOptions = this.scope.compilerOptions(); - boolean oldAnalyseResources = compilerOptions.analyseResourceLeaks; - compilerOptions.analyseResourceLeaks = false; - try { - this.body.analyseCode(this.scope, - ehfc = new ExceptionInferenceFlowContext(null, this, Binding.NO_EXCEPTIONS, null, this.scope, FlowInfo.DEAD_END), - UnconditionalFlowInfo.fakeInitializedFlowInfo(this.firstLocalLocal, this.scope.referenceType().maxFieldCount)); - this.thrownExceptions = ehfc.extendedExceptions == null ? Collections.emptySet() : new HashSet(ehfc.extendedExceptions); - } catch (Exception e) { - // drop silently. - } finally { - compilerOptions.analyseResourceLeaks = oldAnalyseResources; - } - } - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, final FlowInfo flowInfo) { - - if (this.ignoreFurtherInvestigation) - return flowInfo; - - FlowInfo lambdaInfo = flowInfo.copy(); // what happens in vegas, stays in vegas ... - ExceptionHandlingFlowContext methodContext = - new ExceptionHandlingFlowContext( - flowContext, - this, - this.binding.thrownExceptions, - flowContext.getInitializationContext(), - this.scope, - FlowInfo.DEAD_END); - - // nullity, owning and mark as assigned - MethodBinding methodWithParameterDeclaration = argumentsTypeElided() ? this.descriptor : this.binding; - AbstractMethodDeclaration.analyseArguments(currentScope.environment(), lambdaInfo, flowContext, this.arguments, methodWithParameterDeclaration); - - if (this.arguments != null) { - for (int i = 0, count = this.arguments.length; i < count; i++) { - this.bits |= (this.arguments[i].bits & ASTNode.HasTypeAnnotations); - } - } - - lambdaInfo = this.body.analyseCode(this.scope, methodContext, lambdaInfo); - - // check for missing returning path for block body's ... - if (this.body instanceof Block) { - TypeBinding returnTypeBinding = expectedResultType(); - if ((returnTypeBinding == TypeBinding.VOID)) { - if ((lambdaInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0 || ((Block) this.body).statements == null) { - this.bits |= ASTNode.NeedFreeReturn; - } - } else { - if (lambdaInfo != FlowInfo.DEAD_END) { - this.scope.problemReporter().shouldReturn(returnTypeBinding, this); - } - } - } else { // Expression - if (currentScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled - && lambdaInfo.reachMode() == FlowInfo.REACHABLE) - { - Expression expression = (Expression)this.body; - checkAgainstNullAnnotation(flowContext, expression, flowInfo, expression.nullStatus(lambdaInfo, flowContext)); - } - } - return flowInfo; - } - - // cf. AbstractMethodDeclaration.validateNullAnnotations() - // pre: !argumentTypeElided() - void validateNullAnnotations() { - // null annotations on parameters? - if (this.binding != null) { - int length = this.binding.parameters.length; - for (int i=0; i> ASTNode.ParenthesizedSHIFT; - String suffix = ""; //$NON-NLS-1$ - for(int i = 0; i < parenthesesCount; i++) { - output.append('('); - suffix += ')'; - } - output.append('('); - if (this.arguments != null) { - for (int i = 0; i < this.arguments.length; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.arguments[i].print(0, output); - } - } - output.append(") -> " ); //$NON-NLS-1$ - if (makeShort) { - output.append("{}"); //$NON-NLS-1$ - } else { - if (this.body != null) - this.body.print(this.body instanceof Block ? tab : 0, output); - else - output.append("<@incubator>"); //$NON-NLS-1$ - } - return output.append(suffix); - } - - public TypeBinding expectedResultType() { - return this.descriptor != null && this.descriptor.isValidBinding() ? this.descriptor.returnType : null; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - if (this.arguments != null) { - int argumentsLength = this.arguments.length; - for (int i = 0; i < argumentsLength; i++) - this.arguments[i].traverse(visitor, this.scope); - } - - if (this.body != null) { - this.body.traverse(visitor, this.scope); - } - } - visitor.endVisit(this, blockScope); - } - - public MethodScope getScope() { - return this.scope; - } - - private boolean enclosingScopesHaveErrors() { - Scope skope = this.enclosingScope; - while (skope != null) { - ReferenceContext context = skope.referenceContext(); - if (context != null && context.hasErrors()) - return true; - skope = skope.parent; - } - return false; - } - - private void analyzeShape() { // Simple minded analysis for code assist & potential compatibility. - class ShapeComputer extends ASTVisitor { - @Override - public boolean visit(TypeDeclaration type, BlockScope skope) { - return false; - } - @Override - public boolean visit(TypeDeclaration type, ClassScope skope) { - return false; - } - @Override - public boolean visit(LambdaExpression type, BlockScope skope) { - return false; - } - @Override - public boolean visit(ReturnStatement returnStatement, BlockScope skope) { - if (returnStatement.expression != null) { - LambdaExpression.this.valueCompatible = true; - LambdaExpression.this.voidCompatible = false; - LambdaExpression.this.returnsValue = true; - } else { - LambdaExpression.this.voidCompatible = true; - LambdaExpression.this.valueCompatible = false; - LambdaExpression.this.returnsVoid = true; - } - return false; - } - } - if (this.body instanceof Expression && ((Expression) this.body).isTrulyExpression()) { - // When completion is still in progress, it is not possible to ask if the expression constitutes a statement expression. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=435219 - this.voidCompatible = this.assistNode ? true : ((Expression) this.body).statementExpression(); - this.valueCompatible = true; // expression could be of type void - we can't determine that as we are working with unresolved expressions, for potential compatibility it is OK. - } else { - // For code assist, we need to be a bit tolerant/fuzzy here: the code is being written "just now", if we are too pedantic, selection/completion will break; - if (this.assistNode) { - this.voidCompatible = true; - this.valueCompatible = true; - } - this.body.traverse(new ShapeComputer(), null); - if (!this.returnsValue && !this.returnsVoid) - this.valueCompatible = this.body.doesNotCompleteNormally(); - } - } - - @Override - public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope skope) { - /* We get here only when the lambda is NOT pertinent to applicability and that too only for type elided lambdas. */ - - /* 15.12.2.1: A lambda expression (§15.27) is potentially compatible with a functional interface type (§9.8) if all of the following are true: - – The arity of the target type's function type is the same as the arity of the lambda expression. - – If the target type's function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2). - – If the target type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2). - */ - if (!super.isPertinentToApplicability(targetType, null)) - return true; - - final MethodBinding sam = targetType.getSingleAbstractMethod(skope, true); - if (sam == null || !sam.isValidBinding()) - return false; - - if (sam.parameters.length != this.arguments.length) - return false; - - analyzeShape(); - if (sam.returnType.id == TypeIds.T_void) { - if (!this.voidCompatible) - return false; - } else { - if (!this.valueCompatible) - return false; - } - return true; - } - - private enum CompatibilityResult { COMPATIBLE, INCOMPATIBLE, REPORTED } - - public boolean reportShapeError(TypeBinding targetType, Scope skope) { - return internalIsCompatibleWith(targetType, skope, true) == CompatibilityResult.REPORTED; - } - - @Override - public boolean isCompatibleWith(TypeBinding targetType, final Scope skope) { - return internalIsCompatibleWith(targetType, skope, false) == CompatibilityResult.COMPATIBLE; - } - CompatibilityResult internalIsCompatibleWith(TypeBinding targetType, Scope skope, boolean reportShapeProblem) { - - if (!super.isPertinentToApplicability(targetType, null)) - return CompatibilityResult.COMPATIBLE; - - LambdaExpression copy = null; - try { - copy = cachedResolvedCopy(targetType, argumentsTypeElided(), false, null, skope); // if argument types are elided, we don't care for result expressions against *this* target, any valid target is OK. - } catch (CopyFailureException cfe) { - if (this.assistNode) - return CompatibilityResult.COMPATIBLE; // can't type check result expressions, just say yes. - return isPertinentToApplicability(targetType, null) ? CompatibilityResult.INCOMPATIBLE : CompatibilityResult.COMPATIBLE; // don't expect to hit this ever. - } - if (copy == null) - return CompatibilityResult.INCOMPATIBLE; - - // copy here is potentially compatible with the target type and has its shape fully computed: i.e value/void compatibility is determined and result expressions have been gathered. - targetType = findGroundTargetType(this.enclosingScope, targetType, targetType, argumentsTypeElided()); - MethodBinding sam = targetType.getSingleAbstractMethod(this.enclosingScope, true); - if (sam == null || sam.problemId() == ProblemReasons.NoSuchSingleAbstractMethod) { - return CompatibilityResult.INCOMPATIBLE; - } - if (sam.returnType.id == TypeIds.T_void) { - if (!copy.voidCompatible) { - return CompatibilityResult.INCOMPATIBLE; - } - } else { - if (!copy.valueCompatible) { - if (reportShapeProblem) { - skope.problemReporter().missingValueFromLambda(this, sam.returnType); - return CompatibilityResult.REPORTED; - } - return CompatibilityResult.INCOMPATIBLE; - } - } - if (reportShapeProblem) - return CompatibilityResult.COMPATIBLE; // enough seen - - if (!isPertinentToApplicability(targetType, null)) - return CompatibilityResult.COMPATIBLE; - - // catch up on one check deferred via skipKosherCheck=true (only if pertinent for applicability) - if (!kosherDescriptor(this.enclosingScope, sam, false)) - return CompatibilityResult.INCOMPATIBLE; - - Expression [] returnExpressions = copy.resultExpressions; - for (int i = 0, length = returnExpressions.length; i < length; i++) { - if (sam.returnType.isProperType(true) // inference variables can reach here during nested inference - && this.enclosingScope.parameterCompatibilityLevel(returnExpressions[i].resolvedType, sam.returnType) == Scope.NOT_COMPATIBLE) { - if (!returnExpressions[i].isConstantValueOfTypeAssignableToType(returnExpressions[i].resolvedType, sam.returnType)) - if (sam.returnType.id != TypeIds.T_void || this.body instanceof Block) - return CompatibilityResult.INCOMPATIBLE; - } - } - return CompatibilityResult.COMPATIBLE; - } - - static class CopyFailureException extends RuntimeException { - private static final long serialVersionUID = 1L; - } - - private LambdaExpression cachedResolvedCopy(TypeBinding targetType, boolean anyTargetOk, boolean requireExceptionAnalysis, InferenceContext18 context, Scope outerScope) { - if (this.committed && outerScope instanceof BlockScope) { - this.enclosingScope = (BlockScope) outerScope; - // trust the result of any previous shape analysis: - if (this.copiesPerTargetType != null && !this.copiesPerTargetType.isEmpty()) { - LambdaExpression firstCopy = this.copiesPerTargetType.values().iterator().next(); - if (firstCopy != null) { - this.valueCompatible = firstCopy.valueCompatible; - this.voidCompatible = firstCopy.voidCompatible; - } - } - return this; - } - - targetType = findGroundTargetType(this.enclosingScope, targetType, targetType, argumentsTypeElided()); - if (targetType == null) - return null; - - MethodBinding sam = targetType.getSingleAbstractMethod(this.enclosingScope, true); - if (sam == null || !sam.isValidBinding()) - return null; - - if (sam.parameters.length != this.arguments.length) - return null; - - LambdaExpression copy = null; - if (this.copiesPerTargetType != null) { - copy = this.copiesPerTargetType.get(targetType); - if (copy == null) { - if (anyTargetOk && this.copiesPerTargetType.values().size() > 0) - copy = this.copiesPerTargetType.values().iterator().next(); - } - } - IErrorHandlingPolicy oldPolicy = this.enclosingScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy); - try { - if (copy == null) { - copy = copy(); - if (copy == null) - throw new CopyFailureException(); - if (InferenceContext18.DEBUG) { - System.out.println("Copy lambda "+this+" for target "+targetType.debugName()); //$NON-NLS-1$ //$NON-NLS-2$ - } - - copy.setExpressionContext(this.expressionContext); - copy.setExpectedType(targetType); - copy.inferenceContext = context; - TypeBinding type = copy.resolveType(this.enclosingScope, true); - if (type == null || !type.isValidBinding()) - return null; - - targetType = copy.expectedType; // possibly updated local types - if (this.copiesPerTargetType == null) - this.copiesPerTargetType = new HashMap<>(); - this.copiesPerTargetType.put(targetType, copy); - } - if (!requireExceptionAnalysis) - return copy; - if (copy.thrownExceptions == null) - if (!copy.hasIgnoredMandatoryErrors && !enclosingScopesHaveErrors()) - copy.analyzeExceptions(); - return copy; - } finally { - this.enclosingScope.problemReporter().switchErrorHandlingPolicy(oldPolicy); - } - } - - /** - * Get a resolved copy of this lambda for use by type inference, as to avoid spilling any premature - * type results into the original lambda. - * - * @param targetType the target functional type against which inference is attempted, must be a non-null valid functional type - * @return a resolved copy of 'this' or null if significant errors where encountered - */ - @Override - public LambdaExpression resolveExpressionExpecting(TypeBinding targetType, Scope skope, InferenceContext18 context) { - LambdaExpression copy = null; - try { - copy = cachedResolvedCopy(targetType, false, true, context, null /* to be safe we signal: not yet committed */); - } catch (CopyFailureException cfe) { - return null; - } - return copy; - } - - @Override - public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope skope) { - - // 15.12.2.5 - - if (super.sIsMoreSpecific(s, t, skope)) - return true; - - if (argumentsTypeElided() || t.findSuperTypeOriginatingFrom(s) != null) - return false; - TypeBinding sPrime = s; // uncaptured - s = s.capture(this.enclosingScope, this.sourceStart, this.sourceEnd); - MethodBinding sSam = s.getSingleAbstractMethod(this.enclosingScope, true); - if (sSam == null || !sSam.isValidBinding()) - return false; - MethodBinding tSam = t.getSingleAbstractMethod(this.enclosingScope, true); - if (tSam == null || !tSam.isValidBinding()) - return true; // See ORT8.test450415a for a case that slips through isCompatibleWith. - MethodBinding adapted = tSam.computeSubstitutedMethod(sSam, skope.environment()); - if (adapted == null) // not same type params - return false; - MethodBinding sSamPrime = sPrime.getSingleAbstractMethod(this.enclosingScope, true); - TypeBinding[] ps = adapted.parameters; // parameters of S adapted to type parameters of T - // parameters of S (without capture), adapted to type params of T - MethodBinding prime = tSam.computeSubstitutedMethod(sSamPrime, skope.environment()); - TypeBinding[] pPrimes = prime.parameters; - TypeBinding[] qs = tSam.parameters; - for (int i = 0; i < ps.length; i++) { - if (!qs[i].isCompatibleWith(ps[i]) || TypeBinding.notEquals(qs[i], pPrimes[i])) - return false; - } - TypeBinding r1 = adapted.returnType; // return type of S adapted to type parameters of T - TypeBinding r2 = tSam.returnType; - - if (r2.id == TypeIds.T_void) - return true; - - if (r1.id == TypeIds.T_void) - return false; - - // r1 <: r2 - if (r1.isCompatibleWith(r2, skope)) - return true; - - LambdaExpression copy; - try { - copy = cachedResolvedCopy(s, true /* any resolved copy is good */, false, null, null /*not yet committed*/); // we expect a cached copy - otherwise control won't reach here. - } catch (CopyFailureException cfe) { - if (this.assistNode) - return false; - throw cfe; - } - Expression [] returnExpressions = copy.resultExpressions; - int returnExpressionsLength = returnExpressions == null ? 0 : returnExpressions.length; - if (returnExpressionsLength > 0) { - int i; - // r1 is a primitive type, r2 is a reference type, and each result expression is a standalone expression (15.2) of a primitive type - if (r1.isBaseType() && !r2.isBaseType()) { - for (i = 0; i < returnExpressionsLength; i++) { - if (returnExpressions[i].isPolyExpression() || !returnExpressions[i].resolvedType.isBaseType()) - break; - } - if (i == returnExpressionsLength) - return true; - } - if (!r1.isBaseType() && r2.isBaseType()) { - for (i = 0; i < returnExpressionsLength; i++) { - if (returnExpressions[i].resolvedType.isBaseType()) - break; - } - if (i == returnExpressionsLength) - return true; - } - if (r1.isFunctionalInterface(this.enclosingScope) && r2.isFunctionalInterface(this.enclosingScope)) { - for (i = 0; i < returnExpressionsLength; i++) { - Expression resultExpression = returnExpressions[i]; - if (!resultExpression.sIsMoreSpecific(r1, r2, skope)) - break; - } - if (i == returnExpressionsLength) - return true; - } - } - return false; - } - - /** - * @return a virgin copy of `this' by reparsing the stashed textual form. - */ - LambdaExpression copy() { - final Parser parser = new Parser(this.enclosingScope.problemReporter(), false); - char [] source = new char [this.sourceEnd+1]; - System.arraycopy(this.text, 0, source, this.sourceStart, this.sourceEnd - this.sourceStart + 1); - LambdaExpression copy = (LambdaExpression) parser.parseLambdaExpression(source,this.sourceStart, this.sourceEnd - this.sourceStart + 1, - this.enclosingScope.referenceCompilationUnit(), false /* record line separators */); - - if (copy != null) { // ==> syntax errors == null - if (copy.sourceStart != this.sourceStart || copy.sourceEnd != this.sourceEnd) - return null; // something wrong - copy.original = this; - copy.assistNode = this.assistNode; - copy.enclosingScope = this.enclosingScope; - copy.text = this.text; // discard redundant textual copy - } - return copy; - } - - public void returnsExpression(Expression expression, TypeBinding resultType) { - if (this.original == this) // Not in overload resolution context. result expressions not relevant. - return; - if (this.body instanceof Expression && ((Expression) this.body).isTrulyExpression()) { - this.valueCompatible = resultType != null && resultType.id == TypeIds.T_void ? false : true; - this.voidCompatible = this.assistNode ? true : ((Expression) this.body).statementExpression(); // while code is still being written and completed, we can't ask if it is a statement - this.resultExpressions = new Expression[] { expression }; - return; - } - if (expression != null) { - this.returnsValue = true; - this.voidCompatible = false; - this.valueCompatible = !this.returnsVoid; - Expression [] returnExpressions = this.resultExpressions; - int resultsLength = returnExpressions.length; - System.arraycopy(returnExpressions, 0, returnExpressions = new Expression[resultsLength + 1], 0, resultsLength); - returnExpressions[resultsLength] = expression; - this.resultExpressions = returnExpressions; - } else { - this.returnsVoid = true; - this.valueCompatible = false; - this.voidCompatible = !this.returnsValue; - } - } - - @Override - public CompilationResult compilationResult() { - return this.compilationResult; - } - - @Override - public void abort(int abortLevel, CategorizedProblem problem) { - - switch (abortLevel) { - case AbortCompilation : - throw new AbortCompilation(this.compilationResult, problem); - case AbortCompilationUnit : - throw new AbortCompilationUnit(this.compilationResult, problem); - case AbortType : - throw new AbortType(this.compilationResult, problem); - default : - throw new AbortMethod(this.compilationResult, problem); - } - } - - @Override - public CompilationUnitDeclaration getCompilationUnitDeclaration() { - return this.enclosingScope == null ? null : this.enclosingScope.compilationUnitScope().referenceContext; - } - - @Override - public boolean hasErrors() { - return this.ignoreFurtherInvestigation; - } - - @Override - public void tagAsHavingErrors() { - this.ignoreFurtherInvestigation = true; - Scope parent = this.enclosingScope.parent; - while (parent != null) { - switch(parent.kind) { - case Scope.CLASS_SCOPE: - case Scope.METHOD_SCOPE: - ReferenceContext parentAST = parent.referenceContext(); - if (parentAST != this) { - parentAST.tagAsHavingErrors(); - return; - } - //$FALL-THROUGH$ - default: - parent = parent.parent; - break; - } - } - } - - @Override - public void tagAsHavingIgnoredMandatoryErrors(int problemId) { - switch (problemId) { - // 15.27.3 requires exception throw related errors to not influence congruence. Other errors should. Also don't abort shape analysis. - case IProblem.UnhandledExceptionOnAutoClose: - case IProblem.UnhandledExceptionInDefaultConstructor: - case IProblem.UnhandledException: - return; - /* The following structural problems can occur only because of target type imposition. Filter, so we can distinguish inherent errors - in explicit lambdas. This is to help decide whether to proceed with data/control flow analysis to discover shape. In case of inherent - errors, we will not call analyze code as it is not prepared to analyze broken programs. - */ - case IProblem.VoidMethodReturnsValue: - case IProblem.ShouldReturnValueHintMissingDefault: - case IProblem.ShouldReturnValue: - case IProblem.ReturnTypeMismatch: - case IProblem.IncompatibleLambdaParameterType: - case IProblem.lambdaParameterTypeMismatched: - case IProblem.lambdaSignatureMismatched: - case IProblem.LambdaDescriptorMentionsUnmentionable: - case IProblem.TargetTypeNotAFunctionalInterface: - case IProblem.illFormedParameterizationOfFunctionalInterface: - case IProblem.NoGenericLambda: - return; - default: - this.hasIgnoredMandatoryErrors = true; - MethodScope enclosingLambdaScope = this.scope == null ? null : this.scope.enclosingLambdaScope(); - while (enclosingLambdaScope != null) { - LambdaExpression enclosingLambda = (LambdaExpression) enclosingLambdaScope.referenceContext; - enclosingLambda.hasIgnoredMandatoryErrors = true; - enclosingLambdaScope = enclosingLambdaScope.enclosingLambdaScope(); - } - return; - } - } - - public Set getThrownExceptions() { - if (this.thrownExceptions == null) - return Collections.emptySet(); - return this.thrownExceptions; - } - - public void generateCode(ClassScope classScope, ClassFile classFile) { - int problemResetPC = 0; - classFile.codeStream.wideMode = false; - boolean restart = false; - do { - try { - problemResetPC = classFile.contentsOffset; - this.generateCode(classFile); - restart = false; - } catch (AbortMethod e) { - // Restart code generation if possible ... - if (e.compilationResult == CodeStream.RESTART_IN_WIDE_MODE) { - // a branch target required a goto_w, restart code generation in wide mode. - classFile.contentsOffset = problemResetPC; - classFile.methodCount--; - classFile.codeStream.resetInWideMode(); // request wide mode - restart = true; - } else if (e.compilationResult == CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE) { - classFile.contentsOffset = problemResetPC; - classFile.methodCount--; - classFile.codeStream.resetForCodeGenUnusedLocals(); - restart = true; - } else { - throw new AbortType(this.compilationResult, e.problem); - } - } - } while (restart); - } - - public void generateCode(ClassFile classFile) { - classFile.generateMethodInfoHeader(this.binding); - int methodAttributeOffset = classFile.contentsOffset; - int attributeNumber = classFile.generateMethodInfoAttributes(this.binding); - int codeAttributeOffset = classFile.contentsOffset; - classFile.generateCodeAttributeHeader(); - CodeStream codeStream = classFile.codeStream; - codeStream.reset(this, classFile); - // initialize local positions - this.scope.computeLocalVariablePositions(this.outerLocalVariablesSlotSize + (this.binding.isStatic() ? 0 : 1), codeStream); - if (this.outerLocalVariables != null) { - for (int i = 0, max = this.outerLocalVariables.length; i < max; i++) { - LocalVariableBinding argBinding; - codeStream.addVisibleLocalVariable(argBinding = this.outerLocalVariables[i]); - codeStream.record(argBinding); - argBinding.recordInitializationStartPC(0); - } - } - // arguments initialization for local variable debug attributes - if (this.arguments != null) { - for (int i = 0, max = this.arguments.length; i < max; i++) { - LocalVariableBinding argBinding; - codeStream.addVisibleLocalVariable(argBinding = this.arguments[i].binding); - argBinding.recordInitializationStartPC(0); - } - } - codeStream.pushPatternAccessTrapScope(this.scope); - if (this.body instanceof Block) { - this.body.generateCode(this.scope, codeStream); - if ((this.bits & ASTNode.NeedFreeReturn) != 0) { - codeStream.return_(); - } - } else { - Expression expression = (Expression) this.body; - expression.generateCode(this.scope, codeStream, true); - if (this.binding.returnType == TypeBinding.VOID) { - codeStream.return_(); - } else { - codeStream.generateReturnBytecode(expression); - } - } - // See https://github.com/eclipse-jdt/eclipse.jdt.core/issues/1796#issuecomment-1933458054 - codeStream.exitUserScope(this.scope, lvb -> !lvb.isParameter()); - codeStream.handleRecordAccessorExceptions(this.scope); - // local variable attributes - codeStream.exitUserScope(this.scope); - codeStream.recordPositionsFrom(0, this.sourceEnd); // WAS declarationSourceEnd. - try { - classFile.completeCodeAttribute(codeAttributeOffset, this.scope); - } catch(NegativeArraySizeException e) { - throw new AbortMethod(this.scope.referenceCompilationUnit().compilationResult, null); - } - attributeNumber++; - - classFile.completeMethodInfo(this.binding, methodAttributeOffset, attributeNumber); - } - - public void addSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) { - - if (this.original != this || this.binding == null) - return; // Do not bother tracking outer locals for clones created during overload resolution. - - SyntheticArgumentBinding syntheticLocal = null; - int newSlot = this.outerLocalVariables.length; - for (int i = 0; i < newSlot; i++) { - if (this.outerLocalVariables[i].actualOuterLocalVariable == actualOuterLocalVariable) - return; - } - System.arraycopy(this.outerLocalVariables, 0, this.outerLocalVariables = new SyntheticArgumentBinding[newSlot + 1], 0, newSlot); - this.outerLocalVariables[newSlot] = syntheticLocal = new SyntheticArgumentBinding(actualOuterLocalVariable); - syntheticLocal.resolvedPosition = this.outerLocalVariablesSlotSize; // may need adjusting later if we need to generate an instance method for the lambda. - syntheticLocal.declaringScope = this.scope; - int parameterCount = this.binding.parameters.length; - TypeBinding [] newParameters = new TypeBinding[parameterCount + 1]; - newParameters[newSlot] = actualOuterLocalVariable.type; - for (int i = 0, j = 0; i < parameterCount; i++, j++) { - if (i == newSlot) j++; - newParameters[j] = this.binding.parameters[i]; - } - this.binding.parameters = newParameters; - switch (syntheticLocal.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - this.outerLocalVariablesSlotSize += 2; - break; - default : - this.outerLocalVariablesSlotSize++; - break; - } - } - - public SyntheticArgumentBinding addSyntheticArgument(ReferenceBinding enclosingType) { - - if (this.original != this || this.binding == null) - return null; // Do not bother tracking outer locals for clones created during overload resolution. - - SyntheticArgumentBinding syntheticLocal = null; - int newSlot = this.outerLocalVariables.length; - System.arraycopy(this.outerLocalVariables, 0, this.outerLocalVariables = new SyntheticArgumentBinding[newSlot + 1], 0, newSlot); - this.outerLocalVariables[newSlot] = syntheticLocal = new SyntheticArgumentBinding(enclosingType); - syntheticLocal.resolvedPosition = this.outerLocalVariablesSlotSize; // may need adjusting later if we need to generate an instance method for the lambda. - syntheticLocal.declaringScope = this.scope; - int parameterCount = this.binding.parameters.length; - TypeBinding [] newParameters = new TypeBinding[parameterCount + 1]; - newParameters[newSlot] = enclosingType; - for (int i = 0, j = 0; i < parameterCount; i++, j++) { - if (i == newSlot) j++; - newParameters[j] = this.binding.parameters[i]; - } - this.binding.parameters = newParameters; - switch (syntheticLocal.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - this.outerLocalVariablesSlotSize += 2; - break; - default : - this.outerLocalVariablesSlotSize++; - break; - } - return syntheticLocal; - } - public SyntheticArgumentBinding getSyntheticArgument(LocalVariableBinding actualOuterLocalVariable) { - for (int i = 0, length = this.outerLocalVariables == null ? 0 : this.outerLocalVariables.length; i < length; i++) - if (this.outerLocalVariables[i].actualOuterLocalVariable == actualOuterLocalVariable) - return this.outerLocalVariables[i]; - return null; - } - - // Return the actual method binding devoid of synthetics. - @Override - public MethodBinding getMethodBinding() { - if (this.actualMethodBinding == null) { - if (this.binding != null) { - // Get rid of the synthetic arguments added via addSyntheticArgument() - TypeBinding[] newParams = null; - if (this.binding instanceof SyntheticMethodBinding && this.outerLocalVariables.length > 0) { - newParams = new TypeBinding[this.binding.parameters.length - this.outerLocalVariables.length]; - System.arraycopy(this.binding.parameters, this.outerLocalVariables.length, newParams, 0, newParams.length); - } else { - newParams = this.binding.parameters; - } - this.actualMethodBinding = new MethodBinding(this.binding.modifiers, this.binding.selector, - this.binding.returnType, newParams, this.binding.thrownExceptions, this.binding.declaringClass); - this.actualMethodBinding.tagBits = this.binding.tagBits; - } else { - this.actualMethodBinding = new ProblemMethodBinding(CharOperation.NO_CHAR, null, ProblemReasons.NoSuchSingleAbstractMethod); - } - } - return this.actualMethodBinding; - } - - @Override - public int diagnosticsSourceEnd() { - return this.body instanceof Block ? this.arrowPosition : this.sourceEnd; - } - - public TypeBinding[] getMarkerInterfaces() { - if (this.expectedType instanceof IntersectionTypeBinding18) { - Set markerBindings = new LinkedHashSet(); - IntersectionTypeBinding18 intersectionType = (IntersectionTypeBinding18)this.expectedType; - TypeBinding[] intersectionTypes = intersectionType.intersectingTypes; - TypeBinding samType = intersectionType.getSAMType(this.enclosingScope); - for (int i = 0,max = intersectionTypes.length; i < max; i++) { - TypeBinding typeBinding = intersectionTypes[i]; - if (!typeBinding.isInterface() // only interfaces - || TypeBinding.equalsEquals(samType, typeBinding) // except for the samType itself - || typeBinding.id == TypeIds.T_JavaIoSerializable) // but Serializable is captured as a bitflag - { - continue; - } - markerBindings.add(typeBinding); - } - if (markerBindings.size() > 0) { - return (TypeBinding[])markerBindings.toArray(new TypeBinding[markerBindings.size()]); - } - } - return null; - } - - public ReferenceBinding getTypeBinding() { - - if (this.classType != null || this.resolvedType == null) - return null; - - class LambdaTypeBinding extends ReferenceBinding { - @Override - public MethodBinding[] methods() { - return new MethodBinding [] { getMethodBinding() }; - } - @Override - public char[] sourceName() { - return TypeConstants.LAMBDA_TYPE; - } - @Override - public ReferenceBinding superclass() { - return LambdaExpression.this.scope.getJavaLangObject(); - } - @Override - public ReferenceBinding[] superInterfaces() { - return new ReferenceBinding[] { (ReferenceBinding) LambdaExpression.this.resolvedType }; - } - @Override - public char[] computeUniqueKey() { - return LambdaExpression.this.descriptor.declaringClass.computeUniqueKey(); - } - @Override - public String toString() { - StringBuilder output = new StringBuilder("()->{} implements "); //$NON-NLS-1$ - output.append(LambdaExpression.this.descriptor.declaringClass.sourceName()); - output.append('.'); - output.append(LambdaExpression.this.descriptor.toString()); - return output.toString(); - } - } - return this.classType = new LambdaTypeBinding(); - } - - public void addLocalType(LocalTypeBinding localTypeBinding) { - if (this.localTypes == null) - this.localTypes = new HashMap<>(); - this.localTypes.put(localTypeBinding.sourceStart, localTypeBinding); - } - - /** - * During inference, several copies of a lambda may be created. - * If a lambda body contains a local type declaration, one binding may be created - * within each of the lambda copies. Once inference finished, we need to map all - * such local type bindings to the instance from the correct lambda copy. - *

    - * When a local type binding occurs as a field of another type binding (e.g., - * type argument), the local type will be replaced in-place, assuming that the - * previous binding should never escape the context of resolving this lambda. - *

    - */ - static class LocalTypeSubstitutor extends Substitutor { - Map localTypes2; - - public LocalTypeSubstitutor(Map localTypes, MethodBinding methodBinding) { - this.localTypes2 = localTypes; - if (methodBinding != null && methodBinding.isStatic()) - this.staticContext = methodBinding.declaringClass; - } - - @Override - public TypeBinding substitute(Substitution substitution, TypeBinding originalType) { - if (originalType.isLocalType()) { - LocalTypeBinding orgLocal = (LocalTypeBinding) originalType.original(); - MethodScope lambdaScope2 = orgLocal.scope.enclosingLambdaScope(); - if (lambdaScope2 != null) { - // local type within a lambda may need replacement: - TypeBinding substType = this.localTypes2.get(orgLocal.sourceStart); - if (substType != null && substType != orgLocal) { //$IDENTITY-COMPARISON$ - orgLocal.transferConstantPoolNameTo(substType); - return substType; - } - } - return originalType; - } - return super.substitute(substitution, originalType); - } - } - - boolean updateLocalTypes() { - if (this.descriptor == null || this.localTypes == null) - return false; - LocalTypeSubstitutor substor = new LocalTypeSubstitutor(this.localTypes, null/*lambda method is never static*/); - NullSubstitution subst = new NullSubstitution(this.scope.environment()); - updateLocalTypesInMethod(this.binding, substor, subst); - updateLocalTypesInMethod(this.descriptor, substor, subst); - this.resolvedType = substor.substitute(subst, this.resolvedType); - this.expectedType = substor.substitute(subst, this.expectedType); - return true; - } - - /** - * Perform substitution with a {@link LocalTypeSubstitutor} on all types mentioned in the given method binding. - */ - boolean updateLocalTypesInMethod(MethodBinding method) { - if (this.localTypes == null) - return false; - updateLocalTypesInMethod(method, new LocalTypeSubstitutor(this.localTypes, method), new NullSubstitution(this.scope.environment())); - return true; - } - - public static void updateLocalTypesInMethod(MethodBinding method, Substitutor substor, Substitution subst) { - method.declaringClass = (ReferenceBinding) substor.substitute(subst, method.declaringClass); - method.returnType = substor.substitute(subst, method.returnType); - for (int i = 0; i < method.parameters.length; i++) { - method.parameters[i] = substor.substitute(subst, method.parameters[i]); - } - if (method instanceof ParameterizedGenericMethodBinding) { - ParameterizedGenericMethodBinding pgmb = (ParameterizedGenericMethodBinding) method; - for (int i = 0; i < pgmb.typeArguments.length; i++) { - pgmb.typeArguments[i] = substor.substitute(subst, pgmb.typeArguments[i]); - } - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Literal.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Literal.java deleted file mode 100644 index 9735767..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Literal.java +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public abstract class Literal extends Expression { - - public Literal(int s, int e) { - - this.sourceStart = s; - this.sourceEnd = e; - } - - @Override - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - return flowInfo; - } - - public abstract void computeConstant(); - - public abstract TypeBinding literalType(BlockScope scope); - - @Override - public StringBuilder printExpression(int indent, StringBuilder output){ - - return output.append(source()); - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - // compute the real value, which must range its type's range - this.resolvedType = literalType(scope); - - // in case of error, constant did remain null - computeConstant(); - if (this.constant == null) { - scope.problemReporter().constantOutOfRange(this, this.resolvedType); - this.constant = Constant.NotAConstant; - } - return this.resolvedType; - } - - public abstract char[] source(); -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java deleted file mode 100644 index 63e70a7..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LocalDeclaration.java +++ /dev/null @@ -1,536 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * 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 - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 358903 - Filter practically unimportant resource leak warnings - * bug 370639 - [compiler][resource] restore the default for resource leak warnings - * bug 365859 - [compiler][null] distinguish warnings based on flow analysis vs. null annotations - * bug 388996 - [compiler][resource] Incorrect 'potential resource leak' - * bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional - * bug 395002 - Self bound generic class doesn't resolve bounds properly for wildcards for certain parametrisation. - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 400761 - [compiler][null] null may be return as boolean without a diagnostic - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 430150 - [1.8][null] stricter checking against type variables - * Bug 453483 - [compiler][null][loop] Improve null analysis for loops - * Jesper S Moller - Contributions for - * Bug 378674 - "The method can be declared as static" is wrong - * Bug 527554 - [18.3] Compiler support for JEP 286 Local-Variable Type - * Bug 529556 - [18.3] Add content assist support for 'var' as a type - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 409250 - [1.8][compiler] Various loose ends in 308 code generation - * Bug 426616 - [1.8][compiler] Type Annotations, multiple problems - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.ASSIGNMENT_CONTEXT; -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.VANILLA_CONTEXT; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.AnnotationContext; -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.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBindingVisitor; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; -import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; - -public class LocalDeclaration extends AbstractVariableDeclaration { - - public LocalVariableBinding binding; - - public LocalDeclaration( - char[] name, - int sourceStart, - int sourceEnd) { - - this.name = name; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - this.declarationEnd = sourceEnd; - } - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // record variable initialization if any - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - this.bits |= ASTNode.IsLocalDeclarationReachable; // only set if actually reached - } - if (this.initialization == null) { - return flowInfo; - } - this.initialization.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - - FlowInfo preInitInfo = null; - CompilerOptions compilerOptions = currentScope.compilerOptions(); - boolean shouldAnalyseResource = this.binding != null - && flowInfo.reachMode() == FlowInfo.REACHABLE - && compilerOptions.analyseResourceLeaks - && FakedTrackingVariable.isAnyCloseable(this.initialization.resolvedType); - if (shouldAnalyseResource) { - preInitInfo = flowInfo.unconditionalCopy(); - // analysis of resource leaks needs additional context while analyzing the RHS: - FakedTrackingVariable.preConnectTrackerAcrossAssignment(this, this.binding, this.initialization, flowInfo, - compilerOptions.isAnnotationBasedResourceAnalysisEnabled); - } - - flowInfo = - this.initialization - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - - if (shouldAnalyseResource) - FakedTrackingVariable.handleResourceAssignment(currentScope, preInitInfo, flowInfo, flowContext, this, this.initialization, this.binding); - else - FakedTrackingVariable.cleanUpAfterAssignment(currentScope, Binding.LOCAL, this.initialization); - - int nullStatus = this.initialization.nullStatus(flowInfo, flowContext); - if (!flowInfo.isDefinitelyAssigned(this.binding)){// for local variable debug attributes - this.bits |= FirstAssignmentToLocal; - } else { - this.bits &= ~FirstAssignmentToLocal; // int i = (i = 0); - } - flowInfo.markAsDefinitelyAssigned(this.binding); - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { - nullStatus = NullAnnotationMatching.checkAssignment(currentScope, flowContext, this.binding, flowInfo, nullStatus, this.initialization, this.initialization.resolvedType); - } - if ((this.binding.type.tagBits & TagBits.IsBaseType) == 0) { - flowInfo.markNullStatus(this.binding, nullStatus); - // no need to inform enclosing try block since its locals won't get - // known by the finally block - } - return flowInfo; -} - - public void checkModifiers() { - - //only potential valid modifier is <> - if (((this.modifiers & ExtraCompilerModifiers.AccJustFlag) & ~ClassFileConstants.AccFinal) != 0) - //AccModifierProblem -> other (non-visibility problem) - //AccAlternateModifierProblem -> duplicate modifier - //AccModifierProblem | AccAlternateModifierProblem -> visibility problem" - - this.modifiers = (this.modifiers & ~ExtraCompilerModifiers.AccAlternateModifierProblem) | ExtraCompilerModifiers.AccModifierProblem; - } - - /** - * Code generation for a local declaration: - * i.e. normal assignment to a local variable + unused variable handling - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - // even if not reachable, variable must be added to visible if allocated (28298) - if (this.binding.resolvedPosition != -1) { - codeStream.addVisibleLocalVariable(this.binding); - } - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - - // something to initialize? - generateInit: { - if (this.initialization == null) - break generateInit; - // forget initializing unused or final locals set to constant value (final ones are inlined) - if (this.binding.resolvedPosition < 0) { - if (this.initialization.constant != Constant.NotAConstant) - break generateInit; - // if binding unused generate then discard the value - this.initialization.generateCode(currentScope, codeStream, false); - break generateInit; - } - this.initialization.generateCode(currentScope, codeStream, true); - // 26903, need extra cast to store null in array local var - if (this.binding.type.isArrayType() - && ((this.initialization instanceof CastExpression) // arrayLoc = (type[])null - && (((CastExpression)this.initialization).innermostCastedExpression().resolvedType == TypeBinding.NULL))){ - codeStream.checkcast(this.binding.type); - } - codeStream.store(this.binding, false); - if ((this.bits & ASTNode.FirstAssignmentToLocal) != 0) { - /* Variable may have been initialized during the code initializing it - e.g. int i = (i = 1); - */ - this.binding.recordInitializationStartPC(codeStream.position); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind() - */ - @Override - public int getKind() { - return LOCAL_VARIABLE; - } - - // for local variables - public void getAllAnnotationContexts(int targetType, LocalVariableBinding localVariable, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, localVariable, allAnnotationContexts); - this.traverseWithoutInitializer(collector, (BlockScope) null); - } - - // for arguments - public void getAllAnnotationContexts(int targetType, int parameterIndex, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, parameterIndex, allAnnotationContexts); - this.traverse(collector, (BlockScope) null); - } - - public boolean isArgument() { - return false; - } - public boolean isReceiver() { - return false; - } - public TypeBinding patchType(TypeBinding newType) { - // Perform upwards projection on type wrt mentioned type variables - TypeBinding[] mentionedTypeVariables= findCapturedTypeVariables(newType); - if (mentionedTypeVariables != null && mentionedTypeVariables.length > 0) { - newType = newType.upwardsProjection(this.binding.declaringScope, mentionedTypeVariables); - } - this.type.resolvedType = newType; - if (this.binding != null) { - this.binding.type = newType; - this.binding.markInitialized(); - } - return this.type.resolvedType; - } - - private TypeVariableBinding[] findCapturedTypeVariables(TypeBinding typeBinding) { - final Set mentioned = new HashSet<>(); - TypeBindingVisitor.visit(new TypeBindingVisitor() { - @Override - public boolean visit(TypeVariableBinding typeVariable) { - if (typeVariable.isCapture()) - mentioned.add(typeVariable); - return super.visit(typeVariable); - } - }, typeBinding); - if (mentioned.isEmpty()) return null; - return mentioned.toArray(new TypeVariableBinding[mentioned.size()]); - } - - private static Expression findPolyExpression(Expression e) { - // This is simpler than using an ASTVisitor, since we only care about a very few select cases. - if (e instanceof FunctionalExpression) { - return e; - } - if (e instanceof ConditionalExpression) { - ConditionalExpression ce = (ConditionalExpression)e; - Expression candidate = findPolyExpression(ce.valueIfTrue); - if (candidate == null) { - candidate = findPolyExpression(ce.valueIfFalse); - } - if (candidate != null) return candidate; - } - if (e instanceof SwitchExpression) { - SwitchExpression se = (SwitchExpression)e; - for (Expression re : se.resultExpressions) { - Expression candidate = findPolyExpression(re); - if (candidate != null) return candidate; - } - } - return null; - } - - @Override - public void resolve(BlockScope scope) { - resolve(scope, false); - } - public void resolve(BlockScope scope, boolean isPatternVariable) { // prescan NNBD - handleNonNullByDefault(scope, this.annotations, this); - - if (!isPatternVariable && (this.bits & ASTNode.IsForeachElementVariable) == 0 && this.initialization == null && this.isUnnamed(scope)) { - scope.problemReporter().unnamedVariableMustHaveInitializer(this); - } - - TypeBinding variableType = null; - boolean variableTypeInferenceError = false; - boolean isTypeNameVar = isTypeNameVar(scope); - if (isTypeNameVar && !isPatternVariable) { - if (this.type.isParameterizedTypeReference()) { - scope.problemReporter().varCannotBeUsedWithTypeArguments(this.type); - } - if ((this.bits & ASTNode.IsForeachElementVariable) == 0) { - // infer a type from the initializer - if (this.initialization != null) { - variableType = checkInferredLocalVariableInitializer(scope); - variableTypeInferenceError = variableType != null; - } else { - // That's always an error - scope.problemReporter().varLocalWithoutInitizalier(this); - variableType = scope.getJavaLangObject(); - variableTypeInferenceError = true; - } - } - } else { - variableType = this.type == null ? null : this.type.resolveType(scope, true /* check bounds*/); - } - - if (this.type != null) { - this.bits |= (this.type.bits & ASTNode.HasTypeAnnotations); - checkModifiers(); - if (variableType != null) { - if (variableType == TypeBinding.VOID) { - scope.problemReporter().variableTypeCannotBeVoid(this); - return; - } - if (variableType.isArrayType() && ((ArrayBinding) variableType).leafComponentType == TypeBinding.VOID) { - scope.problemReporter().variableTypeCannotBeVoidArray(this); - return; - } - } - - Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/); - if (existingVariable != null && existingVariable.isValidBinding() && !this.isUnnamed(scope)) { - boolean localExists = existingVariable instanceof LocalVariableBinding; - if (localExists && (this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope() && this.hiddenVariableDepth == 0) { - scope.problemReporter().lambdaRedeclaresLocal(this); - } else if (localExists && this.hiddenVariableDepth == 0) { - if (existingVariable.isPatternVariable()) { - scope.problemReporter().illegalRedeclarationOfPatternVar((LocalVariableBinding) existingVariable, this); - } else { - scope.problemReporter().redefineLocal(this); - } - } else { - scope.problemReporter().localVariableHiding(this, existingVariable, false); - } - } - } - if ((this.modifiers & ClassFileConstants.AccFinal)!= 0 && this.initialization == null) { - this.modifiers |= ExtraCompilerModifiers.AccBlankFinal; - } - if (isTypeNameVar) { - // Create binding for the initializer's type - // In order to resolve self-referential initializers, we must declare the variable with a placeholder type (j.l.Object), and then patch it later - this.binding = new LocalVariableBinding(this, variableType != null ? variableType : scope.getJavaLangObject(), this.modifiers, false) { - private boolean isInitialized = false; - - @Override - public void markReferenced() { - if (! this.isInitialized) { - scope.problemReporter().varLocalReferencesItself(LocalDeclaration.this); - this.type = null; - this.isInitialized = true; // Quell additional type errors - } - } - @Override - public void markInitialized() { - this.isInitialized = true; - } - }; - } else { - // create a binding from the specified type - this.binding = new LocalVariableBinding(this, variableType, this.modifiers, false /*isArgument*/); - } - scope.addLocalVariable(this.binding); - this.binding.setConstant(Constant.NotAConstant); - // allow to recursivelly target the binding.... - // the correct constant is harmed if correctly computed at the end of this method - - if (variableType == null) { - if (this.initialization != null) { - if (this.initialization instanceof CastExpression) { - ((CastExpression)this.initialization).setVarTypeDeclaration(true); - } - this.initialization.resolveType(scope); // want to report all possible errors - if (isTypeNameVar && this.initialization.resolvedType != null) { - if (TypeBinding.equalsEquals(TypeBinding.NULL, this.initialization.resolvedType)) { - scope.problemReporter().varLocalInitializedToNull(this); - variableTypeInferenceError = true; - } else if (TypeBinding.equalsEquals(TypeBinding.VOID, this.initialization.resolvedType)) { - scope.problemReporter().varLocalInitializedToVoid(this); - variableTypeInferenceError = true; - } - variableType = patchType(this.initialization.resolvedType); - } else { - variableTypeInferenceError = true; - } - } - } - this.binding.markInitialized(); - if (variableTypeInferenceError) { - return; - } - boolean resolveAnnotationsEarly = false; - if (scope.environment().usesNullTypeAnnotations() - && !isTypeNameVar // 'var' does not provide a target type - && variableType != null && variableType.isValidBinding()) { - resolveAnnotationsEarly = this.initialization instanceof Invocation - || this.initialization instanceof ConditionalExpression - || this.initialization instanceof SwitchExpression - || this.initialization instanceof ArrayInitializer; - } - if (resolveAnnotationsEarly) { - // these are definitely no constants, so resolving annotations early should be safe - resolveAnnotations(scope, this.annotations, this.binding, true); - // for type inference having null annotations upfront gives better results - variableType = this.type.resolvedType; - } - if (this.initialization != null) { - if (this.initialization instanceof ArrayInitializer) { - TypeBinding initializationType = this.initialization.resolveTypeExpecting(scope, variableType); - if (initializationType != null) { - ((ArrayInitializer) this.initialization).binding = (ArrayBinding) initializationType; - this.initialization.computeConversion(scope, variableType, initializationType); - } - } else { - this.initialization.setExpressionContext(isTypeNameVar ? VANILLA_CONTEXT : ASSIGNMENT_CONTEXT); - this.initialization.setExpectedType(variableType); - TypeBinding initializationType = this.initialization.resolvedType != null ? this.initialization.resolvedType : this.initialization.resolveType(scope); - if (initializationType != null) { - if (TypeBinding.notEquals(variableType, initializationType)) // must call before computeConversion() and typeMismatchError() - scope.compilationUnitScope().recordTypeConversion(variableType, initializationType); - if (this.initialization.isConstantValueOfTypeAssignableToType(initializationType, variableType) - || initializationType.isCompatibleWith(variableType, scope)) { - this.initialization.computeConversion(scope, variableType, initializationType); - if (initializationType.needsUncheckedConversion(variableType)) { - scope.problemReporter().unsafeTypeConversion(this.initialization, initializationType, variableType); - } - if (this.initialization instanceof CastExpression - && (this.initialization.bits & ASTNode.UnnecessaryCast) == 0) { - CastExpression.checkNeedForAssignedCast(scope, variableType, (CastExpression) this.initialization); - } - } else if (isBoxingCompatible(initializationType, variableType, this.initialization, scope)) { - this.initialization.computeConversion(scope, variableType, initializationType); - if (this.initialization instanceof CastExpression - && (this.initialization.bits & ASTNode.UnnecessaryCast) == 0) { - CastExpression.checkNeedForAssignedCast(scope, variableType, (CastExpression) this.initialization); - } - } else { - if ((variableType.tagBits & TagBits.HasMissingType) == 0) { - // if problem already got signaled on type, do not report secondary problem - scope.problemReporter().typeMismatchError(initializationType, variableType, this.initialization, null); - } - } - } - } - // check for assignment with no effect - if (this.binding == Expression.getDirectBinding(this.initialization)) { - scope.problemReporter().assignmentHasNoEffect(this, this.name); - } - // change the constant in the binding when it is final - // (the optimization of the constant propagation will be done later on) - // cast from constant actual type to variable type - this.binding.setConstant( - this.binding.isFinal() - ? this.initialization.constant.castTo((variableType.id << 4) + this.initialization.constant.typeID()) - : Constant.NotAConstant); - } - // if init could be a constant only resolve annotation at the end, for constant to be positioned before (96991) - if (!resolveAnnotationsEarly) - resolveAnnotations(scope, this.annotations, this.binding, true); - Annotation.isTypeUseCompatible(this.type, scope, this.annotations); - validateNullAnnotations(scope); - } - - void validateNullAnnotations(BlockScope scope) { - if (!scope.validateNullAnnotation(this.binding.tagBits, this.type, this.annotations)) - this.binding.tagBits &= ~TagBits.AnnotationNullMASK; - } - - /* - * Checks the initializer for simple errors, and reports an error as needed. If error is found, - * returns a reasonable match for further type checking. - */ - private TypeBinding checkInferredLocalVariableInitializer(BlockScope scope) { - TypeBinding errorType = null; - if (this.initialization instanceof ArrayInitializer) { - scope.problemReporter().varLocalCannotBeArrayInitalizers(this); - errorType = scope.createArrayType(scope.getJavaLangObject(), 1); // Treat as array of anything - } else { - // Catch-22: isPolyExpression() is not reliable BEFORE resolveType, so we need to peek to suppress the errors - Expression polyExpression = findPolyExpression(this.initialization); - if (polyExpression instanceof ReferenceExpression) { - scope.problemReporter().varLocalCannotBeMethodReference(this); - errorType = TypeBinding.NULL; - } else if (polyExpression != null) { // Should be instanceof LambdaExpression, but this is safer - scope.problemReporter().varLocalCannotBeLambda(this); - errorType = TypeBinding.NULL; - } - } - if (this.type.dimensions() > 0 || this.type.extraDimensions() > 0) { - scope.problemReporter().varLocalCannotBeArray(this); - errorType = scope.createArrayType(scope.getJavaLangObject(), 1); // This is just to quell some warnings - } - if ((this.bits & ASTNode.IsAdditionalDeclarator) != 0) { - scope.problemReporter().varLocalMultipleDeclarators(this); - errorType = this.initialization.resolveType(scope); - } - return errorType; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, scope); - } - if (this.type != null) { - this.type.traverse(visitor, scope); - } - if (this.initialization != null) - this.initialization.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } - - private void traverseWithoutInitializer(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, scope); - } - this.type.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } - - public boolean isRecoveredFromLoneIdentifier() { // recovered from lonely identifier or identifier cluster ? - return this.name == RecoveryScanner.FAKE_IDENTIFIER && - (this.type instanceof SingleTypeReference || (this.type instanceof QualifiedTypeReference && !(this.type instanceof ArrayQualifiedTypeReference))) && this.initialization == null && !this.type.isBaseTypeReference(); - } - - public boolean isTypeNameVar(Scope scope) { - return this.type != null && this.type.isTypeNameVar(scope); - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java deleted file mode 100644 index 9f63c72..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LongLiteral.java +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.impl.LongConstant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; - -public class LongLiteral extends NumberLiteral { - - private static final char[] HEXA_MIN_VALUE = "0x8000000000000000L".toCharArray(); //$NON-NLS-1$ - private static final char[] HEXA_MINUS_ONE_VALUE = "0xffffffffffffffffL".toCharArray(); //$NON-NLS-1$ - private static final char[] OCTAL_MIN_VALUE = "01000000000000000000000L".toCharArray(); //$NON-NLS-1$ - private static final char[] OCTAL_MINUS_ONE_VALUE = "01777777777777777777777L".toCharArray(); //$NON-NLS-1$ - private static final char[] DECIMAL_MIN_VALUE = "9223372036854775808L".toCharArray(); //$NON-NLS-1$ - private static final char[] DECIMAL_MAX_VALUE = "9223372036854775807L".toCharArray(); //$NON-NLS-1$ - - private final char[] reducedForm; // no underscores - - public static LongLiteral buildLongLiteral(char[] token, int s, int e) { - // remove '_' and prefix '0' first - char[] longReducedToken = removePrefixZerosAndUnderscores(token, true); - switch(longReducedToken.length) { - case 19 : - // 0x8000000000000000L - if (CharOperation.equals(longReducedToken, HEXA_MIN_VALUE)) { - return new LongLiteralMinValue(token, longReducedToken != token ? longReducedToken : null, s, e); - } - break; - case 24 : - // 01000000000000000000000L - if (CharOperation.equals(longReducedToken, OCTAL_MIN_VALUE)) { - return new LongLiteralMinValue(token, longReducedToken != token ? longReducedToken : null, s, e); - } - break; - } - return new LongLiteral(token, longReducedToken != token ? longReducedToken : null, s, e); - } - -LongLiteral(char[] token, char[] reducedForm, int start, int end) { - super(token, start, end); - this.reducedForm = reducedForm; -} -public LongLiteral convertToMinValue() { - if (((this.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT) != 0) { - return this; - } - char[] token = this.reducedForm != null ? this.reducedForm : this.source; - switch(token.length) { - case 20 : - // 9223372036854775808L - if (CharOperation.equals(token, DECIMAL_MIN_VALUE, false)) { - return new LongLiteralMinValue(this.source, this.reducedForm, this.sourceStart, this.sourceEnd); - } - break; - } - return this; -} -@Override -public void computeConstant() { - char[] token = this.reducedForm != null ? this.reducedForm : this.source; - int tokenLength = token.length; - int length = tokenLength - 1; - int radix = 10; - int j = 0; - if (token[0] == '0') { - if (length == 1) { - this.constant = LongConstant.fromValue(0L); - return; - } - if ((token[1] == 'x') || (token[1] == 'X')) { - radix = 16; - j = 2; - } else if ((token[1] == 'b') || (token[1] == 'B')) { - radix = 2; - j = 2; - } else { - radix = 8; - j = 1; - } - } - switch(radix) { - case 2 : - if ((length - 2) > 64) { // remove 0b or 0B - return; /*constant stays null*/ - } - computeValue(token, length, radix, j); - break; - case 16 : - if (tokenLength <= 19) { - if (CharOperation.equals(token, HEXA_MINUS_ONE_VALUE)) { - this.constant = LongConstant.fromValue(-1L); - return; - } - computeValue(token, length, radix, j); - } - break; - case 10 : - if (tokenLength > DECIMAL_MAX_VALUE.length - || (tokenLength == DECIMAL_MAX_VALUE.length - && CharOperation.compareTo(token, DECIMAL_MAX_VALUE, 0, length) > 0)) { - return; /*constant stays null*/ - } - computeValue(token, length, radix, j); - break; - case 8 : - if (tokenLength <= 24) { - if (tokenLength == 24 && token[j] > '1') { - return; /*constant stays null*/ - } - if (CharOperation.equals(token, OCTAL_MINUS_ONE_VALUE)) { - this.constant = LongConstant.fromValue(-1L); - return; - } - computeValue(token, length, radix, j); - } - break; - } -} -private void computeValue(char[] token, int tokenLength, int radix, int j) { - int digitValue; - long computedValue = 0; - while (j < tokenLength) { - if ((digitValue = ScannerHelper.digit(token[j++],radix)) < 0) { - return; /*constant stays null*/ - } - computedValue = (computedValue * radix) + digitValue ; - } - this.constant = LongConstant.fromValue(computedValue); -} -/** - * Code generation for long literal - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public TypeBinding literalType(BlockScope scope) { - return TypeBinding.LONG; -} -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java deleted file mode 100644 index 183ca98..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/LongLiteralMinValue.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.impl.*; - -public class LongLiteralMinValue extends LongLiteral { - - final static char[] CharValue = new char[]{'-', '9','2','2','3','3','7','2','0','3','6','8','5','4','7','7','5','8','0','8','L'}; - -public LongLiteralMinValue(char[] token, char[] reducedForm, int start, int end) { - super(token, reducedForm, start, end); - this.constant = LongConstant.fromValue(Long.MIN_VALUE); -} -@Override -public void computeConstant() { - /*precomputed at creation time*/} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java deleted file mode 100644 index 5272a10..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MagicLiteral.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -public abstract class MagicLiteral extends Literal { - - public MagicLiteral(int start , int end) { - - super(start,end); - } - - @Override - public boolean isValidJavaStatement(){ - - return false ; - } - - @Override - public char[] source() { - - return null; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MarkerAnnotation.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MarkerAnnotation.java deleted file mode 100644 index a86cd21..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MarkerAnnotation.java +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2012 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -/* - * Created on 2004-03-11 - * - * To change the template for this generated file go to - * Window - Preferences - Java - Code Generation - Code and Comments - */ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class MarkerAnnotation extends Annotation { - - public MarkerAnnotation(TypeReference type, int sourceStart) { - this.type = type; - this.sourceStart = sourceStart; - this.sourceEnd = type.sourceEnd; - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.Annotation#memberValuePairs() - */ - @Override - public MemberValuePair[] memberValuePairs() { - return NoValuePairs; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.type != null) { - this.type.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.type != null) { - this.type.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java deleted file mode 100644 index b1693b8..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MemberValuePair.java +++ /dev/null @@ -1,260 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 365519 - editorial cleanup after bug 186342 and bug 365387 - * Bug 434570 - Generic type mismatch for parametrized class annotation attribute with inner class - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -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.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -/** - * MemberValuePair node - */ -public class MemberValuePair extends ASTNode { - - public char[] name; - public Expression value; - public MethodBinding binding; - /** - * The representation of this pair in the type system. - */ - public ElementValuePair compilerElementPair = null; - - public MemberValuePair(char[] token, int sourceStart, int sourceEnd, Expression value) { - this.name = token; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - this.value = value; - if (value instanceof ArrayInitializer) { - value.bits |= IsAnnotationDefaultValue; - } - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - output - .append(this.name) - .append(" = "); //$NON-NLS-1$ - this.value.print(0, output); - return output; - } - - public void resolveTypeExpecting(BlockScope scope, TypeBinding requiredType) { - if (this.compilerElementPair != null) { - return; - } - - if (this.value == null) { - this.compilerElementPair = new ElementValuePair(this.name, this.value, this.binding); - return; - } - if (requiredType == null) { - // fault tolerance: keep resolving - if (this.value instanceof ArrayInitializer) { - this.value.resolveTypeExpecting(scope, null); - } else { - this.value.resolveType(scope); - } - this.compilerElementPair = new ElementValuePair(this.name, this.value, this.binding); - return; - } - - this.value.setExpectedType(requiredType); // needed in case of generic method invocation - looks suspect, generic method invocation here ??? - TypeBinding valueType; - if (this.value instanceof ArrayInitializer) { - ArrayInitializer initializer = (ArrayInitializer) this.value; - valueType = initializer.resolveTypeExpecting(scope, this.binding.returnType); - } else if (this.value instanceof ArrayAllocationExpression) { - scope.problemReporter().annotationValueMustBeArrayInitializer(this.binding.declaringClass, this.name, this.value); - this.value.resolveType(scope); - valueType = null; // no need to pursue - } else { - valueType = this.value.resolveType(scope); - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=248897 - ASTVisitor visitor = new ASTVisitor() { - @Override - public boolean visit(SingleNameReference reference, BlockScope scop) { - if (reference.binding instanceof LocalVariableBinding) { - ((LocalVariableBinding) reference.binding).useFlag = LocalVariableBinding.USED; - } - return true; - } - }; - this.value.traverse(visitor, scope); - } - this.compilerElementPair = new ElementValuePair(this.name, this.value, this.binding); - if (valueType == null) - return; - - TypeBinding leafType = requiredType.leafComponentType(); - if (!(this.value.isConstantValueOfTypeAssignableToType(valueType, requiredType) - || valueType.isCompatibleWith(requiredType))) { - - if (!(requiredType.isArrayType() - && requiredType.dimensions() == 1 - && (this.value.isConstantValueOfTypeAssignableToType(valueType, leafType) - || valueType.isCompatibleWith(leafType)))) { - - if (leafType.isAnnotationType() && !valueType.isAnnotationType()) { - scope.problemReporter().annotationValueMustBeAnnotation(this.binding.declaringClass, this.name, this.value, leafType); - } else { - scope.problemReporter().typeMismatchError(valueType, requiredType, this.value, null); - } - return; // may allow to proceed to find more errors at once - } - } else { - scope.compilationUnitScope().recordTypeConversion(requiredType.leafComponentType(), valueType.leafComponentType()); - this.value.computeConversion(scope, requiredType, valueType); - } - - // annotation methods can only return base types, String, Class, enum type, annotation types and arrays of these - checkAnnotationMethodType: { - switch (leafType.erasure().id) { - case T_byte : - case T_short : - case T_char : - case T_int : - case T_long : - case T_float : - case T_double : - case T_boolean : - case T_JavaLangString : - if (this.value instanceof ArrayInitializer) { - ArrayInitializer initializer = (ArrayInitializer) this.value; - final Expression[] expressions = initializer.expressions; - if (expressions != null) { - for (int i =0, max = expressions.length; i < max; i++) { - Expression expression = expressions[i]; - if (expression.resolvedType == null) continue; // fault-tolerance - if (expression.constant == Constant.NotAConstant) { - scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, expressions[i], false); - } - } - } - } else if (this.value.constant == Constant.NotAConstant) { - if (valueType.isArrayType()) { - scope.problemReporter().annotationValueMustBeArrayInitializer(this.binding.declaringClass, this.name, this.value); - } else { - scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, this.value, false); - } - } - break checkAnnotationMethodType; - case T_JavaLangClass : - if (this.value instanceof ArrayInitializer) { - ArrayInitializer initializer = (ArrayInitializer) this.value; - final Expression[] expressions = initializer.expressions; - if (expressions != null) { - for (int i =0, max = expressions.length; i < max; i++) { - Expression currentExpression = expressions[i]; - if (!(currentExpression instanceof ClassLiteralAccess)) { - scope.problemReporter().annotationValueMustBeClassLiteral(this.binding.declaringClass, this.name, currentExpression); - } - } - } - } else if (!(this.value instanceof ClassLiteralAccess)) { - scope.problemReporter().annotationValueMustBeClassLiteral(this.binding.declaringClass, this.name, this.value); - } - break checkAnnotationMethodType; - } - if (leafType.isEnum()) { - if (this.value instanceof NullLiteral) { - scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, this.value, true); - } else if (this.value instanceof ArrayInitializer) { - ArrayInitializer initializer = (ArrayInitializer) this.value; - final Expression[] expressions = initializer.expressions; - if (expressions != null) { - for (int i =0, max = expressions.length; i < max; i++) { - Expression currentExpression = expressions[i]; - if (currentExpression instanceof NullLiteral) { - scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, currentExpression, true); - } else if (currentExpression instanceof NameReference) { - NameReference nameReference = (NameReference) currentExpression; - final Binding nameReferenceBinding = nameReference.binding; - if (nameReferenceBinding.kind() == Binding.FIELD) { - FieldBinding fieldBinding = (FieldBinding) nameReferenceBinding; - if (!fieldBinding.declaringClass.isEnum()) { - scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, currentExpression, true); - } - } - } - } - } - } else if (this.value instanceof NameReference) { - NameReference nameReference = (NameReference) this.value; - final Binding nameReferenceBinding = nameReference.binding; - if (nameReferenceBinding.kind() == Binding.FIELD) { - FieldBinding fieldBinding = (FieldBinding) nameReferenceBinding; - if (!fieldBinding.declaringClass.isEnum()) { - if (!fieldBinding.type.isArrayType()) { - scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, this.value, true); - } else { - scope.problemReporter().annotationValueMustBeArrayInitializer(this.binding.declaringClass, this.name, this.value); - } - } - } - } else { - scope.problemReporter().annotationValueMustBeConstant(this.binding.declaringClass, this.name, this.value, true); - } - break checkAnnotationMethodType; - } - if (leafType.isAnnotationType()) { - if (!valueType.leafComponentType().isAnnotationType()) { // check annotation type and also reject null literal - scope.problemReporter().annotationValueMustBeAnnotation(this.binding.declaringClass, this.name, this.value, leafType); - } else if (this.value instanceof ArrayInitializer) { - ArrayInitializer initializer = (ArrayInitializer) this.value; - final Expression[] expressions = initializer.expressions; - if (expressions != null) { - for (int i =0, max = expressions.length; i < max; i++) { - Expression currentExpression = expressions[i]; - if (currentExpression instanceof NullLiteral || !(currentExpression instanceof Annotation)) { - scope.problemReporter().annotationValueMustBeAnnotation(this.binding.declaringClass, this.name, currentExpression, leafType); - } - } - } - } else if (!(this.value instanceof Annotation)) { - scope.problemReporter().annotationValueMustBeAnnotation(this.binding.declaringClass, this.name, this.value, leafType); - } - break checkAnnotationMethodType; - } - } - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.value != null) { - this.value.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.value != null) { - this.value.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MessageSend.java deleted file mode 100644 index 145a382..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MessageSend.java +++ /dev/null @@ -1,1364 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Nick Teryaev - fix for bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=40752) - * 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 186342 - [compiler][null] Using annotations for null checking - * bug 358903 - Filter practically unimportant resource leak warnings - * bug 370639 - [compiler][resource] restore the default for resource leak warnings - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 388996 - [compiler][resource] Incorrect 'potential resource leak' - * bug 379784 - [compiler] "Method can be static" is not getting reported - * bug 379834 - Wrong "method can be static" in presence of qualified super and different staticness of nested super class. - * bug 388281 - [compiler][null] inheritance of null annotations as an option - * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types - * bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional - * bug 381445 - [compiler][resource] Can the resource leak check be made aware of Closeables.closeQuietly? - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 382069 - [null] Make the null analysis consider JUnit's assertNotNull similarly to assertions - * bug 382350 - [1.8][compiler] Unable to invoke inherited default method via I.super.m() syntax - * bug 404649 - [1.8][compiler] detect illegal reference to indirect or redundant super - * bug 403086 - [compiler][null] include the effect of 'assert' in syntactic null analysis for fields - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Bug 405569 - Resource leak check false positive when using DbUtils.closeQuietly - * Bug 411964 - [1.8][null] leverage null type annotation in foreach statement - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 423504 - [1.8] Implement "18.5.3 Functional Interface Parameterization Inference" - * Bug 424710 - [1.8][compiler] CCE in SingleNameReference.localVariableBinding - * Bug 425152 - [1.8] [compiler] Lambda Expression not resolved but flow analyzed leading to NPE. - * Bug 424205 - [1.8] Cannot infer type for diamond type with lambda on method invocation - * Bug 424415 - [1.8][compiler] Eventual resolution of ReferenceExpression is not seen to be happening. - * Bug 426366 - [1.8][compiler] Type inference doesn't handle multiple candidate target types in outer overload context - * Bug 426290 - [1.8][compiler] Inference + overloading => wrong method resolution ? - * Bug 427483 - [Java 8] Variables in lambdas sometimes can't be resolved - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 426996 - [1.8][inference] try to avoid method Expression.unresolve()? - * Bug 428352 - [1.8][compiler] Resolution errors don't always surface - * Bug 429430 - [1.8] Lambdas and method reference infer wrong exception type with generics (RuntimeException instead of IOException) - * Bug 441734 - [1.8][inference] Generic method with nested parameterized type argument fails on method reference - * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression - * Bug 456487 - [1.8][null] @Nullable type variant of @NonNull-constrained type parameter causes grief - * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null - * Bug 472618 - [compiler][null] assertNotNull vs. Assert.assertNotNull - * Bug 470958 - [1.8] Unable to convert lambda - * Bug 410218 - Optional warning for arguments of "unexpected" types to Map#get(Object), Collection#remove(Object) et al. - * Jesper S Moller - Contributions for - * Bug 378674 - "The method can be declared as static" is wrong - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - * Bug 409245 - [1.8][compiler] Type annotations dropped when call is routed through a synthetic bridge method - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.ASSIGNMENT_CONTEXT; -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.INVOCATION_CONTEXT; -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.VANILLA_CONTEXT; - -import java.util.HashMap; -import java.util.function.BiConsumer; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.Opcodes; -import org.eclipse.jdt.internal.compiler.flow.ConditionalFlowInfo; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.IrritantSet; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.InferenceVariable; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolyParameterizedGenericMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolymorphicMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; -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.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; -import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable; - -public class MessageSend extends Expression implements IPolyExpression, Invocation { - - public Expression receiver; - public char[] selector; - public Expression[] arguments; - public MethodBinding binding; // exact binding resulting from lookup - public MethodBinding syntheticAccessor; // synthetic accessor for inner-emulation - public TypeBinding expectedType; // for generic method invocation (return type inference) - - public long nameSourcePosition ; //(start<<32)+end - - public TypeBinding actualReceiverType; - public TypeBinding valueCast; // extra reference type cast to perform on method returned value - public TypeReference[] typeArguments; - public TypeBinding[] genericTypeArguments; - public ExpressionContext expressionContext = VANILLA_CONTEXT; - - // hold on to this context from invocation applicability inference until invocation type inference (per method candidate): - private SimpleLookupTable/**/ inferenceContexts; - private HashMap solutionsPerTargetType; - private InferenceContext18 outerInferenceContext; // resolving within the context of an outer (lambda) inference? - - private boolean receiverIsType; - protected boolean argsContainCast; - public TypeBinding[] argumentTypes = Binding.NO_PARAMETERS; - public boolean argumentsHaveErrors = false; - - public FakedTrackingVariable closeTracker; - - BiConsumer flowUpdateOnBooleanResult; // we assume only one arg can be affected, hence no need for a list of updates - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - boolean nonStatic = !this.binding.isStatic(); - boolean wasInsideAssert = ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0); - flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic).unconditionalInits(); - - yieldQualifiedCheck(currentScope); - // recording the closing of AutoCloseable resources: - CompilerOptions compilerOptions = currentScope.compilerOptions(); - boolean analyseResources = compilerOptions.analyseResourceLeaks; - if (analyseResources) { - if (nonStatic) { - // closeable.close() - if (this.binding.isClosingMethod()) { - recordCallingClose(currentScope, flowContext, flowInfo, this.receiver); - } - } else if (this.arguments != null && this.arguments.length > 0 && FakedTrackingVariable.isAnyCloseable(this.arguments[0].resolvedType)) { - // Helper.closeMethod(closeable, ..) - for (int i=0; i { - if (result || negatable) { - if (result == nonNullIfTrue) - f.markAsDefinitelyNonNull(local); - else - f.markAsDefinitelyNull(local); - } - }; -} -@Override -protected void updateFlowOnBooleanResult(FlowInfo flowInfo, boolean result) { - if (this.flowUpdateOnBooleanResult != null) { - this.flowUpdateOnBooleanResult.accept(flowInfo, result); - } -} -private void yieldQualifiedCheck(BlockScope currentScope) { - long sourceLevel = currentScope.compilerOptions().sourceLevel; - if (sourceLevel < ClassFileConstants.JDK14 || !this.receiverIsImplicitThis()) - return; - if (!CharOperation.equals(this.selector, TypeConstants.YIELD)) - return; - currentScope.problemReporter().switchExpressionsYieldUnqualifiedMethodError(this); -} -private void recordCallingClose(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Expression closeTarget) { - if (closeTarget.isThis() || closeTarget.isSuper()) { - // this / super calls of closing method take care of all owning fields - ReferenceBinding currentClass = this.binding.declaringClass; // responsibility starts at the class and upwards - while (currentClass != null) { - for (FieldBinding fieldBinding : currentClass.fields()) { - if (fieldBinding.closeTracker != null) { - FakedTrackingVariable trackingVariable = fieldBinding.closeTracker; - if (trackingVariable.methodScope == null || trackingVariable.methodScope == currentScope.methodScope()) { - trackingVariable.markClose(flowInfo, flowContext); - } else { - trackingVariable.markClosedInNestedMethod(); - } - } - } - currentClass = currentClass.superclass(); - } - } else { - FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(closeTarget, flowInfo, flowContext, - currentScope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled); - if (trackingVariable != null) { // null happens if target is not a variable or not an AutoCloseable - if (trackingVariable.methodScope == null || trackingVariable.methodScope == currentScope.methodScope()) { - trackingVariable.markClose(flowInfo, flowContext); - } else { - trackingVariable.markClosedInNestedMethod(); - } - } - } -} - -// classification of well-known assertion utilities: -private enum AssertUtil { NONE, TRUE_ASSERTION, FALSE_ASSERTION, NULL_ASSERTION, NONNULL_ASSERTION, ARG_NONNULL_IF_TRUE, ARG_NONNULL_IF_TRUE_NEGATABLE, ARG_NULL_IF_TRUE } - -// is the argument at the given position being checked by a well-known assertion utility? -// if so answer what kind of assertion we are facing. -private AssertUtil detectAssertionUtility(int argumentIdx) { - TypeBinding[] parameters = this.binding.original().parameters; - if (argumentIdx < parameters.length) { - TypeBinding parameterType = parameters[argumentIdx]; - TypeBinding declaringClass = this.binding.declaringClass; - if (declaringClass != null && parameterType != null) { - switch (declaringClass.original().id) { - case TypeIds.T_OrgEclipseCoreRuntimeAssert: - if (parameterType.id == TypeIds.T_boolean) - return AssertUtil.TRUE_ASSERTION; - if (parameterType.id == TypeIds.T_JavaLangObject && CharOperation.equals(TypeConstants.IS_NOTNULL, this.selector)) - return AssertUtil.NONNULL_ASSERTION; - break; - case TypeIds.T_JunitFrameworkAssert: - case TypeIds.T_OrgJunitAssert: - case TypeIds.T_OrgJunitJupiterApiAssertions: - if (parameterType.id == TypeIds.T_boolean) { - if (CharOperation.equals(TypeConstants.ASSERT_TRUE, this.selector)) - return AssertUtil.TRUE_ASSERTION; - if (CharOperation.equals(TypeConstants.ASSERT_FALSE, this.selector)) - return AssertUtil.FALSE_ASSERTION; - } else if (parameterType.id == TypeIds.T_JavaLangObject) { - if (CharOperation.equals(TypeConstants.ASSERT_NOTNULL, this.selector)) - return AssertUtil.NONNULL_ASSERTION; - if (CharOperation.equals(TypeConstants.ASSERT_NULL, this.selector)) - return AssertUtil.NULL_ASSERTION; - } - break; - case TypeIds.T_OrgApacheCommonsLangValidate: - if (parameterType.id == TypeIds.T_boolean) { - if (CharOperation.equals(TypeConstants.IS_TRUE, this.selector)) - return AssertUtil.TRUE_ASSERTION; - } else if (parameterType.id == TypeIds.T_JavaLangObject) { - if (CharOperation.equals(TypeConstants.NOT_NULL, this.selector)) - return AssertUtil.NONNULL_ASSERTION; - } - break; - case TypeIds.T_OrgApacheCommonsLang3Validate: - if (parameterType.id == TypeIds.T_boolean) { - if (CharOperation.equals(TypeConstants.IS_TRUE, this.selector)) - return AssertUtil.TRUE_ASSERTION; - } else if (parameterType.isTypeVariable()) { - if (CharOperation.equals(TypeConstants.NOT_NULL, this.selector)) - return AssertUtil.NONNULL_ASSERTION; - } - break; - case TypeIds.T_ComGoogleCommonBasePreconditions: - if (parameterType.id == TypeIds.T_boolean) { - if (CharOperation.equals(TypeConstants.CHECK_ARGUMENT, this.selector) - || CharOperation.equals(TypeConstants.CHECK_STATE, this.selector)) - return AssertUtil.TRUE_ASSERTION; - } else if (parameterType.isTypeVariable()) { - if (CharOperation.equals(TypeConstants.CHECK_NOT_NULL, this.selector)) - return AssertUtil.NONNULL_ASSERTION; - } - break; - case TypeIds.T_JavaUtilObjects: - if (parameterType.isTypeVariable()) { - if (CharOperation.equals(TypeConstants.REQUIRE_NON_NULL, this.selector)) - return AssertUtil.NONNULL_ASSERTION; - } - if (this.arguments[argumentIdx] instanceof SingleNameReference) { - SingleNameReference nameRef = (SingleNameReference) this.arguments[argumentIdx]; - if (nameRef.binding instanceof LocalVariableBinding) { - if (CharOperation.equals(TypeConstants.NON_NULL, this.selector)) - return AssertUtil.ARG_NONNULL_IF_TRUE_NEGATABLE; - if (CharOperation.equals(TypeConstants.IS_NULL, this.selector)) - return AssertUtil.ARG_NULL_IF_TRUE; - } - } - break; - case TypeIds.T_JavaLangClass: - if (CharOperation.equals(TypeConstants.IS_INSTANCE, this.selector)) { - if (this.arguments[argumentIdx] instanceof SingleNameReference) { - SingleNameReference nameRef = (SingleNameReference) this.arguments[argumentIdx]; - if (nameRef.binding instanceof LocalVariableBinding) - return AssertUtil.ARG_NONNULL_IF_TRUE; - } - } - break; - } - } - } - return AssertUtil.NONE; -} - -private FlowInfo analyseBooleanAssertion(BlockScope currentScope, Expression argument, - FlowContext flowContext, FlowInfo flowInfo, boolean wasInsideAssert, boolean passOnTrue) -{ - Constant cst = argument.optimizedBooleanConstant(); - boolean isOptimizedTrueAssertion = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isOptimizedFalseAssertion = cst != Constant.NotAConstant && cst.booleanValue() == false; - int tagBitsSave = flowContext.tagBits; - flowContext.tagBits |= FlowContext.HIDE_NULL_COMPARISON_WARNING; - if (!passOnTrue) - flowContext.tagBits |= FlowContext.INSIDE_NEGATION; // this affects syntactic analysis for fields in EqualExpression - FlowInfo conditionFlowInfo = argument.analyseCode(currentScope, flowContext, flowInfo.copy()); - flowContext.extendTimeToLiveForNullCheckedField(2); // survive this assert as a MessageSend and as a Statement - flowContext.tagBits = tagBitsSave; - - UnconditionalFlowInfo assertWhenPassInfo; - FlowInfo assertWhenFailInfo; - boolean isOptimizedPassing; - boolean isOptimizedFailing; - if (passOnTrue) { - assertWhenPassInfo = conditionFlowInfo.initsWhenTrue().unconditionalInits(); - assertWhenFailInfo = conditionFlowInfo.initsWhenFalse(); - isOptimizedPassing = isOptimizedTrueAssertion; - isOptimizedFailing = isOptimizedFalseAssertion; - } else { - assertWhenPassInfo = conditionFlowInfo.initsWhenFalse().unconditionalInits(); - assertWhenFailInfo = conditionFlowInfo.initsWhenTrue(); - isOptimizedPassing = isOptimizedFalseAssertion; - isOptimizedFailing = isOptimizedTrueAssertion; - } - if (isOptimizedPassing) { - assertWhenFailInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - if (!isOptimizedFailing) { - // if assertion is not failing for sure, only then it makes sense to carry the flow info ahead. - // if the code does reach ahead, it means the assert didn't cause an exit, and so - // the expression inside it shouldn't change the prior flowinfo - // viz. org.eclipse.core.runtime.Assert.isLegal(false && o != null) - - // keep the merge from the initial code for the definite assignment - // analysis, tweak the null part to influence nulls downstream - flowInfo = flowInfo.mergedWith(assertWhenFailInfo.nullInfoLessUnconditionalCopy()). - addInitializationsFrom(assertWhenPassInfo.discardInitializationInfo()); - } - return flowInfo; -} -private FlowInfo analyseNullAssertion(BlockScope currentScope, Expression argument, - FlowContext flowContext, FlowInfo flowInfo, boolean expectingNull) -{ - int nullStatus = argument.nullStatus(flowInfo, flowContext); - boolean willFail = (nullStatus == (expectingNull ? FlowInfo.NON_NULL : FlowInfo.NULL)); - flowInfo = argument.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - LocalVariableBinding local = argument.localVariableBinding(); - if (local != null) {// beyond this point the argument can only be null/nonnull - if (expectingNull) - flowInfo.markAsDefinitelyNull(local); - else - flowInfo.markAsDefinitelyNonNull(local); - } else { - if (!expectingNull - && argument instanceof Reference - && currentScope.compilerOptions().enableSyntacticNullAnalysisForFields) - { - FieldBinding field = ((Reference)argument).lastFieldBinding(); - if (field != null && (field.type.tagBits & TagBits.IsBaseType) == 0) { - flowContext.recordNullCheckedFieldReference((Reference) argument, 3); // survive this assert as a MessageSend and as a Statement - } - } - } - if (willFail) - flowInfo.setReachMode(FlowInfo.UNREACHABLE_BY_NULLANALYSIS); - return flowInfo; -} - -@Override -public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - // message send as a receiver - int nullStatus = nullStatus(flowInfo, flowContext); // note that flowInfo is not used inside nullStatus(..) - if ((nullStatus & FlowInfo.POTENTIALLY_NULL) != 0) { - if(this.binding.returnType.isTypeVariable() && nullStatus == FlowInfo.FREE_TYPEVARIABLE && scope.environment().globalOptions.pessimisticNullAnalysisForFreeTypeVariablesEnabled) { - scope.problemReporter().methodReturnTypeFreeTypeVariableReference(this.binding, this); - } else { - scope.problemReporter().messageSendPotentialNullReference(this.binding, this); - } - } else if ((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0) { - NullAnnotationMatching nonNullStatus = NullAnnotationMatching.okNonNullStatus(this); - if (nonNullStatus.wantToReport()) - nonNullStatus.report(scope); - } - return true; // done all possible checking -} -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) - */ -@Override -public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { - if (runtimeTimeType == null || compileTimeType == null) - return; - // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast) - if (this.binding != null && this.binding.isValidBinding()) { - MethodBinding originalBinding = this.binding.original(); - TypeBinding originalType = originalBinding.returnType; - // extra cast needed if method return type is type variable - if (ArrayBinding.isArrayClone(this.actualReceiverType, this.binding) - && runtimeTimeType.id != TypeIds.T_JavaLangObject - && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { - // from 1.5 source level on, array#clone() resolves to array type, but codegen to #clone()Object - thus require extra inserted cast - this.valueCast = runtimeTimeType; - } else if (originalType.leafComponentType().isTypeVariable()) { - TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) - ? compileTimeType // unboxing: checkcast before conversion - : runtimeTimeType; - this.valueCast = originalType.genericCast(targetType); - } - if (this.valueCast instanceof ReferenceBinding) { - ReferenceBinding referenceCast = (ReferenceBinding) this.valueCast; - if (!referenceCast.canBeSeenBy(scope)) { - scope.problemReporter().invalidType(this, - new ProblemReferenceBinding( - CharOperation.splitOn('.', referenceCast.shortReadableName()), - referenceCast, - ProblemReasons.NotVisible)); - } - } - } - super.computeConversion(scope, runtimeTimeType, compileTimeType); -} - -/** - * MessageSend code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - cleanUpInferenceContexts(); - int pc = codeStream.position; - // generate receiver/enclosing instance access - MethodBinding codegenBinding = this.binding instanceof PolymorphicMethodBinding ? this.binding : this.binding.original(); - boolean isStatic = codegenBinding.isStatic(); - if (isStatic) { - this.receiver.generateCode(currentScope, codeStream, false); - } else if ((this.bits & ASTNode.DepthMASK) != 0 && this.receiver.isImplicitThis()) { // outer access ? - // outer method can be reached through emulation if implicit access - ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); - Object[] path = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); - codeStream.generateOuterAccess(path, this, targetType, currentScope); - } else { - this.receiver.generateCode(currentScope, codeStream, true); - if ((this.bits & NeedReceiverGenericCast) != 0) { - codeStream.checkcast(this.actualReceiverType); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - // generate arguments - generateArguments(this.binding, this.arguments, currentScope, codeStream); - pc = codeStream.position; - // actual message invocation - if (this.syntheticAccessor == null){ - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenBinding, this.actualReceiverType, this.receiver.isImplicitThis()); - if (isStatic){ - codeStream.invoke(Opcodes.OPC_invokestatic, codegenBinding, constantPoolDeclaringClass, this.typeArguments); - } else if((this.receiver.isSuper()) || - (!currentScope.enclosingSourceType().isNestmateOf(this.binding.declaringClass) && codegenBinding.isPrivate())){ - codeStream.invoke(Opcodes.OPC_invokespecial, codegenBinding, constantPoolDeclaringClass, this.typeArguments); - } else if (constantPoolDeclaringClass.isInterface()) { // interface or annotation type - codeStream.invoke(Opcodes.OPC_invokeinterface, codegenBinding, constantPoolDeclaringClass, this.typeArguments); - } else { - codeStream.invoke(Opcodes.OPC_invokevirtual, codegenBinding, constantPoolDeclaringClass, this.typeArguments); - } - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessor, null /* default declaringClass */, this.typeArguments); - } - // required cast must occur even if no value is required - if (this.valueCast != null) codeStream.checkcast(this.valueCast); - if (valueRequired){ - // implicit conversion if necessary - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; - // conversion only generated if unboxing - if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion); - switch (isUnboxing ? postConversionType(currentScope).id : codegenBinding.returnType.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - case T_void : - break; - default : - codeStream.pop(); - } - } - codeStream.recordPositionsFrom(pc, (int)(this.nameSourcePosition >>> 32)); // highlight selector -} -/** - * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() - */ -@Override -public TypeBinding[] genericTypeArguments() { - return this.genericTypeArguments; -} - -@Override -public boolean isSuperAccess() { - return this.receiver.isSuper(); -} -@Override -public boolean isTypeAccess() { - return this.receiver != null && this.receiver.isTypeReference(); -} -public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo){ - - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return; - - // if method from parameterized type got found, use the original method at codegen time - MethodBinding codegenBinding = this.binding.original(); - if (this.binding.isPrivate()){ - boolean useNesting = currentScope.enclosingSourceType().isNestmateOf(codegenBinding.declaringClass) && - !(this.receiver instanceof QualifiedSuperReference); - // depth is set for both implicit and explicit access (see MethodBinding#canBeSeenBy) - if (!useNesting && - TypeBinding.notEquals(currentScope.enclosingSourceType(), codegenBinding.declaringClass)){ - this.syntheticAccessor = ((SourceTypeBinding)codegenBinding.declaringClass).addSyntheticMethod(codegenBinding, false /* not super access there */); - currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this); - return; - } - - } else if (this.receiver instanceof QualifiedSuperReference) { // qualified super - if (this.actualReceiverType.isInterface()) - return; // invoking an overridden default method, which is accessible/public by definition - // qualified super need emulation always - SourceTypeBinding destinationType = (SourceTypeBinding)(((QualifiedSuperReference)this.receiver).currentCompatibleType); - this.syntheticAccessor = destinationType.addSyntheticMethod(codegenBinding, isSuperAccess()); - currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this); - return; - - } else if (this.binding.isProtected()){ - - SourceTypeBinding enclosingSourceType; - if (((this.bits & ASTNode.DepthMASK) != 0) - && codegenBinding.declaringClass.getPackage() - != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()){ - - SourceTypeBinding currentCompatibleType = (SourceTypeBinding)enclosingSourceType.enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); - this.syntheticAccessor = currentCompatibleType.addSyntheticMethod(codegenBinding, isSuperAccess()); - currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this); - return; - } - } -} -@Override -public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - if ((this.implicitConversion & TypeIds.BOXING) != 0) - return FlowInfo.NON_NULL; - if (this.binding.isValidBinding()) { - // try to retrieve null status of this message send from an annotation of the called method: - long tagBits = this.binding.tagBits; - if ((tagBits & TagBits.AnnotationNullMASK) == 0L) // alternatively look for type annotation (will only be present in 1.8+): - tagBits = this.binding.returnType.tagBits & TagBits.AnnotationNullMASK; - if(tagBits == 0L && this.binding.returnType.isFreeTypeVariable()) { - return FlowInfo.FREE_TYPEVARIABLE; - } - return FlowInfo.tagBitsToNullStatus(tagBits); - } - return FlowInfo.UNKNOWN; -} -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope) - */ -@Override -public TypeBinding postConversionType(Scope scope) { - TypeBinding convertedType = this.resolvedType; - if (this.valueCast != null) - convertedType = this.valueCast; - int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; - switch (runtimeType) { - case T_boolean : - convertedType = TypeBinding.BOOLEAN; - break; - case T_byte : - convertedType = TypeBinding.BYTE; - break; - case T_short : - convertedType = TypeBinding.SHORT; - break; - case T_char : - convertedType = TypeBinding.CHAR; - break; - case T_int : - convertedType = TypeBinding.INT; - break; - case T_float : - convertedType = TypeBinding.FLOAT; - break; - case T_long : - convertedType = TypeBinding.LONG; - break; - case T_double : - convertedType = TypeBinding.DOUBLE; - break; - default : - } - if ((this.implicitConversion & TypeIds.BOXING) != 0) { - convertedType = scope.environment().computeBoxingType(convertedType); - } - return convertedType; -} - -@Override -public StringBuilder printExpression(int indent, StringBuilder output){ - - if (!this.receiver.isImplicitThis()) this.receiver.printExpression(0, output).append('.'); - if (this.typeArguments != null) { - output.append('<'); - int max = this.typeArguments.length - 1; - for (int j = 0; j < max; j++) { - this.typeArguments[j].print(0, output); - output.append(", ");//$NON-NLS-1$ - } - this.typeArguments[max].print(0, output); - output.append('>'); - } - output.append(this.selector).append('(') ; - if (this.arguments != null) { - for (int i = 0; i < this.arguments.length ; i ++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.arguments[i].printExpression(0, output); - } - } - return output.append(')'); -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - // Answer the signature return type, answers PolyTypeBinding if a poly expression and there is no target type - // Base type promotion - if (this.constant != Constant.NotAConstant) { - this.constant = Constant.NotAConstant; - long sourceLevel = scope.compilerOptions().sourceLevel; - boolean receiverCast = false; - if (this.receiver instanceof CastExpression) { - this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - receiverCast = true; - } - this.actualReceiverType = this.receiver.resolveType(scope); - if (this.actualReceiverType instanceof InferenceVariable) { - return null; // not yet ready for resolving - } - this.receiverIsType = this.receiver.isType(); - if (receiverCast && this.actualReceiverType != null) { - // due to change of declaring class with receiver type, only identity cast should be notified - TypeBinding resolvedType2 = ((CastExpression)this.receiver).expression.resolvedType; - if (TypeBinding.equalsEquals(resolvedType2, this.actualReceiverType)) { - if (!scope.environment().usesNullTypeAnnotations() || !NullAnnotationMatching.analyse(this.actualReceiverType, resolvedType2, -1).isAnyMismatch()) { - scope.problemReporter().unnecessaryCast((CastExpression) this.receiver); - } - } - } - // resolve type arguments (for generic constructor call) - if (this.typeArguments != null) { - int length = this.typeArguments.length; - this.argumentsHaveErrors = sourceLevel < ClassFileConstants.JDK1_5; // typeChecks all arguments - this.genericTypeArguments = new TypeBinding[length]; - for (int i = 0; i < length; i++) { - TypeReference typeReference = this.typeArguments[i]; - if ((this.genericTypeArguments[i] = typeReference.resolveType(scope, true /* check bounds*/, Binding.DefaultLocationTypeArgument)) == null) { - this.argumentsHaveErrors = true; - } - if (this.argumentsHaveErrors && typeReference instanceof Wildcard) { - scope.problemReporter().illegalUsageOfWildcard(typeReference); - } - } - if (this.argumentsHaveErrors) { - if (this.arguments != null) { // still attempt to resolve arguments - for (int i = 0, max = this.arguments.length; i < max; i++) { - this.arguments[i].resolveType(scope); - } - } - return null; - } - } - // will check for null after args are resolved - if (this.arguments != null) { - this.argumentsHaveErrors = false; // typeChecks all arguments - int length = this.arguments.length; - this.argumentTypes = new TypeBinding[length]; - for (int i = 0; i < length; i++){ - Expression argument = this.arguments[i]; - if (this.arguments[i].resolvedType != null) - scope.problemReporter().genericInferenceError("Argument was unexpectedly found resolved", this); //$NON-NLS-1$ - if (argument instanceof CastExpression) { - argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - this.argsContainCast = true; - } - argument.setExpressionContext(INVOCATION_CONTEXT); - if ((this.argumentTypes[i] = argument.resolveType(scope)) == null){ - this.argumentsHaveErrors = true; - } - } - if (this.argumentsHaveErrors) { - if (this.actualReceiverType instanceof ReferenceBinding) { - // record a best guess, for clients who need hint about possible method match - TypeBinding[] pseudoArgs = new TypeBinding[length]; - for (int i = length; --i >= 0;) - pseudoArgs[i] = this.argumentTypes[i] == null ? TypeBinding.NULL : this.argumentTypes[i]; // replace args with errors with null type - - this.binding = this.receiver.isImplicitThis() ? - scope.getImplicitMethod(this.selector, pseudoArgs, this) : - scope.findMethod((ReferenceBinding) this.actualReceiverType, this.selector, pseudoArgs, this, false); - - if (this.binding != null && !this.binding.isValidBinding()) { - MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; - // record the closest match, for clients who may still need hint about possible method match - if (closestMatch != null) { - if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method - // shouldn't return generic method outside its context, rather convert it to raw method (175409) - closestMatch = scope.environment().createParameterizedGenericMethod(closestMatch.original(), (RawTypeBinding)null); - } - this.binding = closestMatch; - MethodBinding closestMatchOriginal = closestMatch.original(); - if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { - // ignore cases where method is used from within inside itself (e.g. direct recursions) - closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - } - } - } - return null; - } - } - if (this.actualReceiverType == null) { - return null; - } - // base type cannot receive any message - if (this.actualReceiverType.isBaseType()) { - scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, this.argumentTypes); - return null; - } - } - if (this.argumentsHaveErrors) { - return null; - } - - TypeBinding methodType = findMethodBinding(scope); - if (methodType != null && methodType.isPolyType()) { - this.resolvedType = this.binding.returnType.capture(scope, this.sourceStart, this.sourceEnd); - return methodType; - } - - if (!this.binding.isValidBinding()) { - if (this.binding.declaringClass == null) { - if (this.actualReceiverType instanceof ReferenceBinding) { - this.binding.declaringClass = (ReferenceBinding) this.actualReceiverType; - } else { - scope.problemReporter().errorNoMethodFor(this, this.actualReceiverType, this.argumentTypes); - return null; - } - } - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=245007 avoid secondary errors in case of - // missing super type for anonymous classes ... - ReferenceBinding declaringClass = this.binding.declaringClass; - boolean avoidSecondary = declaringClass != null && - declaringClass.isAnonymousType() && - declaringClass.superclass() instanceof MissingTypeBinding; - if (!avoidSecondary) - scope.problemReporter().invalidMethod(this, this.binding, scope); - MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; - switch (this.binding.problemId()) { - case ProblemReasons.Ambiguous : - break; // no resilience on ambiguous - case ProblemReasons.InferredApplicableMethodInapplicable: - case ProblemReasons.InvocationTypeInferenceFailure: - // Grabbing the closest match improves error reporting in nested invocation contexts - if (this.expressionContext != INVOCATION_CONTEXT) - break; - //$FALL-THROUGH$ - case ProblemReasons.NotVisible : - case ProblemReasons.NonStaticReferenceInConstructorInvocation : - case ProblemReasons.NonStaticReferenceInStaticContext : - case ProblemReasons.ReceiverTypeNotVisible : - case ProblemReasons.ParameterBoundMismatch : - // only steal returnType in cases listed above - if (closestMatch != null) this.resolvedType = closestMatch.returnType; - break; - case ProblemReasons.ContradictoryNullAnnotations : - if (closestMatch != null && closestMatch.returnType != null) - this.resolvedType = closestMatch.returnType.withoutToplevelNullAnnotation(); - break; - } - // record the closest match, for clients who may still need hint about possible method match - if (closestMatch != null) { - this.binding = closestMatch; - MethodBinding closestMatchOriginal = closestMatch.original(); - if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { - // ignore cases where method is used from within inside itself (e.g. direct recursions) - closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - } - return (this.resolvedType != null && (this.resolvedType.tagBits & TagBits.HasMissingType) == 0) - ? this.resolvedType - : null; - } - final CompilerOptions compilerOptions = scope.compilerOptions(); - if (compilerOptions.complianceLevel <= ClassFileConstants.JDK1_6 - && this.binding.isPolymorphic()) { - scope.problemReporter().polymorphicMethodNotBelow17(this); - return null; - } - - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { - ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope); - if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8) { - if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) { - TypeVariableBinding[] typeVariables = this.binding.original().typeVariables(); - for (int i = 0; i < this.typeArguments.length; i++) - this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i); - } - } - } - - if (this.binding.isPolymorphic()) { - - boolean resultDetermined = compilerOptions.sourceLevel >= ClassFileConstants.JDK9 - && (this.binding.returnType == TypeBinding.VOID - || this.binding.returnType.id != TypeIds.T_JavaLangObject); - - if (!resultDetermined && ((this.bits & ASTNode.InsideExpressionStatement) != 0)) { - // we only set the return type to be void if this method invocation is used inside an expression statement - this.binding = scope.environment().updatePolymorphicMethodReturnType((PolymorphicMethodBinding) this.binding, TypeBinding.VOID); - } - } - if ((this.binding.tagBits & TagBits.HasMissingType) != 0) { - scope.problemReporter().missingTypeInMethod(this, this.binding); - } - if (!this.binding.isStatic()) { - // the "receiver" must not be a type - if (this.receiverIsType) { - scope.problemReporter().mustUseAStaticMethod(this, this.binding); - if (this.actualReceiverType.isRawType() - && (this.receiver.bits & ASTNode.IgnoreRawTypeCheck) == 0 - && compilerOptions.getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) { - scope.problemReporter().rawTypeReference(this.receiver, this.actualReceiverType); - } - } else { - // handle indirect inheritance thru variable secondary bound - // receiver may receive generic cast, as part of implicit conversion - TypeBinding oldReceiverType = this.actualReceiverType; - this.actualReceiverType = this.actualReceiverType.getErasureCompatibleType(this.binding.declaringClass); - this.receiver.computeConversion(scope, this.actualReceiverType, this.actualReceiverType); - if (TypeBinding.notEquals(this.actualReceiverType, oldReceiverType) && TypeBinding.notEquals(this.receiver.postConversionType(scope), this.actualReceiverType)) { // record need for explicit cast at codegen since receiver could not handle it - this.bits |= NeedReceiverGenericCast; - } - } - } else { - // static message invoked through receiver? legal but unoptimal (optional warning). - if (this.binding.declaringClass.isInterface() && !((isTypeAccess() || this.receiver.isImplicitThis()) && TypeBinding.equalsEquals(this.binding.declaringClass, this.actualReceiverType))) { - scope.problemReporter().nonStaticOrAlienTypeReceiver(this, this.binding); - } else if (!(this.receiver.isImplicitThis() || this.receiver.isSuper() || this.receiverIsType)) { - scope.problemReporter().nonStaticAccessToStaticMethod(this, this.binding); - } - if (!this.receiver.isImplicitThis() && TypeBinding.notEquals(this.binding.declaringClass, this.actualReceiverType)) { - scope.problemReporter().indirectAccessToStaticMethod(this, this.binding); - } - } - if (checkInvocationArguments(scope, this.receiver, this.actualReceiverType, this.binding, this.arguments, this.argumentTypes, this.argsContainCast, this)) { - this.bits |= ASTNode.Unchecked; - } - - //-------message send that are known to fail at compile time----------- - if (this.binding.isAbstract()) { - if (this.receiver.isSuper()) { - scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding); - } - // abstract private methods cannot occur nor abstract static............ - } - if (isMethodUseDeprecated(this.binding, scope, true, this)) - scope.problemReporter().deprecatedMethod(this.binding, this); - - TypeBinding returnType; - if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6 - returnType = this.binding.returnType; - if (returnType != null) { - returnType = scope.environment().convertToRawType(returnType.erasure(), true); - } - } else { - returnType = this.binding.returnType; - if (returnType != null) { - returnType = returnType.capture(scope, this.sourceStart, this.sourceEnd); - } - } - if (scope.environment().usesNullTypeAnnotations()) { - returnType = handleNullnessCodePatterns(scope, returnType); - } - this.resolvedType = returnType; - if (this.receiver.isSuper() && compilerOptions.getSeverity(CompilerOptions.OverridingMethodWithoutSuperInvocation) != ProblemSeverities.Ignore) { - final ReferenceContext referenceContext = scope.methodScope().referenceContext; - if (referenceContext instanceof AbstractMethodDeclaration) { - final AbstractMethodDeclaration abstractMethodDeclaration = (AbstractMethodDeclaration) referenceContext; - MethodBinding enclosingMethodBinding = abstractMethodDeclaration.binding; - if (enclosingMethodBinding.isOverriding() - && CharOperation.equals(this.binding.selector, enclosingMethodBinding.selector) - && this.binding.areParametersEqual(enclosingMethodBinding)) { - abstractMethodDeclaration.bits |= ASTNode.OverridingMethodWithSupercall; - } - } - } - if (this.receiver.isSuper() && this.actualReceiverType.isInterface()) { - // 15.12.3 (Java 8) - scope.checkAppropriateMethodAgainstSupers(this.selector, this.binding, this.argumentTypes, this); - } - if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { - scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(this.binding, this.genericTypeArguments, this.typeArguments); - } - return (this.resolvedType.tagBits & TagBits.HasMissingType) == 0 - ? this.resolvedType - : null; -} - -protected TypeBinding handleNullnessCodePatterns(BlockScope scope, TypeBinding returnType) { - // j.u.s.Stream.filter() may modify nullness of stream elements: - if (this.binding.isWellknownMethod(TypeConstants.JAVA_UTIL_STREAM__STREAM, TypeConstants.FILTER) - && returnType instanceof ParameterizedTypeBinding) - { - ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) returnType; - // filtering on Objects::nonNull? - if (this.arguments != null && this.arguments.length == 1) { - if (this.arguments[0] instanceof ReferenceExpression) { - MethodBinding argumentBinding = ((ReferenceExpression) this.arguments[0]).binding; - if (argumentBinding.isWellknownMethod(TypeIds.T_JavaUtilObjects, TypeConstants.NON_NULL)) - { - // code pattern detected, now update the return type: - if (parameterizedType.arguments.length == 1) { - LookupEnvironment environment = scope.environment(); - TypeBinding updatedTypeArgument = parameterizedType.arguments[0].withoutToplevelNullAnnotation(); - updatedTypeArgument = environment.createNonNullAnnotatedType(updatedTypeArgument); - return environment.createParameterizedType( - parameterizedType.genericType(), new TypeBinding[] { updatedTypeArgument }, parameterizedType.enclosingType()); - } - } - } - } - } - return returnType; -} - -protected TypeBinding findMethodBinding(BlockScope scope) { - ReferenceContext referenceContext = scope.methodScope().referenceContext; - if (referenceContext instanceof LambdaExpression) { - this.outerInferenceContext = ((LambdaExpression) referenceContext).inferenceContext; - } - - if (this.expectedType != null && this.binding instanceof PolyParameterizedGenericMethodBinding) { - this.binding = this.solutionsPerTargetType.get(this.expectedType); - } - if (this.binding == null) { // first look up or a "cache miss" somehow. - this.binding = this.receiver.isImplicitThis() ? - scope.getImplicitMethod(this.selector, this.argumentTypes, this) - : scope.getMethod(this.actualReceiverType, this.selector, this.argumentTypes, this); - - if (this.binding instanceof PolyParameterizedGenericMethodBinding) { - this.solutionsPerTargetType = new HashMap<>(); - return new PolyTypeBinding(this); - } - } - this.binding = resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope); - return this.binding.returnType; -} - -@Override -public void setActualReceiverType(ReferenceBinding receiverType) { - if (receiverType == null) return; // error scenario only - this.actualReceiverType = receiverType; -} -@Override -public void setDepth(int depth) { - this.bits &= ~ASTNode.DepthMASK; // flush previous depth if any - if (depth > 0) { - this.bits |= (depth & 0xFF) << ASTNode.DepthSHIFT; // encoded on 8 bits - } -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#setExpectedType(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) - */ -@Override -public void setExpectedType(TypeBinding expectedType) { - this.expectedType = expectedType; -} - -@Override -public void setExpressionContext(ExpressionContext context) { - this.expressionContext = context; -} - -@Override -public boolean isPolyExpression() { - - /* 15.12 has four requirements: 1) The invocation appears in an assignment context or an invocation context - 2) The invocation elides NonWildTypeArguments 3) the method to be invoked is a generic method (8.4.4). - 4) The return type of the method to be invoked mentions at least one of the method's type parameters. - - We are in no position to ascertain the last two until after resolution has happened. So no client should - depend on asking this question before resolution. - */ - return isPolyExpression(this.binding); -} - -@Override -public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope scope) { - if (this.argumentsHaveErrors || this.binding == null || !this.binding.isValidBinding() || targetType == null || scope == null) - return false; - if (isPolyExpression() && !targetType.isPrimitiveOrBoxedPrimitiveType()) // i.e it is dumb to trigger inference, checking boxing compatibility against say Collector. - return false; - TypeBinding originalExpectedType = this.expectedType; - try { - MethodBinding method = this.solutionsPerTargetType != null ? this.solutionsPerTargetType.get(targetType) : null; - if (method == null) { - this.expectedType = targetType; - // No need to tunnel through overload resolution. this.binding is the MSMB. - method = isPolyExpression() ? ParameterizedGenericMethodBinding.computeCompatibleMethod18(this.binding.shallowOriginal(), this.argumentTypes, scope, this) : this.binding; - registerResult(targetType, method); - } - if (method == null || !method.isValidBinding() || method.returnType == null || !method.returnType.isValidBinding()) - return false; - return super.isBoxingCompatible(method.returnType.capture(scope, this.sourceStart, this.sourceEnd), targetType, this, scope); - } finally { - this.expectedType = originalExpectedType; - } -} - -@Override -public boolean isCompatibleWith(TypeBinding targetType, final Scope scope) { - if (this.argumentsHaveErrors || this.binding == null || !this.binding.isValidBinding() || targetType == null || scope == null) - return false; - TypeBinding originalExpectedType = this.expectedType; - try { - MethodBinding method = this.solutionsPerTargetType != null ? this.solutionsPerTargetType.get(targetType) : null; - if (method == null) { - this.expectedType = targetType; - // No need to tunnel through overload resolution. this.binding is the MSMB. - method = isPolyExpression() ? ParameterizedGenericMethodBinding.computeCompatibleMethod18(this.binding.shallowOriginal(), this.argumentTypes, scope, this) : this.binding; - registerResult(targetType, method); - } - TypeBinding returnType; - if (method == null || !method.isValidBinding() || (returnType = method.returnType) == null || !returnType.isValidBinding()) - return false; - if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) - returnType = scope.environment().convertToRawType(returnType.erasure(), true); - return returnType.capture(scope, this.sourceStart, this.sourceEnd).isCompatibleWith(targetType, scope); - } finally { - this.expectedType = originalExpectedType; - } -} - -/** Variant of isPolyExpression() to be used during type inference, when a resolution candidate exists. */ -@Override -public boolean isPolyExpression(MethodBinding resolutionCandidate) { - if (this.expressionContext != ASSIGNMENT_CONTEXT && this.expressionContext != INVOCATION_CONTEXT) - return false; - - if (this.typeArguments != null && this.typeArguments.length > 0) - return false; - - if (this.constant != Constant.NotAConstant) - throw new UnsupportedOperationException("Unresolved MessageSend can't be queried if it is a polyexpression"); //$NON-NLS-1$ - - if (resolutionCandidate != null) { - if (resolutionCandidate instanceof ParameterizedGenericMethodBinding) { - ParameterizedGenericMethodBinding pgmb = (ParameterizedGenericMethodBinding) resolutionCandidate; - if (pgmb.inferredReturnType) - return true; // if already determined - } - if (resolutionCandidate.returnType != null) { - // resolution may have prematurely instantiated the generic method, we need the original, though: - MethodBinding candidateOriginal = resolutionCandidate.original(); - return candidateOriginal.returnType.mentionsAny(candidateOriginal.typeVariables(), -1); - } - } - - return false; -} - -@Override -public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) { - if (super.sIsMoreSpecific(s, t, scope)) - return true; - return isPolyExpression() ? !s.isBaseType() && t.isBaseType() : false; -} - -@Override -public void setFieldIndex(int depth) { - // ignore for here -} -@Override -public TypeBinding invocationTargetType() { - return this.expectedType; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) { - this.receiver.traverse(visitor, blockScope); - if (this.typeArguments != null) { - for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) { - this.typeArguments[i].traverse(visitor, blockScope); - } - } - if (this.arguments != null) { - int argumentsLength = this.arguments.length; - for (int i = 0; i < argumentsLength; i++) - this.arguments[i].traverse(visitor, blockScope); - } - } - visitor.endVisit(this, blockScope); -} -@Override -public boolean statementExpression() { - return ((this.bits & ASTNode.ParenthesizedMASK) == 0); -} -@Override -public boolean receiverIsImplicitThis() { - return this.receiver.isImplicitThis(); -} -// -- interface Invocation: -- -@Override -public MethodBinding binding() { - return this.binding; -} - -@Override -public void registerInferenceContext(ParameterizedGenericMethodBinding method, InferenceContext18 infCtx18) { - if (InferenceContext18.DEBUG) { - System.out.println("Register inference context of "+this+" for "+method+":\n"+infCtx18); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - if (this.inferenceContexts == null) - this.inferenceContexts = new SimpleLookupTable(); - this.inferenceContexts.put(method, infCtx18); -} - -@Override -public void registerResult(TypeBinding targetType, MethodBinding method) { - if (InferenceContext18.DEBUG) { - System.out.println("Register inference result for "+this+" with target "+ //$NON-NLS-1$ //$NON-NLS-2$ - (targetType == null ? "" : targetType.debugName())+": "+method); //$NON-NLS-1$ //$NON-NLS-2$ - } - if (this.solutionsPerTargetType == null) - this.solutionsPerTargetType = new HashMap<>(); - this.solutionsPerTargetType.put(targetType, method); -} - -@Override -public InferenceContext18 getInferenceContext(ParameterizedMethodBinding method) { - InferenceContext18 context = null; - if (this.inferenceContexts != null) - context = (InferenceContext18) this.inferenceContexts.get(method); - if (InferenceContext18.DEBUG) { - System.out.println("Retrieve inference context of "+this+" for "+method+":\n"+context); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - return context; -} -@Override -public void cleanUpInferenceContexts() { - if (this.inferenceContexts == null) - return; - for (Object value : this.inferenceContexts.valueTable) - if (value != null) - ((InferenceContext18) value).cleanUp(); - this.inferenceContexts = null; - this.outerInferenceContext = null; - this.solutionsPerTargetType = null; -} -@Override -public Expression[] arguments() { - return this.arguments; -} -@Override -public ExpressionContext getExpressionContext() { - return this.expressionContext; -} -// -- Interface InvocationSite: -- -@Override -public InferenceContext18 freshInferenceContext(Scope scope) { - return new InferenceContext18(scope, this.arguments, this, this.outerInferenceContext); -} -@Override -public boolean isQualifiedSuper() { - return this.receiver.isQualifiedSuper(); -} -@Override -public int nameSourceStart() { - return (int) (this.nameSourcePosition >>> 32); -} -@Override -public int nameSourceEnd() { - return (int) this.nameSourcePosition; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java deleted file mode 100644 index c7366a1..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/MethodDeclaration.java +++ /dev/null @@ -1,465 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 349326 - [1.7] new warning for missing try-with-resources - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 365519 - editorial cleanup after bug 186342 and bug 365387 - * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK - * bug 382353 - [1.8][compiler] Implementation property modifiers should be accepted on default methods. - * bug 383368 - [compiler][null] syntactic null analysis for field references - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables - * Bug 438012 - [1.8][null] Bogus Warning: The nullness annotation is redundant with a default that applies to this location - * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations - * Bug 466713 - Null Annotations: NullPointerException using as Type Param - * Jesper S Moller - Contributions for - * bug 378674 - "The method can be declared as static" is wrong - * bug 413873 - Warning "Method can be static" on method referencing a non-static inner class - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.List; -import java.util.function.BiPredicate; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition; -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.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.MemberTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -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.parser.Parser; -import org.eclipse.jdt.internal.compiler.problem.AbortMethod; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; - -public class MethodDeclaration extends AbstractMethodDeclaration { - - public TypeReference returnType; - public TypeParameter[] typeParameters; - - /** - * MethodDeclaration constructor comment. - */ - public MethodDeclaration(CompilationResult compilationResult) { - super(compilationResult); - this.bits |= ASTNode.CanBeStatic; // Start with this assumption, will course correct during resolve and analyseCode. - } - - public void analyseCode(ClassScope classScope, FlowContext flowContext, FlowInfo flowInfo) { - // starting of the code analysis for methods - if (this.ignoreFurtherInvestigation) - return; - try { - if (this.binding == null) - return; - - if (!this.binding.isUsed() && !this.binding.isAbstract()) { - if (this.binding.isPrivate() - || (((this.binding.modifiers & (ExtraCompilerModifiers.AccOverriding|ExtraCompilerModifiers.AccImplementing)) == 0) - && this.binding.isOrEnclosedByPrivateType())) { - if (!classScope.referenceCompilationUnit().compilationResult.hasSyntaxError) { - this.scope.problemReporter().unusedPrivateMethod(this); - } - } - } - - // skip enum implicit methods - if (this.binding.declaringClass.isEnum() && (this.selector == TypeConstants.VALUES || this.selector == TypeConstants.VALUEOF)) - return; - - // may be in a non necessary for innerclass with static final constant fields - if (this.binding.isAbstract() || this.binding.isNative()) - return; - - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=385780 - if (this.typeParameters != null && - !this.scope.referenceCompilationUnit().compilationResult.hasSyntaxError) { - for (int i = 0, length = this.typeParameters.length; i < length; ++i) { - TypeParameter typeParameter = this.typeParameters[i]; - if ((typeParameter.binding.modifiers & ExtraCompilerModifiers.AccLocallyUsed) == 0) { - this.scope.problemReporter().unusedTypeParameter(typeParameter); - } - } - } - ExceptionHandlingFlowContext methodContext = - new ExceptionHandlingFlowContext( - flowContext, - this, - this.binding.thrownExceptions, - null, - this.scope, - FlowInfo.DEAD_END); - - // nullity, owning and mark as assigned - analyseArguments(classScope.environment(), flowInfo, flowContext, this.arguments, this.binding); - - BiPredicate condition = (argType, declClass) -> { - ReferenceBinding enclosingType = argType.enclosingType(); - if (enclosingType != null && TypeBinding.equalsEquals(declClass, enclosingType.actualType())) { - return true; - } - return false; - }; - boolean referencesGenericType = false; - ReferenceBinding declaringClass = this.binding.declaringClass; - if (declaringClass.isGenericType()) { - if (condition.test(this.binding.returnType, declaringClass)) { - referencesGenericType = true; - } - if (!referencesGenericType && this.binding.parameters != null && this.arguments != null) { - int length = Math.min(this.binding.parameters.length, this.arguments.length); - for (int i = 0; i < length; i++) { - if (condition.test(this.binding.parameters[i], this.binding.declaringClass)) { - referencesGenericType = true; - break; - } - } - } - } - if (this.binding.declaringClass instanceof MemberTypeBinding && !this.binding.declaringClass.isStatic() || referencesGenericType) { - // method of a non-static member type can't be static. - this.bits &= ~ASTNode.CanBeStatic; - } - CompilerOptions compilerOptions = this.scope.compilerOptions(); - if (compilerOptions.isAnnotationBasedResourceAnalysisEnabled - && this.binding.isClosingMethod()) - { - // implementation of AutoCloseable.close() should close all @Owning fields, create the obligation now: - ReferenceBinding currentClass = this.binding.declaringClass; - while (currentClass != null) { - for (FieldBinding fieldBinding : currentClass.fields()) { - if (!fieldBinding.isStatic() - && fieldBinding.type.hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable) - && (fieldBinding.tagBits & TagBits.AnnotationOwning) != 0) { - fieldBinding.closeTracker = new FakedTrackingVariable(fieldBinding, this.scope, this, - flowInfo, flowContext, FlowInfo.NULL, true); - } - } - currentClass = currentClass.superclass(); - } - } - // propagate to statements - if (this.statements != null) { - boolean enableSyntacticNullAnalysisForFields = compilerOptions.enableSyntacticNullAnalysisForFields; - 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, true)) < Statement.COMPLAINED_UNREACHABLE) { - flowInfo = stat.analyseCode(this.scope, methodContext, flowInfo); - } - if (enableSyntacticNullAnalysisForFields) { - methodContext.expireNullCheckedFieldInfo(); - } - if (compilerOptions.analyseResourceLeaks) { - FakedTrackingVariable.cleanUpUnassigned(this.scope, stat, flowInfo, false); - } - } - } else { - // method with empty body should not be flagged as static. - this.bits &= ~ASTNode.CanBeStatic; - } - // check for missing returning path - TypeBinding returnTypeBinding = this.binding.returnType; - if ((returnTypeBinding == TypeBinding.VOID) || isAbstract()) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - this.bits |= ASTNode.NeedFreeReturn; - } - } else { - if (flowInfo != FlowInfo.DEAD_END) { - this.scope.problemReporter().shouldReturn(returnTypeBinding, this); - } - } - // check unreachable catch blocks - methodContext.complainIfUnusedExceptionHandlers(this); - // check unused parameters - this.scope.checkUnusedParameters(this.binding); - // check if the method could have been static - if (!this.binding.isStatic() && (this.bits & ASTNode.CanBeStatic) != 0 && !this.isDefaultMethod()) { - if(!this.binding.isOverriding() && !this.binding.isImplementing()) { - if (this.binding.isPrivate() || this.binding.isFinal() || this.binding.declaringClass.isFinal()) { - this.scope.problemReporter().methodCanBeDeclaredStatic(this); - } else { - this.scope.problemReporter().methodCanBePotentiallyDeclaredStatic(this); - } - } - - } - this.scope.checkUnclosedCloseables(flowInfo, null, null/*don't report against a specific location*/, null); - } catch (AbortMethod e) { - this.ignoreFurtherInvestigation = true; - } - } - - @Override - public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this.returnType, targetType, allAnnotationContexts); - for (int i = 0, max = this.annotations.length; i < max; i++) { - Annotation annotation = this.annotations[i]; - annotation.traverse(collector, (BlockScope) null); - } - } - - public boolean hasNullTypeAnnotation(AnnotationPosition position) { - // parser associates SE8 annotations to the declaration - return TypeReference.containsNullAnnotation(this.annotations) || - (this.returnType != null && this.returnType.hasNullTypeAnnotation(position)); // just in case - } - - @Override - public boolean isDefaultMethod() { - return (this.modifiers & ExtraCompilerModifiers.AccDefaultMethod) != 0; - } - - @Override - public boolean isMethod() { - return true; - } - - @Override - public RecordComponent getRecordComponent() { - if (this.arguments != null && this.arguments.length != 0) - return null; - ClassScope skope = this.scope.classScope(); - TypeDeclaration typeDecl = skope.referenceContext; - if (!typeDecl.isRecord()) - return null; - if (!(skope.referenceContext.isRecord())) - return null; - RecordComponent[] recComps = typeDecl.recordComponents; - if (recComps == null || recComps.length == 0) - return null; - for (RecordComponent recComp : recComps) { - if (recComp == null || recComp.name == null) - continue; - if (CharOperation.equals(this.selector, recComp.name)) { - return recComp; - } - } - return null; - } - - @Override - public void parseStatements(Parser parser, CompilationUnitDeclaration unit) { - //fill up the method body with statement - parser.parse(this, unit); - this.containsSwitchWithTry = parser.switchWithTry; - } - - @Override - public StringBuilder printReturnType(int indent, StringBuilder output) { - if (this.returnType == null) return output; - return this.returnType.printExpression(0, output).append(' '); - } - - @Override - public void resolveStatements() { - // ========= abort on fatal error ============= - if (this.returnType != null && this.binding != null) { - this.bits |= (this.returnType.bits & ASTNode.HasTypeAnnotations); - this.returnType.resolvedType = this.binding.returnType; - // record the return type binding - } - RecordComponent recordComponent = getRecordComponent(); - if (recordComponent != null) { - /* JLS 14 Records Sec 8.10.3 */ - if (this.returnType != null && TypeBinding.notEquals(this.returnType.resolvedType, recordComponent.type.resolvedType)) - this.scope.problemReporter().recordIllegalAccessorReturnType(this.returnType, recordComponent.type.resolvedType); - if (this.typeParameters != null) - this.scope.problemReporter().recordAccessorMethodShouldNotBeGeneric(this); - if (this.binding != null) { - if ((this.binding.modifiers & ClassFileConstants.AccPublic) == 0) - this.scope.problemReporter().recordAccessorMethodShouldBePublic(this); - if ((this.binding.modifiers & ClassFileConstants.AccStatic) != 0) - this.scope.problemReporter().recordAccessorMethodShouldNotBeStatic(this); - } - if (this.thrownExceptions != null) - this.scope.problemReporter().recordAccessorMethodHasThrowsClause(this); - } - // check if method with constructor name - if (CharOperation.equals(this.scope.enclosingSourceType().sourceName, this.selector)) { - this.scope.problemReporter().methodWithConstructorName(this); - } - // to check whether the method returns a type parameter not declared by it. - boolean returnsUndeclTypeVar = false; - if (this.returnType != null && this.returnType.resolvedType instanceof TypeVariableBinding) { - returnsUndeclTypeVar = true; - } - if (this.typeParameters != null) { - for (int i = 0, length = this.typeParameters.length; i < length; i++) { - TypeParameter typeParameter = this.typeParameters[i]; - this.bits |= (typeParameter.bits & ASTNode.HasTypeAnnotations); - // typeParameter is already resolved from Scope#connectTypeVariables() - if (returnsUndeclTypeVar && TypeBinding.equalsEquals(this.typeParameters[i].binding, this.returnType.resolvedType)) { - returnsUndeclTypeVar = false; - } - } - } - - // check @Override annotation - final CompilerOptions compilerOptions = this.scope.compilerOptions(); - checkOverride: { - // For a record component accessor method, don't bother with checking for override (JLS 15 9.6.4.4) - if (this.binding == null || recordComponent != null) break checkOverride; - long complianceLevel = compilerOptions.complianceLevel; - if (complianceLevel < ClassFileConstants.JDK1_5) break checkOverride; - int bindingModifiers = this.binding.modifiers; - boolean hasOverrideAnnotation = (this.binding.tagBits & TagBits.AnnotationOverride) != 0; - boolean hasUnresolvedArguments = (this.binding.tagBits & TagBits.HasUnresolvedArguments) != 0; - if (hasOverrideAnnotation && !hasUnresolvedArguments) { - // no static method is considered overriding - if ((bindingModifiers & (ClassFileConstants.AccStatic|ExtraCompilerModifiers.AccOverriding)) == ExtraCompilerModifiers.AccOverriding) - break checkOverride; - // in 1.5, strictly for overriding superclass method - // in 1.6 and above, also tolerate implementing interface method - if (complianceLevel >= ClassFileConstants.JDK1_6 - && ((bindingModifiers & (ClassFileConstants.AccStatic|ExtraCompilerModifiers.AccImplementing)) == ExtraCompilerModifiers.AccImplementing)) - break checkOverride; - // claims to override, and doesn't actually do so - this.scope.problemReporter().methodMustOverride(this, complianceLevel); - } else { - //In case of a concrete class method, we have to check if it overrides(in 1.5 and above) OR implements a method(1.6 and above). - //Also check if the method has a signature that is override-equivalent to that of any public method declared in Object. - if (!this.binding.declaringClass.isInterface()){ - if((bindingModifiers & (ClassFileConstants.AccStatic|ExtraCompilerModifiers.AccOverriding)) == ExtraCompilerModifiers.AccOverriding) { - this.scope.problemReporter().missingOverrideAnnotation(this); - } else { - if(complianceLevel >= ClassFileConstants.JDK1_6 - && compilerOptions.reportMissingOverrideAnnotationForInterfaceMethodImplementation - && this.binding.isImplementing()) { - // actually overrides, but did not claim to do so - this.scope.problemReporter().missingOverrideAnnotationForInterfaceMethodImplementation(this); - } - - } - } - else { //For 1.6 and above only - //In case of a interface class method, we have to check if it overrides a method (isImplementing returns true in case it overrides) - //Also check if the method has a signature that is override-equivalent to that of any public method declared in Object. - if(complianceLevel >= ClassFileConstants.JDK1_6 - && compilerOptions.reportMissingOverrideAnnotationForInterfaceMethodImplementation - && (((bindingModifiers & (ClassFileConstants.AccStatic|ExtraCompilerModifiers.AccOverriding)) == ExtraCompilerModifiers.AccOverriding) || this.binding.isImplementing())){ - // actually overrides, but did not claim to do so - this.scope.problemReporter().missingOverrideAnnotationForInterfaceMethodImplementation(this); - } - } - } - } - - switch (TypeDeclaration.kind(this.scope.referenceType().modifiers)) { - case TypeDeclaration.ENUM_DECL : - if (this.selector == TypeConstants.VALUES) break; - if (this.selector == TypeConstants.VALUEOF) break; - //$FALL-THROUGH$ - case TypeDeclaration.CLASS_DECL : - case TypeDeclaration.RECORD_DECL: - // if a method has an semicolon body and is not declared as abstract==>error - // native methods may have a semicolon body - if ((this.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) { - if ((this.modifiers & ClassFileConstants.AccNative) == 0) - if ((this.modifiers & ClassFileConstants.AccAbstract) == 0) - this.scope.problemReporter().methodNeedBody(this); - } else { - // the method HAS a body --> abstract native modifiers are forbidden - if (((this.modifiers & ClassFileConstants.AccNative) != 0) || ((this.modifiers & ClassFileConstants.AccAbstract) != 0)) - this.scope.problemReporter().methodNeedingNoBody(this); - else if (this.binding == null || this.binding.isStatic() || (this.binding.declaringClass instanceof LocalTypeBinding) || returnsUndeclTypeVar) { - // Cannot be static for one of the reasons stated above - this.bits &= ~ASTNode.CanBeStatic; - } - } - break; - case TypeDeclaration.INTERFACE_DECL : - if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 - && (this.modifiers & (ExtraCompilerModifiers.AccSemicolonBody | ClassFileConstants.AccAbstract)) == ExtraCompilerModifiers.AccSemicolonBody) { - boolean isPrivateMethod = compilerOptions.sourceLevel >= ClassFileConstants.JDK9 && (this.modifiers & ClassFileConstants.AccPrivate) != 0; - if (isPrivateMethod || ((this.modifiers & (ClassFileConstants.AccStatic | ExtraCompilerModifiers.AccDefaultMethod)) != 0)) { - this.scope.problemReporter().methodNeedBody(this); - } - } - break; - } - super.resolveStatements(); - - // TagBits.OverridingMethodWithSupercall is set during the resolveStatements() call - if (compilerOptions.getSeverity(CompilerOptions.OverridingMethodWithoutSuperInvocation) != ProblemSeverities.Ignore) { - if (this.binding != null) { - int bindingModifiers = this.binding.modifiers; - if ((bindingModifiers & (ExtraCompilerModifiers.AccOverriding|ExtraCompilerModifiers.AccImplementing)) == ExtraCompilerModifiers.AccOverriding - && (this.bits & ASTNode.OverridingMethodWithSupercall) == 0) { - this.scope.problemReporter().overridesMethodWithoutSuperInvocation(this.binding); - } - } - } - } - - @Override - public void traverse( - ASTVisitor visitor, - ClassScope classScope) { - - if (visitor.visit(this, classScope)) { - if (this.javadoc != null) { - this.javadoc.traverse(visitor, this.scope); - } - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, this.scope); - } - if (this.typeParameters != null) { - int typeParametersLength = this.typeParameters.length; - for (int i = 0; i < typeParametersLength; i++) { - this.typeParameters[i].traverse(visitor, this.scope); - } - } - if (this.returnType != null) - this.returnType.traverse(visitor, this.scope); - if (this.arguments != null) { - int argumentLength = this.arguments.length; - for (int i = 0; i < argumentLength; i++) - this.arguments[i].traverse(visitor, this.scope); - } - if (this.thrownExceptions != null) { - int thrownExceptionsLength = this.thrownExceptions.length; - for (int i = 0; i < thrownExceptionsLength; i++) - this.thrownExceptions[i].traverse(visitor, this.scope); - } - if (this.statements != null) { - int statementsLength = this.statements.length; - for (int i = 0; i < statementsLength; i++) - this.statements[i].traverse(visitor, this.scope); - } - } - visitor.endVisit(this, classScope); - } - @Override - public TypeParameter[] typeParameters() { - return this.typeParameters; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java deleted file mode 100644 index 7ca7079..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ModuleDeclaration.java +++ /dev/null @@ -1,470 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.problem.ProblemSeverities.*; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jdt.core.compiler.CategorizedProblem; -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ClassFile; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.ModuleScope; -import org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.SourceModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit; -import org.eclipse.jdt.internal.compiler.problem.AbortMethod; -import org.eclipse.jdt.internal.compiler.problem.AbortType; -import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; - -public class ModuleDeclaration extends ASTNode implements ReferenceContext { - - public ExportsStatement[] exports; - public RequiresStatement[] requires; - public UsesStatement[] uses; - public ProvidesStatement[] services; - public OpensStatement[] opens; - public Annotation[] annotations; - public int exportsCount; - public int requiresCount; - public int usesCount; - public int servicesCount; - public int opensCount; - public SourceModuleBinding binding; - public int declarationSourceStart; - public int declarationSourceEnd; - public int bodyStart; - public int bodyEnd; // doesn't include the trailing comment if any. - public int modifiersSourceStart; - public ModuleScope scope; - public char[][] tokens; - public char[] moduleName; - public long[] sourcePositions; - public int modifiers = ClassFileConstants.AccDefault; - boolean ignoreFurtherInvestigation; - boolean hasResolvedModuleDirectives; - boolean hasResolvedPackageDirectives; - boolean hasResolvedTypeDirectives; - CompilationResult compilationResult; - - public ModuleDeclaration(CompilationResult compilationResult, char[][] tokens, long[] positions) { - this.compilationResult = compilationResult; - this.exportsCount = 0; - this.requiresCount = 0; - this.tokens = tokens; - this.moduleName = CharOperation.concatWith(tokens, '.'); - this.sourcePositions = positions; - this.sourceEnd = (int) (positions[positions.length-1] & 0x00000000FFFFFFFF); - this.sourceStart = (int) (positions[0] >>> 32); - } - - public ModuleBinding setBinding(SourceModuleBinding sourceModuleBinding) { - this.binding = sourceModuleBinding; - return sourceModuleBinding; - } - - public void checkAndSetModifiers() { - int realModifiers = this.modifiers & ExtraCompilerModifiers.AccJustFlag; - int expectedModifiers = ClassFileConstants.ACC_OPEN | ClassFileConstants.ACC_SYNTHETIC; - if ((realModifiers & ~(expectedModifiers)) != 0) { - this.scope.problemReporter().illegalModifierForModule(this); - realModifiers &= expectedModifiers; - } - int effectiveModifiers = ClassFileConstants.AccModule | realModifiers; - this.modifiers = this.binding.modifiers = effectiveModifiers; - } - - public boolean isOpen() { - return (this.modifiers & ClassFileConstants.ACC_OPEN) != 0; - } - - public void createScope(final Scope parentScope) { - this.scope = new ModuleScope(parentScope, this); - } - - public void generateCode() { - if ((this.bits & ASTNode.HasBeenGenerated) != 0) - return; - this.bits |= ASTNode.HasBeenGenerated; - if (this.ignoreFurtherInvestigation) { - return; - } - try { - // create the result for a compiled type - LookupEnvironment env = this.scope.environment(); - ClassFile classFile = env.classFilePool.acquireForModule(this.binding, env.globalOptions); - classFile.initializeForModule(this.binding); - - // finalize the compiled type result - classFile.addModuleAttributes(this.binding, this.annotations, this.scope.referenceCompilationUnit()); - this.scope.referenceCompilationUnit().compilationResult.record( - this.binding.moduleName, - classFile); - } catch (AbortType e) { - if (this.binding == null) - return; - } - } - - /** Resolve those module directives that relate to modules (requires). */ - public void resolveModuleDirectives(CompilationUnitScope cuScope) { - if (this.binding == null) { - this.ignoreFurtherInvestigation = true; - return; - } - if (this.hasResolvedModuleDirectives) - return; - - this.hasResolvedModuleDirectives = true; - - Set requiredModules = new HashSet<>(); - Set requiredTransitiveModules = new HashSet<>(); - for(int i = 0; i < this.requiresCount; i++) { - RequiresStatement ref = this.requires[i]; - if (ref != null && ref.resolve(cuScope) != null) { - if (!requiredModules.add(ref.resolvedBinding)) { - cuScope.problemReporter().duplicateModuleReference(IProblem.DuplicateRequires, ref.module); - } - if (ref.isTransitive()) - requiredTransitiveModules.add(ref.resolvedBinding); - Collection deps = ref.resolvedBinding.dependencyGraphCollector().get(); - if (deps.contains(this.binding)) { - cuScope.problemReporter().cyclicModuleDependency(this.binding, ref.module); - requiredModules.remove(ref.module.binding); - } - } - } - this.binding.setRequires(requiredModules.toArray(new ModuleBinding[requiredModules.size()]), - requiredTransitiveModules.toArray(new ModuleBinding[requiredTransitiveModules.size()])); - - // also resolve module references inside package statements ("to"): - if (this.exports != null) { - for (ExportsStatement exportsStatement : this.exports) { - if (exportsStatement.isQualified()) { - for (ModuleReference moduleReference : exportsStatement.targets) - moduleReference.resolve(cuScope); - } - } - } - if (this.opens != null) { - for (OpensStatement opensStatement : this.opens) { - if (opensStatement.isQualified()) { - for (ModuleReference moduleReference : opensStatement.targets) - moduleReference.resolve(cuScope); - } - } - } - } - - /** Resolve those module directives that relate to packages (exports, opens). */ - public void resolvePackageDirectives(CompilationUnitScope cuScope) { - if (this.binding == null) { - this.ignoreFurtherInvestigation = true; - return; - } - if (this.hasResolvedPackageDirectives) - return; - - this.hasResolvedPackageDirectives = true; - - Set exportedPkgs = new HashSet<>(); - for (int i = 0; i < this.exportsCount; i++) { - ExportsStatement ref = this.exports[i]; - if (ref != null && ref.resolve(cuScope)) { - if (!exportedPkgs.add(ref.resolvedPackage)) { - cuScope.problemReporter().invalidPackageReference(IProblem.DuplicateExports, ref); - } - char[][] targets = null; - if (ref.targets != null) { - targets = new char[ref.targets.length][]; - for (int j = 0; j < targets.length; j++) - targets[j] = ref.targets[j].moduleName; - } - this.binding.addResolvedExport(ref.resolvedPackage, targets); - } - } - - HashtableOfObject openedPkgs = new HashtableOfObject(); - for (int i = 0; i < this.opensCount; i++) { - OpensStatement ref = this.opens[i]; - if (isOpen()) { - cuScope.problemReporter().invalidOpensStatement(ref, this); - } else { - if (openedPkgs.containsKey(ref.pkgName)) { - cuScope.problemReporter().invalidPackageReference(IProblem.DuplicateOpens, ref); - } else { - openedPkgs.put(ref.pkgName, ref); - ref.resolve(cuScope); - } - char[][] targets = null; - if (ref.targets != null) { - targets = new char[ref.targets.length][]; - for (int j = 0; j < targets.length; j++) - targets[j] = ref.targets[j].moduleName; - } - this.binding.addResolvedOpens(ref.resolvedPackage, targets); - } - } - } - - /** Resolve those module directives that relate to types (provides / uses). */ - public void resolveTypeDirectives(CompilationUnitScope cuScope) { - if (this.binding == null) { - this.ignoreFurtherInvestigation = true; - return; - } - if (this.hasResolvedTypeDirectives) - return; - - this.hasResolvedTypeDirectives = true; - ASTNode.resolveAnnotations(this.scope, this.annotations, this.binding); - - Set allTypes = new HashSet<>(); - for(int i = 0; i < this.usesCount; i++) { - TypeBinding serviceBinding = this.uses[i].serviceInterface.resolveType(this.scope); - if (serviceBinding != null && serviceBinding.isValidBinding()) { - if (!(serviceBinding.isClass() || serviceBinding.isInterface() || serviceBinding.isAnnotationType())) { - cuScope.problemReporter().invalidServiceRef(IProblem.InvalidServiceIntfType, this.uses[i].serviceInterface); - } - if (!allTypes.add(this.uses[i].serviceInterface.resolvedType)) { - cuScope.problemReporter().duplicateTypeReference(IProblem.DuplicateUses, this.uses[i].serviceInterface); - } - } - } - this.binding.setUses(allTypes.toArray(new TypeBinding[allTypes.size()])); - - Set interfaces = new HashSet<>(); - for(int i = 0; i < this.servicesCount; i++) { - this.services[i].resolve(this.scope); - TypeBinding infBinding = this.services[i].serviceInterface.resolvedType; - if (infBinding != null && infBinding.isValidBinding()) { - if (!interfaces.add(this.services[i].serviceInterface.resolvedType)) { - cuScope.problemReporter().duplicateTypeReference(IProblem.DuplicateServices, - this.services[i].serviceInterface); - } - this.binding.setImplementations(infBinding, this.services[i].getResolvedImplementations()); - } - } - this.binding.setServices(interfaces.toArray(new TypeBinding[interfaces.size()])); - } - - public void analyseCode(CompilationUnitScope skope) { - analyseModuleGraph(skope); - analyseReferencedPackages(skope); - } - - private void analyseReferencedPackages(CompilationUnitScope skope) { - if (this.exports != null) { - analyseSomeReferencedPackages(this.exports, skope); - } - if (this.opens != null) { - analyseSomeReferencedPackages(this.opens, skope); - } - } - - private void analyseSomeReferencedPackages(PackageVisibilityStatement[] stats, CompilationUnitScope skope) { - for (PackageVisibilityStatement stat : stats) { - PlainPackageBinding pb = stat.resolvedPackage; - if (pb == null) - continue; - if (pb.hasCompilationUnit(true)) - continue; - for (ModuleBinding req : this.binding.getAllRequiredModules()) { - for (PlainPackageBinding exported : req.getExports()) { - if (CharOperation.equals(pb.compoundName, exported.compoundName)) { - skope.problemReporter().exportingForeignPackage(stat, req); - return; - } - } - } - skope.problemReporter().invalidPackageReference(IProblem.PackageDoesNotExistOrIsEmpty, stat); - } - } - - public void analyseModuleGraph(CompilationUnitScope skope) { - if (this.requires != null) { - // collect transitively: - Map> pack2mods = new HashMap<>(); - for (ModuleBinding requiredModule : this.binding.getAllRequiredModules()) { - for (PlainPackageBinding exportedPackage : requiredModule.getExports()) { - if (this.binding.canAccess(exportedPackage)) { - String packName = String.valueOf(exportedPackage.readableName()); - Set mods = pack2mods.get(packName); - if (mods == null) - pack2mods.put(packName, mods = new HashSet<>()); - mods.add(requiredModule); - } - } - } - // report against the causing requires directives: - for (RequiresStatement requiresStat : this.requires) { - ModuleBinding requiredModule = requiresStat.resolvedBinding; - if (requiredModule != null) { - if (requiredModule.isDeprecated()) - skope.problemReporter().deprecatedModule(requiresStat.module, requiredModule); - analyseOneDependency(requiresStat, requiredModule, skope, pack2mods); - if (requiresStat.isTransitive()) { - for (ModuleBinding secondLevelModule : requiredModule.getAllRequiredModules()) - analyseOneDependency(requiresStat, secondLevelModule, skope, pack2mods); - } - } - } - } - } - - private void analyseOneDependency(RequiresStatement requiresStat, ModuleBinding requiredModule, CompilationUnitScope skope, - Map> pack2mods) - { - for (PlainPackageBinding pack : requiredModule.getExports()) { - Set mods = pack2mods.get(String.valueOf(pack.readableName())); - if (mods != null && mods.size() > 1) { - CompilerOptions compilerOptions = skope.compilerOptions(); - boolean inJdtDebugCompileMode = compilerOptions.enableJdtDebugCompileMode; - if (!inJdtDebugCompileMode) { - skope.problemReporter().conflictingPackagesFromModules(pack, mods, requiresStat.sourceStart, requiresStat.sourceEnd); - } - } - } - } - - public void traverse(ASTVisitor visitor, CompilationUnitScope unitScope) { - visitor.visit(this, unitScope); - } - - public StringBuilder printHeader(int indent, StringBuilder output) { - if (this.annotations != null) { - for (int i = 0; i < this.annotations.length; i++) { - this.annotations[i].print(indent, output); - if (i != this.annotations.length - 1) - output.append(" "); //$NON-NLS-1$ - } - output.append('\n'); - } - if (isOpen()) { - output.append("open "); //$NON-NLS-1$ - } - output.append("module "); //$NON-NLS-1$ - output.append(CharOperation.charToString(this.moduleName)); - return output; - } - public StringBuilder printBody(int indent, StringBuilder output) { - output.append(" {"); //$NON-NLS-1$ - if (this.requires != null) { - for(int i = 0; i < this.requiresCount; i++) { - output.append('\n'); - printIndent(indent + 1, output); - this.requires[i].print(0, output); - } - } - if (this.exports != null) { - for(int i = 0; i < this.exportsCount; i++) { - output.append('\n'); - this.exports[i].print(indent + 1, output); - } - } - if (this.opens != null) { - for(int i = 0; i < this.opensCount; i++) { - output.append('\n'); - this.opens[i].print(indent + 1, output); - } - } - if (this.uses != null) { - for(int i = 0; i < this.usesCount; i++) { - output.append('\n'); - this.uses[i].print(indent + 1, output); - } - } - if (this.servicesCount != 0) { - for(int i = 0; i < this.servicesCount; i++) { - output.append('\n'); - this.services[i].print(indent + 1, output); - } - } - output.append('\n'); - return printIndent(indent, output).append('}'); - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - // - printIndent(indent, output); - printHeader(0, output); - return printBody(indent, output); - } - - @Override - public void abort(int abortLevel, CategorizedProblem problem) { - switch (abortLevel) { - case AbortCompilation : - throw new AbortCompilation(this.compilationResult, problem); - case AbortCompilationUnit : - throw new AbortCompilationUnit(this.compilationResult, problem); - case AbortMethod : - throw new AbortMethod(this.compilationResult, problem); - default : - throw new AbortType(this.compilationResult, problem); - } - } - - @Override - public CompilationResult compilationResult() { - return this.compilationResult; - } - - @Override - public CompilationUnitDeclaration getCompilationUnitDeclaration() { - return this.scope.referenceCompilationUnit(); - } - - @Override - public boolean hasErrors() { - return this.ignoreFurtherInvestigation; - } - - @Override - public void tagAsHavingErrors() { - this.ignoreFurtherInvestigation = true; - } - - @Override - public void tagAsHavingIgnoredMandatoryErrors(int problemId) { - // Nothing to do for this context; - } - - public String getModuleVersion() { - if (this.scope != null) { - LookupEnvironment env = this.scope.environment().root; - return env.moduleVersion; - } - return null; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ModuleReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ModuleReference.java deleted file mode 100644 index 419f57b..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ModuleReference.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; - -public class ModuleReference extends ASTNode { - public char[][] tokens; - public long[] sourcePositions; //each entry is using the code : (start<<32) + end - public char[] moduleName; - public ModuleBinding binding = null; - - public ModuleReference(char[][] tokens, long[] sourcePositions) { - this.tokens = tokens; - this.sourcePositions = sourcePositions; - this.sourceEnd = (int) (sourcePositions[sourcePositions.length - 1] & 0x00000000FFFFFFFF); - this.sourceStart = (int) (sourcePositions[0] >>> 32); - this.moduleName = CharOperation.concatWith(tokens, '.'); - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - for (int i = 0; i < this.tokens.length; i++) { - if (i > 0) output.append('.'); - output.append(this.tokens[i]); - } - return output; - } - - public ModuleBinding resolve(Scope scope) { - if (scope == null || this.binding != null) - return this.binding; - return this.binding = scope.environment().getModule(this.moduleName); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ModuleStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ModuleStatement.java deleted file mode 100644 index ba1fbbb..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ModuleStatement.java +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -/** - * Just a marker class to represent statements that can occur in a module declaration - */ -public abstract class ModuleStatement extends ASTNode { - - public int declarationEnd; - public int declarationSourceStart; - public int declarationSourceEnd; -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NameReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NameReference.java deleted file mode 100644 index 2054aa6..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NameReference.java +++ /dev/null @@ -1,134 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 331649 - [compiler][null] consider null annotations for fields - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 426996 - [1.8][inference] try to avoid method Expression.unresolve()? - * Jesper S Moller - Contributions for - * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.function.Predicate; - -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.problem.AbortMethod; - -public abstract class NameReference extends Reference implements InvocationSite { - - public Binding binding; //may be aTypeBinding-aFieldBinding-aLocalVariableBinding - - public TypeBinding actualReceiverType; // modified receiver type - actual one according to namelookup - - //the error printing - //some name reference are build as name reference but - //only used as type reference. When it happens, instead of - //creating a new object (aTypeReference) we just flag a boolean - //This concesion is valuable while there are cases when the NameReference - //will be a TypeReference (static message sends.....) and there is - //no changeClass in java. -public NameReference() { - this.bits |= Binding.TYPE | Binding.VARIABLE; // restrictiveFlag -} - -/** - * Use this method only when sure that the current reference is not - * a chain of several fields (QualifiedNameReference with more than one field). - * Otherwise use {@link #lastFieldBinding()}. - */ -@Override -public FieldBinding fieldBinding() { - //this method should be sent ONLY after a check against isFieldReference() - //check its use doing senders......... - return (FieldBinding) this.binding ; -} - -@Override -public FieldBinding lastFieldBinding() { - if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) - return fieldBinding(); // most subclasses only refer to one field anyway - return null; -} - -@Override -public InferenceContext18 freshInferenceContext(Scope scope) { - return null; -} - -@Override -public boolean isSuperAccess() { - return false; -} - -@Override -public boolean isTypeAccess() { - // null is acceptable when we are resolving the first part of a reference - return this.binding == null || (this.binding.kind() & Binding.TYPE) != 0; -} - -@Override -public boolean isTypeReference() { - return this.binding instanceof ReferenceBinding; -} - -@Override -public void setActualReceiverType(ReferenceBinding receiverType) { - if (receiverType == null) return; // error scenario only - this.actualReceiverType = receiverType; -} - -@Override -public void setDepth(int depth) { - this.bits &= ~DepthMASK; // flush previous depth if any - if (depth > 0) { - this.bits |= (depth & 0xFF) << DepthSHIFT; // encoded on 8 bits - } -} - -@Override -public void setFieldIndex(int index){ - // ignored -} - -public abstract String unboundReferenceErrorName(); - -public abstract char[][] getName(); - -/* Called during code generation to ensure that outer locals's effectively finality is guaranteed. - Aborts if constraints are violated. Due to various complexities, this check is not conveniently - implementable in resolve/analyze phases. - Another quirk here is this method tells the clients whether the below condition is true - (this.bits & ASTNode.IsCapturedOuterLocal) != 0 -*/ -public boolean checkEffectiveFinality(VariableBinding localBinding, Scope scope) { - Predicate test = local -> (!localBinding.isFinal() && !localBinding.isEffectivelyFinal()); - if ((this.bits & ASTNode.IsCapturedOuterLocal) != 0) { - if (test.test(localBinding)) { - scope.problemReporter().cannotReferToNonEffectivelyFinalOuterLocal(localBinding, this); - throw new AbortMethod(scope.referenceCompilationUnit().compilationResult, null); - } - return true; - } else if ((this.bits & ASTNode.IsUsedInPatternGuard) != 0) { - if (test.test(localBinding)) { - scope.problemReporter().cannotReferToNonFinalLocalInGuard(localBinding, this); - throw new AbortMethod(scope.referenceCompilationUnit().compilationResult, null); - } - } - return false; -} - -@Override -public boolean isType() { - return (this.bits & Binding.TYPE) != 0; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NormalAnnotation.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NormalAnnotation.java deleted file mode 100644 index e1a8a7d..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NormalAnnotation.java +++ /dev/null @@ -1,95 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.*; - -/** - * Normal annotation node - */ -public class NormalAnnotation extends Annotation { - - public MemberValuePair[] memberValuePairs; - - public NormalAnnotation(TypeReference type, int sourceStart) { - this.type = type; - this.sourceStart = sourceStart; - this.sourceEnd = type.sourceEnd; - } - - @Override - public ElementValuePair[] computeElementValuePairs() { - int numberOfPairs = this.memberValuePairs == null ? 0 : this.memberValuePairs.length; - if (numberOfPairs == 0) - return Binding.NO_ELEMENT_VALUE_PAIRS; - - ElementValuePair[] pairs = new ElementValuePair[numberOfPairs]; - for (int i = 0; i < numberOfPairs; i++) - pairs[i] = this.memberValuePairs[i].compilerElementPair; - return pairs; - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.Annotation#memberValuePairs() - */ - @Override - public MemberValuePair[] memberValuePairs() { - return this.memberValuePairs == null ? NoValuePairs : this.memberValuePairs; - } - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - super.printExpression(indent, output); - output.append('('); - if (this.memberValuePairs != null) { - for (int i = 0, max = this.memberValuePairs.length; i < max; i++) { - if (i > 0) { - output.append(','); - } - this.memberValuePairs[i].print(indent, output); - } - } - output.append(')'); - return output; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.type != null) { - this.type.traverse(visitor, scope); - } - if (this.memberValuePairs != null) { - int memberValuePairsLength = this.memberValuePairs.length; - for (int i = 0; i < memberValuePairsLength; i++) - this.memberValuePairs[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.type != null) { - this.type.traverse(visitor, scope); - } - if (this.memberValuePairs != null) { - int memberValuePairsLength = this.memberValuePairs.length; - for (int i = 0; i < memberValuePairsLength; i++) - this.memberValuePairs[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java deleted file mode 100644 index 8afda56..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java +++ /dev/null @@ -1,830 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2013, 2020 GK Software AG and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Stephan Herrmann - initial API and implementation - * Till Brychcy - Contributions for - * Bug 467482 - TYPE_USE null annotations: Incorrect "Redundant null check"-warning - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.CaptureBinding; -import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.Substitution; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBindingVisitor; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; - -/** - * Performs matching of null type annotations. - * Instances are used to encode result from this analysis. - * @since 3.10 - */ -public class NullAnnotationMatching { - - public static final NullAnnotationMatching NULL_ANNOTATIONS_OK = new NullAnnotationMatching(Severity.OK, FlowInfo.UNKNOWN, null); - public static final NullAnnotationMatching NULL_ANNOTATIONS_OK_NONNULL = new NullAnnotationMatching(Severity.OK, FlowInfo.NON_NULL, null); - public static final NullAnnotationMatching NULL_ANNOTATIONS_UNCHECKED = new NullAnnotationMatching(Severity.UNCHECKED, FlowInfo.UNKNOWN, null); - public static final NullAnnotationMatching NULL_ANNOTATIONS_MISMATCH = new NullAnnotationMatching(Severity.MISMATCH, FlowInfo.UNKNOWN, null); - - public enum CheckMode { - /** in this mode we check normal assignment compatibility. */ - COMPATIBLE { - @Override boolean requiredNullableMatchesAll() { - return true; - } - }, - /** in this mode we check similar to isTypeArgumentContained. */ - EXACT, - /** in this mode we check compatibility of a type argument against the corresponding type parameter. */ - BOUND_CHECK, - /** similar to COMPATIBLE, but for type variables we look for instantiations, rather than treating them as "free type variables". */ - BOUND_SUPER_CHECK, - /** allow covariant return types, but no other deviations. */ - OVERRIDE_RETURN { - @Override CheckMode toDetail() { - return OVERRIDE; - } - }, - /** in this mode we do not tolerate incompatibly missing annotations on type parameters (for overriding analysis) */ - OVERRIDE { - @Override boolean requiredNullableMatchesAll() { - return true; - } - @Override CheckMode toDetail() { - return OVERRIDE; - } - }; - - boolean requiredNullableMatchesAll() { - return false; - } - CheckMode toDetail() { - return CheckMode.EXACT; - } - } - - private enum Severity { - /** No problem detected. */ - OK, - /** No real problem, but could issue an {@link IProblem#NonNullTypeVariableFromLegacyMethod} or similar. */ - LEGACY_WARNING, - /** Need unchecked conversion from unannotated to annotated. */ - UNCHECKED, - /** Need unchecked conversion to pass type with annotated type arguments into unannotated code. */ - UNCHECKED_TO_UNANNOTATED, - /** Definite nullity mismatch. */ - MISMATCH; - - public Severity max(Severity severity) { - if (compareTo(severity) < 0) - return severity; - return this; - } - - public boolean isAnyMismatch() { - return compareTo(LEGACY_WARNING) > 0; - } - } - - private final Severity severity; - private final boolean problemAtDetail; - - /** If non-null this field holds the supertype of the provided type which was used for direct matching. */ - public final TypeBinding superTypeHint; - public final int nullStatus; - - NullAnnotationMatching(Severity severity, int nullStatus, TypeBinding superTypeHint) { - this(false, severity, nullStatus, superTypeHint); - } - NullAnnotationMatching(boolean atDetail, Severity severity, int nullStatus, TypeBinding superTypeHint) { - this.severity = severity; - this.superTypeHint = superTypeHint; - this.nullStatus = nullStatus; - this.problemAtDetail = atDetail; - } - - /** - * For creating updated status during *FlowContext.complainOnDeferred*Checks() once the actual nullStatus is known - */ - public NullAnnotationMatching withNullStatus(int updatedNullStatus) { - return updatedNullStatus == this.nullStatus ? this - : new NullAnnotationMatching(this.severity, updatedNullStatus, this.superTypeHint); - } - - public boolean isAnyMismatch() { return this.severity.isAnyMismatch(); } - public boolean isUnchecked() { return this.severity == Severity.UNCHECKED || this.severity == Severity.UNCHECKED_TO_UNANNOTATED; } - public boolean isAnnotatedToUnannotated() { return this.severity == Severity.UNCHECKED_TO_UNANNOTATED; } - public boolean isDefiniteMismatch() { return this.severity == Severity.MISMATCH; } - public boolean wantToReport() { return this.severity == Severity.LEGACY_WARNING; } - - public boolean isPotentiallyNullMismatch() { - return !isDefiniteMismatch() && this.nullStatus != -1 && (this.nullStatus & FlowInfo.POTENTIALLY_NULL) != 0; - } - - public String superTypeHintName(CompilerOptions options, boolean shortNames) { - return String.valueOf(this.superTypeHint.nullAnnotatedReadableName(options, shortNames)); - } - - /** Check null-ness of 'var' against a possible null annotation */ - public static int checkAssignment(BlockScope currentScope, FlowContext flowContext, - VariableBinding var, FlowInfo flowInfo, int nullStatus, Expression expression, TypeBinding providedType) - { - if (providedType == null) return FlowInfo.UNKNOWN; // assume we already reported an error - long lhsTagBits = 0L; - boolean hasReported = false; - boolean usesNullTypeAnnotations = currentScope.environment().usesNullTypeAnnotations(); - if (!usesNullTypeAnnotations) { - lhsTagBits = var.tagBits & TagBits.AnnotationNullMASK; - } else { - if (expression instanceof ConditionalExpression && expression.isPolyExpression()) { - // drill into both branches: - ConditionalExpression ce = ((ConditionalExpression) expression); - int status1 = NullAnnotationMatching.checkAssignment(currentScope, flowContext, var, flowInfo, ce.ifTrueNullStatus, ce.valueIfTrue, ce.valueIfTrue.resolvedType); - int status2 = NullAnnotationMatching.checkAssignment(currentScope, flowContext, var, flowInfo, ce.ifFalseNullStatus, ce.valueIfFalse, ce.valueIfFalse.resolvedType); - if (status1 == status2) - return status1; - return nullStatus; // if both branches disagree use the precomputed & merged nullStatus - } else if (expression instanceof SwitchExpression && expression.isPolyExpression()) { - // drill into all the branches: - SwitchExpression se = ((SwitchExpression) expression); - Expression[] resExprs = se.resultExpressions.toArray(new Expression[0]); - Expression re = resExprs[0]; - int status0 = NullAnnotationMatching.checkAssignment(currentScope, flowContext, var, flowInfo, re.nullStatus(flowInfo, flowContext), re, re.resolvedType); - boolean identicalStatus = true; - for (int i = 1, l = resExprs.length; i < l; ++i) { - re = resExprs[i]; - int otherStatus = NullAnnotationMatching.checkAssignment(currentScope, flowContext, var, flowInfo, re.nullStatus(flowInfo, flowContext), re, re.resolvedType); - identicalStatus &= status0 == otherStatus; - } - return identicalStatus ? status0 : nullStatus; // if not all branches agree use the precomputed & merged nullStatus - } - lhsTagBits = var.type.tagBits & TagBits.AnnotationNullMASK; - NullAnnotationMatching annotationStatus = analyse(var.type, providedType, null, null, nullStatus, expression, CheckMode.COMPATIBLE); - if (annotationStatus.isAnyMismatch()) { - flowContext.recordNullityMismatch(currentScope, expression, providedType, var.type, flowInfo, nullStatus, annotationStatus); - hasReported = true; - } else { - if (annotationStatus.wantToReport()) - annotationStatus.report(currentScope); - if (annotationStatus.nullStatus != FlowInfo.UNKNOWN) { - return annotationStatus.nullStatus; - } - } - } - if (lhsTagBits == TagBits.AnnotationNonNull && nullStatus != FlowInfo.NON_NULL) { - if (!hasReported) - flowContext.recordNullityMismatch(currentScope, expression, providedType, var.type, flowInfo, nullStatus, null); - return FlowInfo.NON_NULL; - } else if (lhsTagBits == TagBits.AnnotationNullable && nullStatus == FlowInfo.UNKNOWN) { // provided a legacy type? - if (usesNullTypeAnnotations && providedType.isTypeVariable() && (providedType.tagBits & TagBits.AnnotationNullMASK) == 0) - return FlowInfo.POTENTIALLY_NULL | FlowInfo.POTENTIALLY_NON_NULL; // -> free type variable can mean either nullable or nonnull - return FlowInfo.POTENTIALLY_NULL | FlowInfo.POTENTIALLY_UNKNOWN; // -> combine info from lhs & rhs - } - return nullStatus; - } - - /** - * Find any mismatches between the two given types, which are caused by null type annotations. - * @param nullStatus we are only interested in NULL or NON_NULL, -1 indicates that we are in a recursion, where flow info is ignored - * @return a status object representing the severity of mismatching plus optionally a supertype hint - */ - public static NullAnnotationMatching analyse(TypeBinding requiredType, TypeBinding providedType, int nullStatus) { - return analyse(requiredType, providedType, null, null, nullStatus, null, CheckMode.COMPATIBLE); - } - /** - * Find any mismatches between the two given types, which are caused by null type annotations. - * @param providedSubstitute in inheritance situations this maps the providedType into the realm of the subclass, needed for TVB identity checks. - * Pass null if not interested in these added checks. - * @param substitution TODO - * @param nullStatus we are only interested in NULL or NON_NULL, -1 indicates that we are in a recursion, where flow info is ignored - * @param providedExpression optionally holds the provided expression of type 'providedType' - * @param mode controls the kind of check performed (see {@link CheckMode}). - * @return a status object representing the severity of mismatching plus optionally a supertype hint - */ - public static NullAnnotationMatching analyse(TypeBinding requiredType, TypeBinding providedType, TypeBinding providedSubstitute, Substitution substitution, - int nullStatus, Expression providedExpression, CheckMode mode) - { - if (!requiredType.enterRecursiveFunction()) - return NullAnnotationMatching.NULL_ANNOTATIONS_OK; - try { - Severity severity = Severity.OK; - TypeBinding superTypeHint = null; - TypeBinding originalRequiredType = requiredType; - NullAnnotationMatching okStatus = NullAnnotationMatching.NULL_ANNOTATIONS_OK; - boolean problemAtDetail = false; - if (areSameTypes(requiredType, providedType, providedSubstitute)) { - if ((requiredType.tagBits & TagBits.AnnotationNonNull) != 0) - return okNonNullStatus(providedExpression); - return okStatus; - } - if (requiredType instanceof TypeVariableBinding && substitution != null && (mode == CheckMode.EXACT || mode == CheckMode.COMPATIBLE || mode == CheckMode.BOUND_SUPER_CHECK)) { - requiredType.exitRecursiveFunction(); - requiredType = Scope.substitute(substitution, requiredType); - if (!requiredType.enterRecursiveFunction()) - return NullAnnotationMatching.NULL_ANNOTATIONS_OK; - if (areSameTypes(requiredType, providedType, providedSubstitute)) { - if ((requiredType.tagBits & TagBits.AnnotationNonNull) != 0) - return okNonNullStatus(providedExpression); - return okStatus; - } - } - if (mode == CheckMode.BOUND_CHECK && requiredType instanceof TypeVariableBinding) { - boolean passedBoundCheck = (substitution instanceof ParameterizedTypeBinding) && (((ParameterizedTypeBinding) substitution).tagBits & TagBits.PassedBoundCheck) != 0; - if (!passedBoundCheck) { - // during bound check against a type variable check the provided type against all upper bounds: - TypeBinding superClass = requiredType.superclass(); - if (superClass != null && (superClass.hasNullTypeAnnotations() || substitution != null)) { // annotations may enter when substituting a nested type variable - NullAnnotationMatching status = analyse(superClass, providedType, null, substitution, nullStatus, providedExpression, CheckMode.BOUND_SUPER_CHECK); - severity = severity.max(status.severity); - if (severity == Severity.MISMATCH) - return new NullAnnotationMatching(true, severity, nullStatus, superTypeHint); - else if (severity != Severity.OK) - problemAtDetail = true; - } - TypeBinding[] superInterfaces = requiredType.superInterfaces(); - if (superInterfaces != null) { - for (int i = 0; i < superInterfaces.length; i++) { - if (superInterfaces[i].hasNullTypeAnnotations() || substitution != null) { // annotations may enter when substituting a nested type variable - NullAnnotationMatching status = analyse(superInterfaces[i], providedType, null, substitution, nullStatus, providedExpression, CheckMode.BOUND_SUPER_CHECK); - severity = severity.max(status.severity); - if (severity == Severity.MISMATCH) - return new NullAnnotationMatching(true, severity, nullStatus, superTypeHint); - else if (severity != Severity.OK) - problemAtDetail = true; - } - } - } - } - } - if (requiredType instanceof ArrayBinding) { - long[] requiredDimsTagBits = ((ArrayBinding)requiredType).nullTagBitsPerDimension; - if (requiredDimsTagBits != null) { - int dims = requiredType.dimensions(); - if (requiredType.dimensions() == providedType.dimensions()) { - long[] providedDimsTagBits = ((ArrayBinding)providedType).nullTagBitsPerDimension; - if (providedDimsTagBits == null) - providedDimsTagBits = new long[dims+1]; // set to unspec'd at all dimensions - int currentNullStatus = nullStatus; - for (int i=0; i<=dims; i++) { - long requiredBits = validNullTagBits(requiredDimsTagBits[i]); - long providedBits = validNullTagBits(providedDimsTagBits[i]); - if (i == 0 && requiredBits == TagBits.AnnotationNullable && nullStatus != -1 && mode.requiredNullableMatchesAll()) { - // toplevel nullable array: no need to check - if (nullStatus == FlowInfo.NULL) - break; // null value has no details - } else { - if (i > 0) - currentNullStatus = -1; // don't use beyond the outermost dimension - Severity dimSeverity = computeNullProblemSeverity(requiredBits, providedBits, currentNullStatus, i == 0 ? mode : mode.toDetail(), null); - if (i > 0 && dimSeverity == Severity.UNCHECKED - && providedExpression instanceof ArrayAllocationExpression - && providedBits == 0 && requiredBits != 0) - { - Expression[] dimensions = ((ArrayAllocationExpression) providedExpression).dimensions; - Expression previousDim = dimensions[i-1]; - if (previousDim instanceof IntLiteral && previousDim.constant.intValue() == 0) { - dimSeverity = Severity.OK; // element of empty dimension matches anything - nullStatus = -1; - break; - } - } - severity = severity.max(dimSeverity); - if (severity == Severity.MISMATCH) { - if (nullStatus == FlowInfo.NULL) - return new NullAnnotationMatching(true, severity, nullStatus, null); - return NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH; - } - } - if (severity == Severity.OK) - nullStatus = -1; - } - } else if (providedType.id == TypeIds.T_null) { - if (dims > 0 && requiredDimsTagBits[0] == TagBits.AnnotationNonNull) - return NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH; - } - } - } else if (requiredType.hasNullTypeAnnotations() || providedType.hasNullTypeAnnotations() || requiredType.isTypeVariable()) { - long requiredBits = requiredNullTagBits(requiredType, mode); - if (requiredBits == TagBits.AnnotationNullable && nullStatus != -1 && mode.requiredNullableMatchesAll()) { - // at toplevel (having a nullStatus) nullable matches all - } else { - long providedBits = providedNullTagBits(providedType); - Severity s = computeNullProblemSeverity(requiredBits, providedBits, nullStatus, mode, originalRequiredType); - if (s.isAnyMismatch() && requiredType.isWildcard() && requiredBits != 0) { - if (((WildcardBinding) requiredType).determineNullBitsFromDeclaration(null, null) == 0) { - TypeVariableBinding typeVariable = ((WildcardBinding) requiredType).typeVariable(); - if ((typeVariable.tagBits & TagBits.AnnotationNullMASK) != 0) { - // wildcard has its nullBits from the type variable - s = Severity.OK; // is already reported as illegal substitution - } - } - } - severity = severity.max(s); - if (!severity.isAnyMismatch() && (providedBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNonNull) - okStatus = okNonNullStatus(providedExpression); - } - if (severity != Severity.MISMATCH && nullStatus != FlowInfo.NULL) { // null value has no details - TypeBinding providedSuper = providedType.findSuperTypeOriginatingFrom(requiredType); - TypeBinding providedSubstituteSuper = providedSubstitute != null ? providedSubstitute.findSuperTypeOriginatingFrom(requiredType) : null; - if (severity == Severity.UNCHECKED && requiredType.isTypeVariable() && providedType.isTypeVariable() && (providedSuper == requiredType || providedSubstituteSuper == requiredType)) { //$IDENTITY-COMPARISON$ - severity = Severity.OK; - } - if (providedSuper != providedType) //$IDENTITY-COMPARISON$ - superTypeHint = providedSuper; - if (requiredType.isParameterizedType() && providedSuper instanceof ParameterizedTypeBinding) { // TODO(stephan): handle providedType.isRaw() - TypeBinding[] requiredArguments = ((ParameterizedTypeBinding) requiredType).arguments; - TypeBinding[] providedArguments = ((ParameterizedTypeBinding) providedSuper).arguments; - TypeBinding[] providedSubstitutes = (providedSubstituteSuper instanceof ParameterizedTypeBinding) ? ((ParameterizedTypeBinding)providedSubstituteSuper).arguments : null; - if (requiredArguments != null && providedArguments != null && requiredArguments.length == providedArguments.length) { - for (int i = 0; i < requiredArguments.length; i++) { - TypeBinding providedArgSubstitute = providedSubstitutes != null ? providedSubstitutes[i] : null; - NullAnnotationMatching status = analyse(requiredArguments[i], providedArguments[i], providedArgSubstitute, substitution, -1, providedExpression, mode.toDetail()); - severity = severity.max(status.severity); - if (severity == Severity.MISMATCH) - return new NullAnnotationMatching(true, severity, nullStatus, superTypeHint); - else if (severity != Severity.OK) - problemAtDetail = true; - } - } - } - TypeBinding requiredEnclosing = requiredType.enclosingType(); - TypeBinding providedEnclosing = providedType.enclosingType(); - if (requiredEnclosing != null && providedEnclosing != null) { - TypeBinding providedEnclSubstitute = providedSubstitute != null ? providedSubstitute.enclosingType() : null; - NullAnnotationMatching status = analyse(requiredEnclosing, providedEnclosing, providedEnclSubstitute, substitution, -1, providedExpression, mode); - severity = severity.max(status.severity); - } - } - } - if (!severity.isAnyMismatch()) - return okStatus; - return new NullAnnotationMatching(problemAtDetail, severity, nullStatus, superTypeHint); - } finally { - requiredType.exitRecursiveFunction(); - } - } - public void report(Scope scope) { - // nop - } - public int getProblemId(TypeBinding requiredType) { - if (isAnnotatedToUnannotated()) { - return IProblem.AnnotatedTypeArgumentToUnannotated; - } else if (isUnchecked()) { - if (this.problemAtDetail) - return IProblem.NullityUncheckedTypeAnnotationDetail; - else - return IProblem.NullityUncheckedTypeAnnotation; - } else if (requiredType.isTypeVariable() && !requiredType.hasNullTypeAnnotations()) { - return IProblem.NullityMismatchAgainstFreeTypeVariable; - } else { - return IProblem.NullityMismatchingTypeAnnotation; - } - } - - public static NullAnnotationMatching okNonNullStatus(final Expression providedExpression) { - if (providedExpression instanceof MessageSend) { - final MethodBinding method = ((MessageSend) providedExpression).binding; - if (method != null && method.isValidBinding()) { - MethodBinding originalMethod = method.original(); - TypeBinding originalDeclaringClass = originalMethod.declaringClass; - if (originalDeclaringClass instanceof BinaryTypeBinding - && ((BinaryTypeBinding) originalDeclaringClass).externalAnnotationStatus.isPotentiallyUnannotatedLib() - && originalMethod.returnType.isTypeVariable() - && (originalMethod.returnType.tagBits & TagBits.AnnotationNullMASK) == 0) - { - final int severity = ((BinaryTypeBinding) originalDeclaringClass).externalAnnotationStatus == ExternalAnnotationStatus.NO_EEA_FILE - ? ProblemSeverities.Warning : ProblemSeverities.Info; // reduce severity if not configured to for external annotations - return new NullAnnotationMatching(Severity.LEGACY_WARNING, FlowInfo.UNKNOWN, null) { - @Override - public void report(Scope scope) { - scope.problemReporter().nonNullTypeVariableInUnannotatedBinary(scope.environment(), method, providedExpression, severity); - } - }; - } - } - } - return NullAnnotationMatching.NULL_ANNOTATIONS_OK_NONNULL; - } - - /** Are both types identical wrt the unannotated type and any null type annotations? Only unstructured types and captures are considered. */ - protected static boolean areSameTypes(TypeBinding requiredType, TypeBinding providedType, TypeBinding providedSubstitute) { - if (requiredType == providedType) //$IDENTITY-COMPARISON$ // short cut for really-really-same types - return true; - if (requiredType.isParameterizedType() || requiredType.isArrayType()) - return false; // not analysing details here - if (TypeBinding.notEquals(requiredType, providedType)) { - if (requiredType instanceof CaptureBinding) { - // when providing exactly the lower bound of the required type we're definitely fine: - TypeBinding lowerBound = ((CaptureBinding)requiredType).lowerBound; - if (lowerBound != null && areSameTypes(lowerBound, providedType, providedSubstitute)) - return (requiredType.tagBits & TagBits.AnnotationNullMASK) == (providedType.tagBits & TagBits.AnnotationNullMASK); - } else if (requiredType.kind() == Binding.TYPE_PARAMETER && requiredType == providedSubstitute) { //$IDENTITY-COMPARISON$ - return true; - } else if (providedType instanceof CaptureBinding) { - // when requiring exactly the upper bound of the provided type we're fine, too: - TypeBinding upperBound = ((CaptureBinding)providedType).upperBound(); - if (upperBound != null && areSameTypes(requiredType, upperBound, providedSubstitute)) - return (requiredType.tagBits & TagBits.AnnotationNullMASK) == (providedType.tagBits & TagBits.AnnotationNullMASK); - } - return false; - } - return (requiredType.tagBits & TagBits.AnnotationNullMASK) == (providedType.tagBits & TagBits.AnnotationNullMASK); - } - - // interpreting 'type' as a required type, compute the required null bits - // we inspect the main type plus bounds of type variables and wildcards - static long requiredNullTagBits(TypeBinding type, CheckMode mode) { - - long tagBits = type.tagBits & TagBits.AnnotationNullMASK; - if (tagBits != 0) - return validNullTagBits(tagBits); - - if (type.isWildcard()) { - WildcardBinding wildcardBinding = (WildcardBinding) type; - TypeBinding bound = wildcardBinding.bound; - tagBits = bound != null ? bound.tagBits & TagBits.AnnotationNullMASK : 0; - switch (wildcardBinding.boundKind) { - case Wildcard.SUPER: - if (tagBits == TagBits.AnnotationNullable) - return TagBits.AnnotationNullable; // type cannot require @NonNull - break; - case Wildcard.EXTENDS: - if (tagBits == TagBits.AnnotationNonNull) - return tagBits; - break; - } - return TagBits.AnnotationNullMASK; - } - - if (type.isTypeVariable()) { - // assume we must require @NonNull, unless lower @Nullable bound - // (annotation directly on the TV has already been checked above) - if (type.isCapture()) { - TypeBinding lowerBound = ((CaptureBinding) type).lowerBound; - if (lowerBound != null) { - tagBits = lowerBound.tagBits & TagBits.AnnotationNullMASK; - if (tagBits == TagBits.AnnotationNullable) - return TagBits.AnnotationNullable; // type cannot require @NonNull - } - } - switch (mode) { - case BOUND_CHECK: // no pessimistic checks during boundcheck (we *have* the instantiation) - case BOUND_SUPER_CHECK: - case OVERRIDE: // no pessimistic checks during override check (comparing two *declarations*) - case OVERRIDE_RETURN: - break; - default: - return TagBits.AnnotationNonNull; // instantiation could require @NonNull - } - } - - return 0; - } - - // interpreting 'type' as a provided type, compute the provide null bits - // we inspect the main type plus bounds of type variables and wildcards - static long providedNullTagBits(TypeBinding type) { - - long tagBits = type.tagBits & TagBits.AnnotationNullMASK; - if (tagBits != 0) - return validNullTagBits(tagBits); - - if (type.isWildcard()) { // wildcard can be 'provided' during inheritance checks - return TagBits.AnnotationNullMASK; - } - - if (type.isTypeVariable()) { // incl. captures - TypeVariableBinding typeVariable = (TypeVariableBinding)type; - boolean haveNullBits = false; - if (typeVariable.isCapture()) { - TypeBinding lowerBound = ((CaptureBinding) typeVariable).lowerBound; - if (lowerBound != null) { - tagBits = lowerBound.tagBits & TagBits.AnnotationNullMASK; - if (tagBits == TagBits.AnnotationNullable) - return TagBits.AnnotationNullable; // cannot be @NonNull - haveNullBits |= (tagBits != 0); - } - } - if (typeVariable.firstBound != null) { - long boundBits = typeVariable.firstBound.tagBits & TagBits.AnnotationNullMASK; - if (boundBits == TagBits.AnnotationNonNull) - return TagBits.AnnotationNonNull; // cannot be @Nullable - haveNullBits |= (boundBits != 0); - } - if (haveNullBits) - return TagBits.AnnotationNullMASK; // could be either, can only match to a wildcard accepting both - } - - return 0; - } - - /** - * Use only if no suitable flowInfo is available. - */ - public static int nullStatusFromExpressionType(TypeBinding type) { - if (type.isFreeTypeVariable()) - return FlowInfo.FREE_TYPEVARIABLE; - long bits = type.tagBits & TagBits.AnnotationNullMASK; - if (bits == 0) - return FlowInfo.UNKNOWN; - if (bits == TagBits.AnnotationNonNull) - return FlowInfo.NON_NULL; - return FlowInfo.POTENTIALLY_NON_NULL | FlowInfo.POTENTIALLY_NULL; - } - - public static long validNullTagBits(long bits) { - bits &= TagBits.AnnotationNullMASK; - return bits == TagBits.AnnotationNullMASK ? 0 : bits; - } - - /** Provided that both types are {@link TypeBinding#equalsEquals}, return the one that is more likely to show null at runtime. */ - public static TypeBinding moreDangerousType(TypeBinding one, TypeBinding two) { - if (one == null) return null; - long oneNullBits = validNullTagBits(one.tagBits); - long twoNullBits = validNullTagBits(two.tagBits); - if (oneNullBits != twoNullBits) { - if (oneNullBits == TagBits.AnnotationNullable) - return one; // nullable is dangerous - if (twoNullBits == TagBits.AnnotationNullable) - return two; // nullable is dangerous - // below this point we have unknown vs. nonnull, which is which? - if (oneNullBits == 0) - return one; // unknown is more dangerous than nonnull - return two; // unknown is more dangerous than nonnull - } else if (one != two) { //$IDENTITY-COMPARISON$ - if (analyse(one, two, -1).isAnyMismatch()) - return two; // two doesn't snugly fit into one, so it must be more dangerous - } - return one; - } - - /** - * Evaluate problem severity from the given details: - * @param requiredBits null tagBits of the required type - * @param providedBits null tagBits of the provided type - * @param nullStatus -1 means: don't use, other values see constants in FlowInfo - * @param mode check mode (see {@link CheckMode}) - * @param requiredType the required type, used, e.g., to check if it is a type variable (possibly: "free type variable")? - * @return see {@link #severity} for interpretation of values - */ - private static Severity computeNullProblemSeverity(long requiredBits, long providedBits, int nullStatus, CheckMode mode, TypeBinding requiredType) { - if (requiredBits == providedBits) - return Severity.OK; - if (requiredBits == 0) { - switch (mode) { - case EXACT: - if (providedBits == TagBits.AnnotationNonNull && !(requiredType instanceof TypeVariableBinding)) - return Severity.UNCHECKED_TO_UNANNOTATED; - return Severity.OK; - case COMPATIBLE: - case BOUND_CHECK: - case BOUND_SUPER_CHECK: - return Severity.OK; - case OVERRIDE_RETURN: - if (providedBits == TagBits.AnnotationNonNull) - return Severity.OK; // covariant redefinition to nonnull is good - if (!(requiredType instanceof TypeVariableBinding)) - return Severity.OK; // refining an unconstrained non-TVB return to nullable is also legal - return Severity.UNCHECKED; - case OVERRIDE: - return Severity.UNCHECKED; // warn about dropped annotation - } - } else if (requiredBits == TagBits.AnnotationNullMASK) { - if (mode == CheckMode.EXACT && providedBits == TagBits.AnnotationNonNull) { - if (requiredType instanceof WildcardBinding) { - WildcardBinding wildcard = (WildcardBinding) requiredType; - // passing '@NonNull X' into '? super Y' risks pollution with null - if (wildcard.boundKind == Wildcard.SUPER && providedBits == TagBits.AnnotationNonNull) { - TypeBinding bound = wildcard.bound; - if (bound != null && (bound.tagBits & TagBits.AnnotationNullMASK) != 0) - return Severity.OK; // when the wildcard is annotated via its bound, there is not annotated->unannotated conversion - return Severity.UNCHECKED_TO_UNANNOTATED; - } - } - } - return Severity.OK; // OK since LHS accepts either - } else if (requiredBits == TagBits.AnnotationNonNull) { - switch (mode) { - case COMPATIBLE: - if (nullStatus == FlowInfo.NULL) - return Severity.MISMATCH; // NOK by flow analysis - //$FALL-THROUGH$ - case BOUND_SUPER_CHECK: - if (nullStatus == FlowInfo.NON_NULL) - return Severity.OK; // OK by flow analysis - //$FALL-THROUGH$ - case BOUND_CHECK: - case EXACT: - case OVERRIDE_RETURN: - case OVERRIDE: - if (providedBits == 0) - return Severity.UNCHECKED; - return Severity.MISMATCH; - } - - } else if (requiredBits == TagBits.AnnotationNullable) { - switch (mode) { - case COMPATIBLE: - case OVERRIDE_RETURN: - case BOUND_SUPER_CHECK: - return Severity.OK; // in these modes everything is compatible to nullable - case BOUND_CHECK: - case EXACT: - if (providedBits == 0) - return Severity.UNCHECKED; - return Severity.MISMATCH; - case OVERRIDE: - return Severity.MISMATCH; - } - } - return Severity.OK; // shouldn't get here, requiredBits should be one of the listed cases - } - - static class SearchContradictions extends TypeBindingVisitor { - ReferenceBinding typeWithContradiction; - @Override - public boolean visit(ReferenceBinding referenceBinding) { - if ((referenceBinding.tagBits & TagBits.AnnotationNullMASK) == TagBits.AnnotationNullMASK) { - this.typeWithContradiction = referenceBinding; - return false; - } - return true; - } - @Override - public boolean visit(TypeVariableBinding typeVariable) { - if (!visit((ReferenceBinding)typeVariable)) - return false; - long allNullBits = typeVariable.tagBits & TagBits.AnnotationNullMASK; - if (typeVariable.firstBound != null) - allNullBits = typeVariable.firstBound.tagBits & TagBits.AnnotationNullMASK; - for (TypeBinding otherBound : typeVariable.otherUpperBounds()) - allNullBits |= otherBound.tagBits & TagBits.AnnotationNullMASK; - if (allNullBits == TagBits.AnnotationNullMASK) { - this.typeWithContradiction = typeVariable; - return false; - } - return true; - } - @Override - public boolean visit(RawTypeBinding rawType) { - return visit((ReferenceBinding)rawType); - } - @Override - public boolean visit(WildcardBinding wildcardBinding) { - long allNullBits = wildcardBinding.tagBits & TagBits.AnnotationNullMASK; - switch (wildcardBinding.boundKind) { - case Wildcard.EXTENDS: - allNullBits |= wildcardBinding.bound.tagBits & TagBits.AnnotationNonNull; - break; - case Wildcard.SUPER: - allNullBits |= wildcardBinding.bound.tagBits & TagBits.AnnotationNullable; - break; - } - if (allNullBits == TagBits.AnnotationNullMASK) { - this.typeWithContradiction = wildcardBinding; - return false; - } - return true; - } - @Override - public boolean visit(ParameterizedTypeBinding parameterizedTypeBinding) { - if (!visit((ReferenceBinding) parameterizedTypeBinding)) - return false; - return super.visit(parameterizedTypeBinding); - } - } - - /** - * After a method has substituted type parameters, check if this resulted in any contradictory null annotations. - * Problems are either reported directly (if scope != null) or by returning a ProblemMethodBinding. - */ - public static MethodBinding checkForContradictions(MethodBinding method, Object location, Scope scope) { - - int start = 0, end = 0; - if (location instanceof InvocationSite) { - start = ((InvocationSite) location).sourceStart(); - end = ((InvocationSite) location).sourceEnd(); - } else if (location instanceof ASTNode) { - start = ((ASTNode) location).sourceStart; - end = ((ASTNode) location).sourceEnd; - } - SearchContradictions searchContradiction = new SearchContradictions(); - TypeBindingVisitor.visit(searchContradiction, method.returnType); - if (searchContradiction.typeWithContradiction != null) { - if (scope == null) - return new ProblemMethodBinding(method, method.selector, method.parameters, ProblemReasons.ContradictoryNullAnnotations); - scope.problemReporter().contradictoryNullAnnotationsInferred(method, start, end, location instanceof FunctionalExpression); - // note: if needed, we might want to update the method by removing the contradictory annotations?? - return method; - } - - Expression[] arguments = null; - if (location instanceof Invocation) - arguments = ((Invocation)location).arguments(); - for (int i = 0; i < method.parameters.length; i++) { - TypeBindingVisitor.visit(searchContradiction, method.parameters[i]); - if (searchContradiction.typeWithContradiction != null) { - if (scope == null) - return new ProblemMethodBinding(method, method.selector, method.parameters, ProblemReasons.ContradictoryNullAnnotations); - if (arguments != null && i < arguments.length) - scope.problemReporter().contradictoryNullAnnotationsInferred(method, arguments[i]); - else - scope.problemReporter().contradictoryNullAnnotationsInferred(method, start, end, location instanceof FunctionalExpression); - return method; - } - } - return method; - } - - public static boolean hasContradictions(TypeBinding type) { - SearchContradictions searchContradiction = new SearchContradictions(); - TypeBindingVisitor.visit(searchContradiction, type); - return searchContradiction.typeWithContradiction != null; - } - - public static TypeBinding strongerType(TypeBinding type1, TypeBinding type2, LookupEnvironment environment) { - if ((type1.tagBits & TagBits.AnnotationNonNull) != 0) - return mergeTypeAnnotations(type1, type2, true, environment); - return mergeTypeAnnotations(type2, type1, true, environment); // don't bother to distinguish unannotated vs. @Nullable, since both can accept null - } - - public static TypeBinding[] weakerTypes(TypeBinding[] parameters1, TypeBinding[] parameters2, LookupEnvironment environment) { - TypeBinding[] newParameters = new TypeBinding[parameters1.length]; - for (int i = 0; i < newParameters.length; i++) { - long tagBits1 = parameters1[i].tagBits; - long tagBits2 = parameters2[i].tagBits; - if ((tagBits1 & TagBits.AnnotationNullable) != 0) - newParameters[i] = mergeTypeAnnotations(parameters1[i], parameters2[i], true, environment); // @Nullable must be preserved - else if ((tagBits2 & TagBits.AnnotationNullable) != 0) - newParameters[i] = mergeTypeAnnotations(parameters2[i], parameters1[i], true, environment); // @Nullable must be preserved - else if ((tagBits1 & TagBits.AnnotationNonNull) == 0) - newParameters[i] = mergeTypeAnnotations(parameters1[i], parameters2[i], true, environment); // unannotated must be preserved - else - newParameters[i] = mergeTypeAnnotations(parameters2[i], parameters1[i], true, environment); // either unannotated, or both are @NonNull - } - return newParameters; - } - private static TypeBinding mergeTypeAnnotations(TypeBinding type, TypeBinding otherType, boolean top, LookupEnvironment environment) { - TypeBinding mainType = type; - if (!top) { - // for all but the top level type superimpose other's type annotation onto type - AnnotationBinding[] otherAnnotations = otherType.getTypeAnnotations(); - if (otherAnnotations != Binding.NO_ANNOTATIONS) - mainType = environment.createAnnotatedType(type, otherAnnotations); - } - if (mainType.isParameterizedType() && otherType.isParameterizedType()) { - ParameterizedTypeBinding ptb = (ParameterizedTypeBinding) type, otherPTB = (ParameterizedTypeBinding) otherType; - TypeBinding[] typeArguments = ptb.arguments; - TypeBinding[] otherTypeArguments = otherPTB.arguments; - TypeBinding[] newTypeArguments = new TypeBinding[typeArguments.length]; - for (int i = 0; i < typeArguments.length; i++) { - newTypeArguments[i] = mergeTypeAnnotations(typeArguments[i], otherTypeArguments[i], false, environment); - } - return environment.createParameterizedType(ptb.genericType(), newTypeArguments, ptb.enclosingType()); - } - return mainType; - } - - @Override - public String toString() { - if (this == NULL_ANNOTATIONS_OK) return "OK"; //$NON-NLS-1$ - if (this == NULL_ANNOTATIONS_MISMATCH) return "MISMATCH"; //$NON-NLS-1$ - if (this == NULL_ANNOTATIONS_OK_NONNULL) return "OK NonNull"; //$NON-NLS-1$ - if (this == NULL_ANNOTATIONS_UNCHECKED) return "UNCHECKED"; //$NON-NLS-1$ - StringBuilder buf = new StringBuilder(); - buf.append("Analysis result: severity="+this.severity); //$NON-NLS-1$ - buf.append(" nullStatus="+this.nullStatus); //$NON-NLS-1$ - return buf.toString(); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java deleted file mode 100644 index 7ea8ca3..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NullLiteral.java +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 383368 - [compiler][null] syntactic null analysis for field references - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.*; -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.*; - -public class NullLiteral extends MagicLiteral { - - static final char[] source = {'n' , 'u' , 'l' , 'l'}; - - public NullLiteral(int s , int e) { - - super(s,e); - } - - @Override - public void computeConstant() { - - this.constant = Constant.NotAConstant; - } - - /** - * Code generation for the null literal - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (valueRequired) { - codeStream.aconst_null(); - codeStream.generateImplicitConversion(this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - @Override - public TypeBinding literalType(BlockScope scope) { - return TypeBinding.NULL; - } - - @Override - public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - return FlowInfo.NULL; - } - - @Override - public Object reusableJSRTarget() { - return TypeBinding.NULL; - } - - @Override - public char[] source() { - return source; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java deleted file mode 100644 index 332bbcf..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/NumberLiteral.java +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2011 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -public abstract class NumberLiteral extends Literal { - - char[] source; - - public NumberLiteral(char[] token, int s, int e) { - this(s,e) ; - this.source = token ; - } - - public NumberLiteral(int s, int e) { - super (s,e) ; - } - - @Override - public boolean isValidJavaStatement(){ - return false ; - } - - @Override - public char[] source(){ - return this.source; - } - protected static char[] removePrefixZerosAndUnderscores(char[] token, boolean isLong) { - int max = token.length; - int start = 0; - int end = max - 1; - if (isLong) { - end--; // remove the 'L' or 'l' - } - if (max > 1 && token[0] == '0') { - if (max > 2 && (token[1] == 'x' || token[1] == 'X')) { - start = 2; - } else if (max > 2 && (token[1] == 'b' || token[1] == 'B')) { - start = 2; - } else { - start = 1; - } - } - boolean modified = false; - boolean ignore = true; - loop: for (int i = start; i < max; i++) { - char currentChar = token[i]; - switch(currentChar) { - case '0' : - // this is a prefix '0' - if (ignore && !modified && (i < end)) { - modified = true; - } - break; - case '_' : - modified = true; - break loop; - default : - ignore = false; - } - } - if (!modified) { - return token; - } - ignore = true; - StringBuilder buffer = new StringBuilder(); - buffer.append(token, 0, start); - loop: for (int i = start; i < max; i++) { - char currentChar = token[i]; - switch(currentChar) { - case '0' : - if (ignore && (i < end)) { - // this is a prefix '0' - continue loop; - } - break; - case '_' : - continue loop; - default: - ignore = false; - } - buffer.append(currentChar); - } - return buffer.toString().toCharArray(); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java deleted file mode 100644 index 26c9577..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OR_OR_Expression.java +++ /dev/null @@ -1,322 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 319201 - [null] no warning when unboxing SingleNameReference causes NPE - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 403086 - [compiler][null] include the effect of 'assert' in syntactic null analysis for fields - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 422796 - [compiler][null] boxed boolean reported as potentially null after null test in lazy disjunction - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -//dedicated treatment for the || -public class OR_OR_Expression extends BinaryExpression { - - int rightInitStateIndex = -1; - int mergedInitStateIndex = -1; - - public OR_OR_Expression(Expression left, Expression right, int operator) { - super(left, right, operator); - } - - @Override - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - Constant cst = this.left.optimizedBooleanConstant(); - boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isLeftOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - - if (isLeftOptimizedFalse) { - // FALSE || anything - // need to be careful of scenario: - // (x || y) || !z, if passing the left info to the right, it would be swapped by the ! - FlowInfo mergedInfo = this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - flowContext.expireNullCheckedFieldInfo(); - mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo); - flowContext.expireNullCheckedFieldInfo(); - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } - - FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo); - if ((flowContext.tagBits & FlowContext.INSIDE_NEGATION) == 0) - flowContext.expireNullCheckedFieldInfo(); - - // rightInfo captures the flow (!left then right): - FlowInfo rightInfo = leftInfo.initsWhenFalse().unconditionalCopy(); - this.rightInitStateIndex = - currentScope.methodScope().recordInitializationStates(rightInfo); - - int previousMode = rightInfo.reachMode(); - if (isLeftOptimizedTrue){ - if ((rightInfo.reachMode() & FlowInfo.UNREACHABLE) == 0) { - currentScope.problemReporter().fakeReachable(this.right); - rightInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - } - this.left.updateFlowOnBooleanResult(rightInfo, false); - rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo); - if ((flowContext.tagBits & FlowContext.INSIDE_NEGATION) == 0) - flowContext.expireNullCheckedFieldInfo(); - this.left.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - this.right.checkNPEbyUnboxing(currentScope, flowContext, leftInfo.initsWhenFalse()); - // tweak reach mode to ensure that inits are considered during merge: - UnconditionalFlowInfo rightWhenTrueForMerge = rightInfo.safeInitsWhenTrue().setReachMode(previousMode).unconditionalInits(); - FlowInfo mergedInfo = FlowInfo.conditional( - // then = left or (!left then right): - leftInfo.initsWhenTrue().mergedWith(rightWhenTrueForMerge), - // else = (!left then !right): - rightInfo.initsWhenFalse()); - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } - - /** - * Code generation for a binary operation - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (this.constant != Constant.NotAConstant) { - // inlined value - if (valueRequired) - codeStream.generateConstant(this.constant, this.implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - Constant cst = this.right.constant; - if (cst != Constant.NotAConstant) { - // || true --> true - if (cst.booleanValue() == true) { - this.left.generateCode(currentScope, codeStream, false); - if (valueRequired) codeStream.iconst_1(); - } else { - // || false --> - this.left.generateCode(currentScope, codeStream, valueRequired); - } - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - - BranchLabel trueLabel = new BranchLabel(codeStream), endLabel; - cst = this.left.optimizedBooleanConstant(); - boolean leftIsConst = cst != Constant.NotAConstant; - boolean leftIsTrue = leftIsConst && cst.booleanValue() == true; - - cst = this.right.optimizedBooleanConstant(); - boolean rightIsConst = cst != Constant.NotAConstant; - boolean rightIsTrue = rightIsConst && cst.booleanValue() == true; - - generateOperands : { - if (leftIsConst) { - this.left.generateCode(currentScope, codeStream, false); - if (leftIsTrue) { - break generateOperands; // no need to generate right operand - } - } else { - this.left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, true); - // need value, e.g. if (a == 1 || ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a==1 - } - if (this.rightInitStateIndex != -1) { - codeStream.addDefinitelyAssignedVariables(currentScope, this.rightInitStateIndex); - } - if (rightIsConst) { - this.right.generateCode(currentScope, codeStream, false); - } else { - this.right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, valueRequired); - } - } - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - /* - * improving code gen for such a case: boolean b = i < 0 || true since - * the label has never been used, we have the inlined value on the - * stack. - */ - if (valueRequired) { - if (leftIsConst && leftIsTrue) { - codeStream.iconst_1(); - codeStream.recordPositionsFrom(codeStream.position, this.left.sourceEnd); - } else { - if (rightIsConst && rightIsTrue) { - codeStream.iconst_1(); - codeStream.recordPositionsFrom(codeStream.position, this.left.sourceEnd); - } else { - codeStream.iconst_0(); - } - if (trueLabel.forwardReferenceCount() > 0) { - if ((this.bits & IsReturnedValue) != 0) { - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateReturnBytecode(this); - trueLabel.place(); - codeStream.iconst_1(); - } else { - codeStream.goto_(endLabel = new BranchLabel(codeStream)); - codeStream.decrStackSize(1); - trueLabel.place(); - codeStream.iconst_1(); - endLabel.place(); - } - } else { - trueLabel.place(); - } - } - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } else { - trueLabel.place(); - } - } - - /** - * Boolean operator code generation Optimized operations are: || - */ - @Override - public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - if (this.constant != Constant.NotAConstant) { - super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - return; - } - - // || false --> - Constant cst = this.right.constant; - if (cst != Constant.NotAConstant && cst.booleanValue() == false) { - int pc = codeStream.position; - this.left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired); - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - - cst = this.left.optimizedBooleanConstant(); - boolean leftIsConst = cst != Constant.NotAConstant; - boolean leftIsTrue = leftIsConst && cst.booleanValue() == true; - - cst = this.right.optimizedBooleanConstant(); - boolean rightIsConst = cst != Constant.NotAConstant; - boolean rightIsTrue = rightIsConst && cst.booleanValue() == true; - - // default case - generateOperands : { - if (falseLabel == null) { - if (trueLabel != null) { - // implicit falling through the FALSE case - this.left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, !leftIsConst); - // need value, e.g. if (a == 1 || ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a==1 - if (leftIsTrue) { - if (valueRequired) codeStream.goto_(trueLabel); - codeStream.recordPositionsFrom(codeStream.position, this.left.sourceEnd); - break generateOperands; // no need to generate right operand - } - if (this.rightInitStateIndex != -1) { - codeStream.addDefinitelyAssignedVariables(currentScope, this.rightInitStateIndex); - } - this.right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null, valueRequired && !rightIsConst); - if (valueRequired && rightIsTrue) { - codeStream.goto_(trueLabel); - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd); - } - } - } else { - // implicit falling through the TRUE case - if (trueLabel == null) { - BranchLabel internalTrueLabel = new BranchLabel(codeStream); - this.left.generateOptimizedBoolean(currentScope, codeStream, internalTrueLabel, null, !leftIsConst); - // need value, e.g. if (a == 1 || ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a==1 - if (leftIsTrue) { - internalTrueLabel.place(); - break generateOperands; // no need to generate right operand - } - if (this.rightInitStateIndex != -1) { - codeStream - .addDefinitelyAssignedVariables(currentScope, this.rightInitStateIndex); - } - this.right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired && !rightIsConst); - int pc = codeStream.position; - if (valueRequired && rightIsConst && !rightIsTrue) { - codeStream.goto_(falseLabel); - codeStream.recordPositionsFrom(pc, this.sourceEnd); - } - internalTrueLabel.place(); - } else { - // no implicit fall through TRUE/FALSE --> should never occur - } - } - } - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - } - - @Override - public LocalVariableBinding[] bindingsWhenFalse() { - - LocalVariableBinding [] leftVars = this.left.bindingsWhenFalse(); - LocalVariableBinding [] rightVars = this.right.bindingsWhenFalse(); - - if (leftVars == NO_VARIABLES) - return rightVars; - - if (rightVars == NO_VARIABLES) - return leftVars; - - return LocalVariableBinding.merge(leftVars, rightVars); - } - - @Override - public boolean isCompactableOperation() { - return false; - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.BinaryExpression#resolveType(org.eclipse.jdt.internal.compiler.lookup.BlockScope) - */ - @Override - public TypeBinding resolveType(BlockScope scope) { - TypeBinding result = super.resolveType(scope); - // check whether comparing identical expressions - Binding leftDirect = Expression.getDirectBinding(this.left); - if (leftDirect != null && leftDirect == Expression.getDirectBinding(this.right)) { - if (!(this.right instanceof Assignment)) - scope.problemReporter().comparingIdenticalExpressions(this); - } - return result; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.left.traverse(visitor, scope); - this.right.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OpensStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OpensStatement.java deleted file mode 100644 index 6560167..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OpensStatement.java +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; - -public class OpensStatement extends PackageVisibilityStatement { - - public OpensStatement(ImportReference pkgRef) { - this(pkgRef, null); - } - public OpensStatement(ImportReference pkgRef, ModuleReference[] targets) { - super(pkgRef, targets); - } - @Override - public int computeSeverity(int problemId) { - switch (problemId) { - case IProblem.PackageDoesNotExistOrIsEmpty: - return ProblemSeverities.Warning; - default: - return ProblemSeverities.Error; - } - } - @Override - public StringBuilder print(int indent, StringBuilder output) { - printIndent(indent, output); - output.append("opens "); //$NON-NLS-1$ - super.print(0, output); - output.append(";"); //$NON-NLS-1$ - return output; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java deleted file mode 100644 index 50aea34..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OperatorExpression.java +++ /dev/null @@ -1,1578 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Perry James - nullStatus method improvement (165346) - * Stephan Herrmann - Contribution for - * bug 383368 - [compiler][null] syntactic null analysis for field references - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.util.Util; - -public abstract class OperatorExpression extends Expression implements OperatorIds { - - public static int[][] OperatorSignatures = new int[UNSIGNED_RIGHT_SHIFT+1][]; - - static {classInitialize();} - - /** - * OperatorExpression constructor comment. - */ - public OperatorExpression() { - super(); - } - public static final void classInitialize() { - OperatorSignatures[AND] = get_AND(); - OperatorSignatures[AND_AND] = get_AND_AND(); - OperatorSignatures[DIVIDE] = get_DIVIDE(); - OperatorSignatures[EQUAL_EQUAL] = get_EQUAL_EQUAL(); - OperatorSignatures[GREATER] = get_GREATER(); - OperatorSignatures[GREATER_EQUAL] = get_GREATER_EQUAL(); - OperatorSignatures[LEFT_SHIFT] = get_LEFT_SHIFT(); - OperatorSignatures[LESS] = get_LESS(); - OperatorSignatures[LESS_EQUAL] = get_LESS_EQUAL(); - OperatorSignatures[MINUS] = get_MINUS(); - OperatorSignatures[MULTIPLY] = get_MULTIPLY(); - OperatorSignatures[OR] = get_OR(); - OperatorSignatures[OR_OR] = get_OR_OR(); - OperatorSignatures[PLUS] = get_PLUS(); - OperatorSignatures[REMAINDER] = get_REMAINDER(); - OperatorSignatures[RIGHT_SHIFT] = get_RIGHT_SHIFT(); - OperatorSignatures[UNSIGNED_RIGHT_SHIFT] = get_UNSIGNED_RIGHT_SHIFT(); - OperatorSignatures[XOR] = get_XOR(); - } - - public static final String generateTableTestCase(){ - //return a String which is a java method allowing to test - //the non zero entries of all tables - - /* - org.eclipse.jdt.internal.compiler.ast. - OperatorExpression.generateTableTestCase(); - */ - - int[] operators = new int[]{AND,AND_AND,DIVIDE,GREATER,GREATER_EQUAL, - LEFT_SHIFT,LESS,LESS_EQUAL,MINUS,MULTIPLY,OR,OR_OR,PLUS,REMAINDER, - RIGHT_SHIFT,UNSIGNED_RIGHT_SHIFT,XOR}; - - class Decode { - public final String constant(int code){ - switch(code){ - case T_boolean : return "true"; //$NON-NLS-1$ - case T_byte : return "((byte) 3)"; //$NON-NLS-1$ - case T_char : return "'A'"; //$NON-NLS-1$ - case T_double : return "300.0d"; //$NON-NLS-1$ - case T_float : return "100.0f"; //$NON-NLS-1$ - case T_int : return "1"; //$NON-NLS-1$ - case T_long : return "7L"; //$NON-NLS-1$ - case T_JavaLangString : return "\"hello-world\""; //$NON-NLS-1$ - case T_null : return "null"; //$NON-NLS-1$ - case T_short : return "((short) 5)"; //$NON-NLS-1$ - case T_JavaLangObject : return "null";} //$NON-NLS-1$ - return Util.EMPTY_STRING;} - - public final String type(int code){ - switch(code){ - case T_boolean : return "z"; //$NON-NLS-1$ - case T_byte : return "b"; //$NON-NLS-1$ - case T_char : return "c"; //$NON-NLS-1$ - case T_double : return "d"; //$NON-NLS-1$ - case T_float : return "f"; //$NON-NLS-1$ - case T_int : return "i"; //$NON-NLS-1$ - case T_long : return "l"; //$NON-NLS-1$ - case T_JavaLangString : return "str"; //$NON-NLS-1$ - case T_null : return "null"; //$NON-NLS-1$ - case T_short : return "s"; //$NON-NLS-1$ - case T_JavaLangObject : return "obj";} //$NON-NLS-1$ - return "xxx";} //$NON-NLS-1$ - - public final String operator(int operator){ - switch (operator) { - case EQUAL_EQUAL : return "=="; //$NON-NLS-1$ - case LESS_EQUAL : return "<="; //$NON-NLS-1$ - case GREATER_EQUAL :return ">="; //$NON-NLS-1$ - case LEFT_SHIFT : return "<<"; //$NON-NLS-1$ - case RIGHT_SHIFT : return ">>"; //$NON-NLS-1$ - case UNSIGNED_RIGHT_SHIFT : return ">>>"; //$NON-NLS-1$ - case OR_OR :return "||"; //$NON-NLS-1$ - case AND_AND : return "&&"; //$NON-NLS-1$ - case PLUS : return "+"; //$NON-NLS-1$ - case MINUS : return "-"; //$NON-NLS-1$ - case NOT : return "!"; //$NON-NLS-1$ - case REMAINDER : return "%"; //$NON-NLS-1$ - case XOR : return "^"; //$NON-NLS-1$ - case AND : return "&"; //$NON-NLS-1$ - case MULTIPLY : return "*"; //$NON-NLS-1$ - case OR : return "|"; //$NON-NLS-1$ - case TWIDDLE : return "~"; //$NON-NLS-1$ - case DIVIDE : return "/"; //$NON-NLS-1$ - case GREATER : return ">"; //$NON-NLS-1$ - case LESS : return "<"; } //$NON-NLS-1$ - return "????";} //$NON-NLS-1$ - } - - - Decode decode = new Decode(); - String s; - - s = "\tpublic static void binaryOperationTablesTestCase(){\n" + //$NON-NLS-1$ - - "\t\t//TC test : all binary operation (described in tables)\n"+ //$NON-NLS-1$ - "\t\t//method automatically generated by\n"+ //$NON-NLS-1$ - "\t\t//org.eclipse.jdt.internal.compiler.ast.OperatorExpression.generateTableTestCase();\n"+ //$NON-NLS-1$ - - "\t\tString str0;\t String str\t= "+decode.constant(T_JavaLangString)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\t\tint i0;\t int i\t= "+decode.constant(T_int)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\t\tboolean z0;\t boolean z\t= "+decode.constant(T_boolean)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\t\tchar c0; \t char c\t= "+decode.constant(T_char)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\t\tfloat f0; \t float f\t= "+decode.constant(T_float)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\t\tdouble d0;\t double d\t= "+decode.constant(T_double)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\t\tbyte b0; \t byte b\t= "+decode.constant(T_byte)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\t\tshort s0; \t short s\t= "+decode.constant(T_short)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\t\tlong l0; \t long l\t= "+decode.constant(T_long)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\t\tObject obj0; \t Object obj\t= "+decode.constant(T_JavaLangObject)+";\n"+ //$NON-NLS-1$ //$NON-NLS-2$ - "\n"; //$NON-NLS-1$ - - int error = 0; - for (int i=0; i < operators.length; i++) - { int operator = operators[i]; - for (int left=0; left<16;left++) - for (int right=0; right<16;right++) - { int result = (OperatorSignatures[operator][(left<<4)+right]) & 0x0000F; - if (result != T_undefined) - - //1/ First regular computation then 2/ comparaison - //with a compile time constant (generated by the compiler) - // z0 = s >= s; - // if ( z0 != (((short) 5) >= ((short) 5))) - // System.out.println(155); - - { s += "\t\t"+decode.type(result)+"0"+" = "+decode.type(left); //$NON-NLS-1$ //$NON-NLS-3$ //$NON-NLS-2$ - s += " "+decode.operator(operator)+" "+decode.type(right)+";\n"; //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-3$ - String begin = result == T_JavaLangString ? "\t\tif (! " : "\t\tif ( "; //$NON-NLS-2$ //$NON-NLS-1$ - String test = result == T_JavaLangString ? ".equals(" : " != ("; //$NON-NLS-2$ //$NON-NLS-1$ - s += begin +decode.type(result)+"0"+test //$NON-NLS-1$ - +decode.constant(left)+" " //$NON-NLS-1$ - +decode.operator(operator)+" " //$NON-NLS-1$ - +decode.constant(right)+"))\n"; //$NON-NLS-1$ - s += "\t\t\tSystem.out.println("+ (++error) +");\n"; //$NON-NLS-1$ //$NON-NLS-2$ - - } - } - } - - return s += "\n\t\tSystem.out.println(\"binary tables test : done\");}"; //$NON-NLS-1$ - } - - public static final int[] get_AND(){ - - //the code is an int, only 20 bits are used, see below. - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - int[] table = new int[16*16]; - - // table[(T_undefined<<4)+T_undefined] = T_undefined; - // table[(T_undefined<<4)+T_byte] = T_undefined; - // table[(T_undefined<<4)+T_long] = T_undefined; - // table[(T_undefined<<4)+T_short] = T_undefined; - // table[(T_undefined<<4)+T_void] = T_undefined; - // table[(T_undefined<<4)+T_String] = T_undefined; - // table[(T_undefined<<4)+T_Object] = T_undefined; - // table[(T_undefined<<4)+T_double] = T_undefined; - // table[(T_undefined<<4)+T_float] = T_undefined; - // table[(T_undefined<<4)+T_boolean] = T_undefined; - // table[(T_undefined<<4)+T_char] = T_undefined; - // table[(T_undefined<<4)+T_int] = T_undefined; - // table[(T_undefined<<4)+T_null] = T_undefined; - - // table[(T_byte<<4)+T_undefined] = T_undefined; - table[(T_byte<<4)+T_byte] = (Byte2Int<<12) +(Byte2Int<<4) +T_int; - table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_long; - table[(T_byte<<4)+T_short] = (Byte2Int<<12) +(Short2Int<<4)+T_int; - // table[(T_byte<<4)+T_void] = T_undefined; - // table[(T_byte<<4)+T_String] = T_undefined; - // table[(T_byte<<4)+T_Object] = T_undefined; - // table[(T_byte<<4)+T_double] = T_undefined; - // table[(T_byte<<4)+T_float] = T_undefined; - // table[(T_byte<<4)+T_boolean] = T_undefined; - table[(T_byte<<4)+T_char] = (Byte2Int<<12) +(Char2Int<<4) +T_int; - table[(T_byte<<4)+T_int] = (Byte2Int<<12) +(Int2Int<<4) +T_int; - // table[(T_byte<<4)+T_null] = T_undefined; - - // table[(T_long<<4)+T_undefined] = T_undefined; - table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_long; - table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_long; - table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_long; - // table[(T_long<<4)+T_void] = T_undefined; - // table[(T_long<<4)+T_String] = T_undefined; - // table[(T_long<<4)+T_Object] = T_undefined; - // table[(T_long<<4)+T_double] = T_undefined; - // table[(T_long<<4)+T_float] = T_undefined; - // table[(T_long<<4)+T_boolean] = T_undefined; - table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_long; - table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_long; - // table[(T_long<<4)+T_null] = T_undefined; - - // table[(T_short<<4)+T_undefined] = T_undefined; - table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_long; - table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_short<<4)+T_void] = T_undefined; - // table[(T_short<<4)+T_String] = T_undefined; - // table[(T_short<<4)+T_Object] = T_undefined; - // table[(T_short<<4)+T_double] = T_undefined; - // table[(T_short<<4)+T_float] = T_undefined; - // table[(T_short<<4)+T_boolean] = T_undefined; - table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_int; - table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_short<<4)+T_null] = T_undefined; - - // table[(T_void<<4)+T_undefined] = T_undefined; - // table[(T_void<<4)+T_byte] = T_undefined; - // table[(T_void<<4)+T_long] = T_undefined; - // table[(T_void<<4)+T_short] = T_undefined; - // table[(T_void<<4)+T_void] = T_undefined; - // table[(T_void<<4)+T_String] = T_undefined; - // table[(T_void<<4)+T_Object] = T_undefined; - // table[(T_void<<4)+T_double] = T_undefined; - // table[(T_void<<4)+T_float] = T_undefined; - // table[(T_void<<4)+T_boolean] = T_undefined; - // table[(T_void<<4)+T_char] = T_undefined; - // table[(T_void<<4)+T_int] = T_undefined; - // table[(T_void<<4)+T_null] = T_undefined; - - // table[(T_String<<4)+T_undefined] = T_undefined; - // table[(T_String<<4)+T_byte] = T_undefined; - // table[(T_String<<4)+T_long] = T_undefined; - // table[(T_String<<4)+T_short] = T_undefined; - // table[(T_String<<4)+T_void] = T_undefined; - // table[(T_String<<4)+T_String] = T_undefined; - // table[(T_String<<4)+T_Object] = T_undefined; - // table[(T_String<<4)+T_double] = T_undefined; - // table[(T_String<<4)+T_float] = T_undefined; - // table[(T_String<<4)+T_boolean] = T_undefined; - // table[(T_String<<4)+T_char] = T_undefined; - // table[(T_String<<4)+T_int] = T_undefined; - // table[(T_String<<4)+T_null] = T_undefined; - - // table[(T_Object<<4)+T_undefined] = T_undefined; - // table[(T_Object<<4)+T_byte] = T_undefined; - // table[(T_Object<<4)+T_long] = T_undefined; - // table[(T_Object<<4)+T_short] = T_undefined; - // table[(T_Object<<4)+T_void] = T_undefined; - // table[(T_Object<<4)+T_String] = T_undefined; - // table[(T_Object<<4)+T_Object] = T_undefined; - // table[(T_Object<<4)+T_double] = T_undefined; - // table[(T_Object<<4)+T_float] = T_undefined; - // table[(T_Object<<4)+T_boolean] = T_undefined; - // table[(T_Object<<4)+T_char] = T_undefined; - // table[(T_Object<<4)+T_int] = T_undefined; - // table[(T_Object<<4)+T_null] = T_undefined; - - // table[(T_double<<4)+T_undefined] = T_undefined; - // table[(T_double<<4)+T_byte] = T_undefined; - // table[(T_double<<4)+T_long] = T_undefined; - // table[(T_double<<4)+T_short] = T_undefined; - // table[(T_double<<4)+T_void] = T_undefined; - // table[(T_double<<4)+T_String] = T_undefined; - // table[(T_double<<4)+T_Object] = T_undefined; - // table[(T_double<<4)+T_double] = T_undefined; - // table[(T_double<<4)+T_float] = T_undefined; - // table[(T_double<<4)+T_boolean] = T_undefined; - // table[(T_double<<4)+T_char] = T_undefined; - // table[(T_double<<4)+T_int] = T_undefined; - // table[(T_double<<4)+T_null] = T_undefined; - - // table[(T_float<<4)+T_undefined] = T_undefined; - // table[(T_float<<4)+T_byte] = T_undefined; - // table[(T_float<<4)+T_long] = T_undefined; - // table[(T_float<<4)+T_short] = T_undefined; - // table[(T_float<<4)+T_void] = T_undefined; - // table[(T_float<<4)+T_String] = T_undefined; - // table[(T_float<<4)+T_Object] = T_undefined; - // table[(T_float<<4)+T_double] = T_undefined; - // table[(T_float<<4)+T_float] = T_undefined; - // table[(T_float<<4)+T_boolean] = T_undefined; - // table[(T_float<<4)+T_char] = T_undefined; - // table[(T_float<<4)+T_int] = T_undefined; - // table[(T_float<<4)+T_null] = T_undefined; - - // table[(T_boolean<<4)+T_undefined] = T_undefined; - // table[(T_boolean<<4)+T_byte] = T_undefined; - // table[(T_boolean<<4)+T_long] = T_undefined; - // table[(T_boolean<<4)+T_short] = T_undefined; - // table[(T_boolean<<4)+T_void] = T_undefined; - // table[(T_boolean<<4)+T_String] = T_undefined; - // table[(T_boolean<<4)+T_Object] = T_undefined; - // table[(T_boolean<<4)+T_double] = T_undefined; - // table[(T_boolean<<4)+T_float] = T_undefined; - table[(T_boolean<<4)+T_boolean] = (Boolean2Boolean << 12)+(Boolean2Boolean << 4)+T_boolean; - // table[(T_boolean<<4)+T_char] = T_undefined; - // table[(T_boolean<<4)+T_int] = T_undefined; - // table[(T_boolean<<4)+T_null] = T_undefined; - - // table[(T_char<<4)+T_undefined] = T_undefined; - table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_long; - table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_char<<4)+T_void] = T_undefined; - // table[(T_char<<4)+T_String] = T_undefined; - // table[(T_char<<4)+T_Object] = T_undefined; - // table[(T_char<<4)+T_double] = T_undefined; - // table[(T_char<<4)+T_float] = T_undefined; - // table[(T_char<<4)+T_boolean] = T_undefined; - table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_int; - table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_char<<4)+T_null] = T_undefined; - - // table[(T_int<<4)+T_undefined] = T_undefined; - table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_long; - table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_int<<4)+T_void] = T_undefined; - // table[(T_int<<4)+T_String] = T_undefined; - // table[(T_int<<4)+T_Object] = T_undefined; - // table[(T_int<<4)+T_double] = T_undefined; - // table[(T_int<<4)+T_float] = T_undefined; - // table[(T_int<<4)+T_boolean] = T_undefined; - table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_int; - table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_int<<4)+T_null] = T_undefined; - - // table[(T_null<<4)+T_undefined] = T_undefined; - // table[(T_null<<4)+T_byte] = T_undefined; - // table[(T_null<<4)+T_long] = T_undefined; - // table[(T_null<<4)+T_short] = T_undefined; - // table[(T_null<<4)+T_void] = T_undefined; - // table[(T_null<<4)+T_String] = T_undefined; - // table[(T_null<<4)+T_Object] = T_undefined; - // table[(T_null<<4)+T_double] = T_undefined; - // table[(T_null<<4)+T_float] = T_undefined; - // table[(T_null<<4)+T_boolean] = T_undefined; - // table[(T_null<<4)+T_char] = T_undefined; - // table[(T_null<<4)+T_int] = T_undefined; - // table[(T_null<<4)+T_null] = T_undefined; - - return table; - } - - public static final int[] get_AND_AND(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - int[] table = new int[16*16]; - - // table[(T_undefined<<4)+T_undefined] = T_undefined; - // table[(T_undefined<<4)+T_byte] = T_undefined; - // table[(T_undefined<<4)+T_long] = T_undefined; - // table[(T_undefined<<4)+T_short] = T_undefined; - // table[(T_undefined<<4)+T_void] = T_undefined; - // table[(T_undefined<<4)+T_String] = T_undefined; - // table[(T_undefined<<4)+T_Object] = T_undefined; - // table[(T_undefined<<4)+T_double] = T_undefined; - // table[(T_undefined<<4)+T_float] = T_undefined; - // table[(T_undefined<<4)+T_boolean] = T_undefined; - // table[(T_undefined<<4)+T_char] = T_undefined; - // table[(T_undefined<<4)+T_int] = T_undefined; - // table[(T_undefined<<4)+T_null] = T_undefined; - - // table[(T_byte<<4)+T_undefined] = T_undefined; - // table[(T_byte<<4)+T_byte] = T_undefined; - // table[(T_byte<<4)+T_long] = T_undefined; - // table[(T_byte<<4)+T_short] = T_undefined; - // table[(T_byte<<4)+T_void] = T_undefined; - // table[(T_byte<<4)+T_String] = T_undefined; - // table[(T_byte<<4)+T_Object] = T_undefined; - // table[(T_byte<<4)+T_double] = T_undefined; - // table[(T_byte<<4)+T_float] = T_undefined; - // table[(T_byte<<4)+T_boolean] = T_undefined; - // table[(T_byte<<4)+T_char] = T_undefined; - // table[(T_byte<<4)+T_int] = T_undefined; - // table[(T_byte<<4)+T_null] = T_undefined; - - // table[(T_long<<4)+T_undefined] = T_undefined; - // table[(T_long<<4)+T_byte] = T_undefined; - // table[(T_long<<4)+T_long] = T_undefined; - // table[(T_long<<4)+T_short] = T_undefined; - // table[(T_long<<4)+T_void] = T_undefined; - // table[(T_long<<4)+T_String] = T_undefined; - // table[(T_long<<4)+T_Object] = T_undefined; - // table[(T_long<<4)+T_double] = T_undefined; - // table[(T_long<<4)+T_float] = T_undefined; - // table[(T_long<<4)+T_boolean] = T_undefined; - // table[(T_long<<4)+T_char] = T_undefined; - // table[(T_long<<4)+T_int] = T_undefined; - // table[(T_long<<4)+T_null] = T_undefined; - - // table[(T_short<<4)+T_undefined] = T_undefined; - // table[(T_short<<4)+T_byte] = T_undefined; - // table[(T_short<<4)+T_long] = T_undefined; - // table[(T_short<<4)+T_short] = T_undefined; - // table[(T_short<<4)+T_void] = T_undefined; - // table[(T_short<<4)+T_String] = T_undefined; - // table[(T_short<<4)+T_Object] = T_undefined; - // table[(T_short<<4)+T_double] = T_undefined; - // table[(T_short<<4)+T_float] = T_undefined; - // table[(T_short<<4)+T_boolean] = T_undefined; - // table[(T_short<<4)+T_char] = T_undefined; - // table[(T_short<<4)+T_int] = T_undefined; - // table[(T_short<<4)+T_null] = T_undefined; - - // table[(T_void<<4)+T_undefined] = T_undefined; - // table[(T_void<<4)+T_byte] = T_undefined; - // table[(T_void<<4)+T_long] = T_undefined; - // table[(T_void<<4)+T_short] = T_undefined; - // table[(T_void<<4)+T_void] = T_undefined; - // table[(T_void<<4)+T_String] = T_undefined; - // table[(T_void<<4)+T_Object] = T_undefined; - // table[(T_void<<4)+T_double] = T_undefined; - // table[(T_void<<4)+T_float] = T_undefined; - // table[(T_void<<4)+T_boolean] = T_undefined; - // table[(T_void<<4)+T_char] = T_undefined; - // table[(T_void<<4)+T_int] = T_undefined; - // table[(T_void<<4)+T_null] = T_undefined; - - // table[(T_String<<4)+T_undefined] = T_undefined; - // table[(T_String<<4)+T_byte] = T_undefined; - // table[(T_String<<4)+T_long] = T_undefined; - // table[(T_String<<4)+T_short] = T_undefined; - // table[(T_String<<4)+T_void] = T_undefined; - // table[(T_String<<4)+T_String] = T_undefined; - // table[(T_String<<4)+T_Object] = T_undefined; - // table[(T_String<<4)+T_double] = T_undefined; - // table[(T_String<<4)+T_float] = T_undefined; - // table[(T_String<<4)+T_boolean] = T_undefined; - // table[(T_String<<4)+T_char] = T_undefined; - // table[(T_String<<4)+T_int] = T_undefined; - // table[(T_String<<4)+T_null] = T_undefined; - - // table[(T_Object<<4)+T_undefined] = T_undefined; - // table[(T_Object<<4)+T_byte] = T_undefined; - // table[(T_Object<<4)+T_long] = T_undefined; - // table[(T_Object<<4)+T_short] = T_undefined; - // table[(T_Object<<4)+T_void] = T_undefined; - // table[(T_Object<<4)+T_String] = T_undefined; - // table[(T_Object<<4)+T_Object] = T_undefined; - // table[(T_Object<<4)+T_double] = T_undefined; - // table[(T_Object<<4)+T_float] = T_undefined; - // table[(T_Object<<4)+T_boolean] = T_undefined; - // table[(T_Object<<4)+T_char] = T_undefined; - // table[(T_Object<<4)+T_int] = T_undefined; - // table[(T_Object<<4)+T_null] = T_undefined; - - // table[(T_double<<4)+T_undefined] = T_undefined; - // table[(T_double<<4)+T_byte] = T_undefined; - // table[(T_double<<4)+T_long] = T_undefined; - // table[(T_double<<4)+T_short] = T_undefined; - // table[(T_double<<4)+T_void] = T_undefined; - // table[(T_double<<4)+T_String] = T_undefined; - // table[(T_double<<4)+T_Object] = T_undefined; - // table[(T_double<<4)+T_double] = T_undefined; - // table[(T_double<<4)+T_float] = T_undefined; - // table[(T_double<<4)+T_boolean] = T_undefined; - // table[(T_double<<4)+T_char] = T_undefined; - // table[(T_double<<4)+T_int] = T_undefined; - // table[(T_double<<4)+T_null] = T_undefined; - - // table[(T_float<<4)+T_undefined] = T_undefined; - // table[(T_float<<4)+T_byte] = T_undefined; - // table[(T_float<<4)+T_long] = T_undefined; - // table[(T_float<<4)+T_short] = T_undefined; - // table[(T_float<<4)+T_void] = T_undefined; - // table[(T_float<<4)+T_String] = T_undefined; - // table[(T_float<<4)+T_Object] = T_undefined; - // table[(T_float<<4)+T_double] = T_undefined; - // table[(T_float<<4)+T_float] = T_undefined; - // table[(T_float<<4)+T_boolean] = T_undefined; - // table[(T_float<<4)+T_char] = T_undefined; - // table[(T_float<<4)+T_int] = T_undefined; - // table[(T_float<<4)+T_null] = T_undefined; - - // table[(T_boolean<<4)+T_undefined] = T_undefined; - // table[(T_boolean<<4)+T_byte] = T_undefined; - // table[(T_boolean<<4)+T_long] = T_undefined; - // table[(T_boolean<<4)+T_short] = T_undefined; - // table[(T_boolean<<4)+T_void] = T_undefined; - // table[(T_boolean<<4)+T_String] = T_undefined; - // table[(T_boolean<<4)+T_Object] = T_undefined; - // table[(T_boolean<<4)+T_double] = T_undefined; - // table[(T_boolean<<4)+T_float] = T_undefined; - table[(T_boolean<<4)+T_boolean] = (Boolean2Boolean<<12)+(Boolean2Boolean<<4)+T_boolean; - // table[(T_boolean<<4)+T_char] = T_undefined; - // table[(T_boolean<<4)+T_int] = T_undefined; - // table[(T_boolean<<4)+T_null] = T_undefined; - - // table[(T_char<<4)+T_undefined] = T_undefined; - // table[(T_char<<4)+T_byte] = T_undefined; - // table[(T_char<<4)+T_long] = T_undefined; - // table[(T_char<<4)+T_short] = T_undefined; - // table[(T_char<<4)+T_void] = T_undefined; - // table[(T_char<<4)+T_String] = T_undefined; - // table[(T_char<<4)+T_Object] = T_undefined; - // table[(T_char<<4)+T_double] = T_undefined; - // table[(T_char<<4)+T_float] = T_undefined; - // table[(T_char<<4)+T_boolean] = T_undefined; - // table[(T_char<<4)+T_char] = T_undefined; - // table[(T_char<<4)+T_int] = T_undefined; - // table[(T_char<<4)+T_null] = T_undefined; - - // table[(T_int<<4)+T_undefined] = T_undefined; - // table[(T_int<<4)+T_byte] = T_undefined; - // table[(T_int<<4)+T_long] = T_undefined; - // table[(T_int<<4)+T_short] = T_undefined; - // table[(T_int<<4)+T_void] = T_undefined; - // table[(T_int<<4)+T_String] = T_undefined; - // table[(T_int<<4)+T_Object] = T_undefined; - // table[(T_int<<4)+T_double] = T_undefined; - // table[(T_int<<4)+T_float] = T_undefined; - // table[(T_int<<4)+T_boolean] = T_undefined; - // table[(T_int<<4)+T_char] = T_undefined; - // table[(T_int<<4)+T_int] = T_undefined; - // table[(T_int<<4)+T_null] = T_undefined; - - // table[(T_null<<4)+T_undefined] = T_undefined; - // table[(T_null<<4)+T_byte] = T_undefined; - // table[(T_null<<4)+T_long] = T_undefined; - // table[(T_null<<4)+T_short] = T_undefined; - // table[(T_null<<4)+T_void] = T_undefined; - // table[(T_null<<4)+T_String] = T_undefined; - // table[(T_null<<4)+T_Object] = T_undefined; - // table[(T_null<<4)+T_double] = T_undefined; - // table[(T_null<<4)+T_float] = T_undefined; - // table[(T_null<<4)+T_boolean] = T_undefined; - // table[(T_null<<4)+T_char] = T_undefined; - // table[(T_null<<4)+T_int] = T_undefined; - // table[(T_null<<4)+T_null] = T_undefined; - return table; - } - - public static final int[] get_DIVIDE(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - - // int[] table = new int[16*16]; - - return get_MINUS(); - } - - public static final int[] get_EQUAL_EQUAL(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - int[] table = new int[16*16]; - - // table[(T_undefined<<4)+T_undefined] = T_undefined; - // table[(T_undefined<<4)+T_byte] = T_undefined; - // table[(T_undefined<<4)+T_long] = T_undefined; - // table[(T_undefined<<4)+T_short] = T_undefined; - // table[(T_undefined<<4)+T_void] = T_undefined; - // table[(T_undefined<<4)+T_String] = T_undefined; - // table[(T_undefined<<4)+T_Object] = T_undefined; - // table[(T_undefined<<4)+T_double] = T_undefined; - // table[(T_undefined<<4)+T_float] = T_undefined; - // table[(T_undefined<<4)+T_boolean] = T_undefined; - // table[(T_undefined<<4)+T_char] = T_undefined; - // table[(T_undefined<<4)+T_int] = T_undefined; - // table[(T_undefined<<4)+T_null] = T_undefined; - - // table[(T_byte<<4)+T_undefined] = T_undefined; - table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_boolean; - table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_boolean; - // table[(T_byte<<4)+T_void] = T_undefined; - // table[(T_byte<<4)+T_String] = T_undefined; - // table[(T_byte<<4)+T_Object] = T_undefined; - table[(T_byte<<4)+T_double] = (Byte2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_byte<<4)+T_float] = (Byte2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_byte<<4)+T_boolean] = T_undefined; - table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_boolean; - table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_boolean; - // table[(T_byte<<4)+T_null] = T_undefined; - - // table[(T_long<<4)+T_undefined] = T_undefined; - table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_boolean; - table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_boolean; - // table[(T_long<<4)+T_void] = T_undefined; - // table[(T_long<<4)+T_String] = T_undefined; - // table[(T_long<<4)+T_Object] = T_undefined; - table[(T_long<<4)+T_double] = (Long2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_long<<4)+T_float] = (Long2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_long<<4)+T_boolean] = T_undefined; - table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_boolean; - table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_boolean; - // table[(T_long<<4)+T_null] = T_undefined; - - // table[(T_short<<4)+T_undefined] = T_undefined; - table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_boolean; - table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_boolean; - // table[(T_short<<4)+T_void] = T_undefined; - // table[(T_short<<4)+T_String] = T_undefined; - // table[(T_short<<4)+T_Object] = T_undefined; - table[(T_short<<4)+T_double] = (Short2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_short<<4)+T_float] = (Short2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_short<<4)+T_boolean] = T_undefined; - table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_boolean; - table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_boolean; - // table[(T_short<<4)+T_null] = T_undefined; - - // table[(T_void<<4)+T_undefined] = T_undefined; - // table[(T_void<<4)+T_byte] = T_undefined; - // table[(T_void<<4)+T_long] = T_undefined; - // table[(T_void<<4)+T_short] = T_undefined; - // table[(T_void<<4)+T_void] = T_undefined; - // table[(T_void<<4)+T_String] = T_undefined; - // table[(T_void<<4)+T_Object] = T_undefined; - // table[(T_void<<4)+T_double] = T_undefined; - // table[(T_void<<4)+T_float] = T_undefined; - // table[(T_void<<4)+T_boolean] = T_undefined; - // table[(T_void<<4)+T_char] = T_undefined; - // table[(T_void<<4)+T_int] = T_undefined; - // table[(T_void<<4)+T_null] = T_undefined; - - // table[(T_String<<4)+T_undefined] = T_undefined; - // table[(T_String<<4)+T_byte] = T_undefined; - // table[(T_String<<4)+T_long] = T_undefined; - // table[(T_String<<4)+T_short] = T_undefined; - // table[(T_String<<4)+T_void] = T_undefined; - table[(T_JavaLangString<<4)+T_JavaLangString] = /*String2Object String2Object*/ - (T_JavaLangObject<<16)+(T_JavaLangString<<12)+(T_JavaLangObject<<8)+(T_JavaLangString<<4)+T_boolean; - table[(T_JavaLangString<<4)+T_JavaLangObject] = /*String2Object Object2Object*/ - (T_JavaLangObject<<16)+(T_JavaLangString<<12)+(T_JavaLangObject<<8)+(T_JavaLangObject<<4)+T_boolean; - // table[(T_String<<4)+T_double] = T_undefined; - // table[(T_String<<4)+T_float] = T_undefined; - // table[(T_String<<4)+T_boolean] = T_undefined; - // table[(T_String<<4)+T_char] = T_undefined; - // table[(T_String<<4)+T_int] = T_undefined; - table[(T_JavaLangString<<4)+T_null] = /*Object2String null2Object */ - (T_JavaLangObject<<16)+(T_JavaLangString<<12)+(T_JavaLangObject<<8)+(T_null<<4)+T_boolean; - - // table[(T_Object<<4)+T_undefined] = T_undefined; - // table[(T_Object<<4)+T_byte] = T_undefined; - // table[(T_Object<<4)+T_long] = T_undefined; - // table[(T_Object<<4)+T_short] = T_undefined; - // table[(T_Object<<4)+T_void] = T_undefined; - table[(T_JavaLangObject<<4)+T_JavaLangString] = /*Object2Object String2Object*/ - (T_JavaLangObject<<16)+(T_JavaLangObject<<12)+(T_JavaLangObject<<8)+(T_JavaLangString<<4)+T_boolean; - table[(T_JavaLangObject<<4)+T_JavaLangObject] = /*Object2Object Object2Object*/ - (T_JavaLangObject<<16)+(T_JavaLangObject<<12)+(T_JavaLangObject<<8)+(T_JavaLangObject<<4)+T_boolean; - // table[(T_Object<<4)+T_double] = T_undefined; - // table[(T_Object<<4)+T_float] = T_undefined; - // table[(T_Object<<4)+T_boolean] = T_undefined; - // table[(T_Object<<4)+T_char] = T_undefined; - // table[(T_Object<<4)+T_int] = T_undefined; - table[(T_JavaLangObject<<4)+T_null] = /*Object2Object null2Object*/ - (T_JavaLangObject<<16)+(T_JavaLangObject<<12)+(T_JavaLangObject<<8)+(T_null<<4)+T_boolean; - - // table[(T_double<<4)+T_undefined] = T_undefined; - table[(T_double<<4)+T_byte] = (Double2Double<<12)+(Byte2Double<<4)+T_boolean; - table[(T_double<<4)+T_long] = (Double2Double<<12)+(Long2Double<<4)+T_boolean; - table[(T_double<<4)+T_short] = (Double2Double<<12)+(Short2Double<<4)+T_boolean; - // table[(T_double<<4)+T_void] = T_undefined; - // table[(T_double<<4)+T_String] = T_undefined; - // table[(T_double<<4)+T_Object] = T_undefined; - table[(T_double<<4)+T_double] = (Double2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_double<<4)+T_float] = (Double2Double<<12)+(Float2Double<<4)+T_boolean; - // table[(T_double<<4)+T_boolean] = T_undefined; - table[(T_double<<4)+T_char] = (Double2Double<<12)+(Char2Double<<4)+T_boolean; - table[(T_double<<4)+T_int] = (Double2Double<<12)+(Int2Double<<4)+T_boolean; - // table[(T_double<<4)+T_null] = T_undefined; - - // table[(T_float<<4)+T_undefined] = T_undefined; - table[(T_float<<4)+T_byte] = (Float2Float<<12)+(Byte2Float<<4)+T_boolean; - table[(T_float<<4)+T_long] = (Float2Float<<12)+(Long2Float<<4)+T_boolean; - table[(T_float<<4)+T_short] = (Float2Float<<12)+(Short2Float<<4)+T_boolean; - // table[(T_float<<4)+T_void] = T_undefined; - // table[(T_float<<4)+T_String] = T_undefined; - // table[(T_float<<4)+T_Object] = T_undefined; - table[(T_float<<4)+T_double] = (Float2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_float<<4)+T_float] = (Float2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_float<<4)+T_boolean] = T_undefined; - table[(T_float<<4)+T_char] = (Float2Float<<12)+(Char2Float<<4)+T_boolean; - table[(T_float<<4)+T_int] = (Float2Float<<12)+(Int2Float<<4)+T_boolean; - // table[(T_float<<4)+T_null] = T_undefined; - - // table[(T_boolean<<4)+T_undefined] = T_undefined; - // table[(T_boolean<<4)+T_byte] = T_undefined; - // table[(T_boolean<<4)+T_long] = T_undefined; - // table[(T_boolean<<4)+T_short] = T_undefined; - // table[(T_boolean<<4)+T_void] = T_undefined; - // table[(T_boolean<<4)+T_String] = T_undefined; - // table[(T_boolean<<4)+T_Object] = T_undefined; - // table[(T_boolean<<4)+T_double] = T_undefined; - // table[(T_boolean<<4)+T_float] = T_undefined; - table[(T_boolean<<4)+T_boolean] = (Boolean2Boolean<<12)+(Boolean2Boolean<<4)+T_boolean; - // table[(T_boolean<<4)+T_char] = T_undefined; - // table[(T_boolean<<4)+T_int] = T_undefined; - // table[(T_boolean<<4)+T_null] = T_undefined; - - // table[(T_char<<4)+T_undefined] = T_undefined; - table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_boolean; - table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_boolean; - // table[(T_char<<4)+T_void] = T_undefined; - // table[(T_char<<4)+T_String] = T_undefined; - // table[(T_char<<4)+T_Object] = T_undefined; - table[(T_char<<4)+T_double] = (Char2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_char<<4)+T_float] = (Char2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_char<<4)+T_boolean] = T_undefined; - table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_boolean; - table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_boolean; - // table[(T_char<<4)+T_null] = T_undefined; - - // table[(T_int<<4)+T_undefined] = T_undefined; - table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_boolean; - table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_boolean; - // table[(T_int<<4)+T_void] = T_undefined; - // table[(T_int<<4)+T_String] = T_undefined; - // table[(T_int<<4)+T_Object] = T_undefined; - table[(T_int<<4)+T_double] = (Int2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_int<<4)+T_float] = (Int2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_int<<4)+T_boolean] = T_undefined; - table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_boolean; - table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_boolean; - // table[(T_int<<4)+T_null] = T_undefined; - - // table[(T_null<<4)+T_undefined] = T_undefined; - // table[(T_null<<4)+T_byte] = T_undefined; - // table[(T_null<<4)+T_long] = T_undefined; - // table[(T_null<<4)+T_short] = T_undefined; - // table[(T_null<<4)+T_void] = T_undefined; - table[(T_null<<4)+T_JavaLangString] = /*null2Object String2Object*/ - (T_JavaLangObject<<16)+(T_null<<12)+(T_JavaLangObject<<8)+(T_JavaLangString<<4)+T_boolean; - table[(T_null<<4)+T_JavaLangObject] = /*null2Object Object2Object*/ - (T_JavaLangObject<<16)+(T_null<<12)+(T_JavaLangObject<<8)+(T_JavaLangObject<<4)+T_boolean; - // table[(T_null<<4)+T_double] = T_undefined; - // table[(T_null<<4)+T_float] = T_undefined; - // table[(T_null<<4)+T_boolean] = T_undefined; - // table[(T_null<<4)+T_char] = T_undefined; - // table[(T_null<<4)+T_int] = T_undefined; - table[(T_null<<4)+T_null] = /*null2Object null2Object*/ - (T_JavaLangObject<<16)+(T_null<<12)+(T_JavaLangObject<<8)+(T_null<<4)+T_boolean; - return table; - } - - public static final int[] get_GREATER(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - // int[] table = new int[16*16]; - return get_LESS(); - } - - public static final int[] get_GREATER_EQUAL(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - // int[] table = new int[16*16]; - return get_LESS(); - } - - public static final int[] get_LEFT_SHIFT(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - int[] table = new int[16*16]; - - // table[(T_undefined<<4)+T_undefined] = T_undefined; - // table[(T_undefined<<4)+T_byte] = T_undefined; - // table[(T_undefined<<4)+T_long] = T_undefined; - // table[(T_undefined<<4)+T_short] = T_undefined; - // table[(T_undefined<<4)+T_void] = T_undefined; - // table[(T_undefined<<4)+T_String] = T_undefined; - // table[(T_undefined<<4)+T_Object] = T_undefined; - // table[(T_undefined<<4)+T_double] = T_undefined; - // table[(T_undefined<<4)+T_float] = T_undefined; - // table[(T_undefined<<4)+T_boolean] = T_undefined; - // table[(T_undefined<<4)+T_char] = T_undefined; - // table[(T_undefined<<4)+T_int] = T_undefined; - // table[(T_undefined<<4)+T_null] = T_undefined; - - // table[(T_byte<<4)+T_undefined] = T_undefined; - table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_byte<<4)+T_long] = (Byte2Int<<12)+(Long2Int<<4)+T_int; - table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_byte<<4)+T_void] = T_undefined; - // table[(T_byte<<4)+T_String] = T_undefined; - // table[(T_byte<<4)+T_Object] = T_undefined; - // table[(T_byte<<4)+T_double] = T_undefined; - // table[(T_byte<<4)+T_float] = T_undefined; - // table[(T_byte<<4)+T_boolean] = T_undefined; - table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_int; - table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_byte<<4)+T_null] = T_undefined; - - // table[(T_long<<4)+T_undefined] = T_undefined; - table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Int<<4)+T_long; - table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Int<<4)+T_long; - table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Int<<4)+T_long; - // table[(T_long<<4)+T_void] = T_undefined; - // table[(T_long<<4)+T_String] = T_undefined; - // table[(T_long<<4)+T_Object] = T_undefined; - // table[(T_long<<4)+T_double] = T_undefined; - // table[(T_long<<4)+T_float] = T_undefined; - // table[(T_long<<4)+T_boolean] = T_undefined; - table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Int<<4)+T_long; - table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Int<<4)+T_long; - // table[(T_long<<4)+T_null] = T_undefined; - - // table[(T_short<<4)+T_undefined] = T_undefined; - table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_short<<4)+T_long] = (Short2Int<<12)+(Long2Int<<4)+T_int; - table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_short<<4)+T_void] = T_undefined; - // table[(T_short<<4)+T_String] = T_undefined; - // table[(T_short<<4)+T_Object] = T_undefined; - // table[(T_short<<4)+T_double] = T_undefined; - // table[(T_short<<4)+T_float] = T_undefined; - // table[(T_short<<4)+T_boolean] = T_undefined; - table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_int; - table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_short<<4)+T_null] = T_undefined; - - // table[(T_void<<4)+T_undefined] = T_undefined; - // table[(T_void<<4)+T_byte] = T_undefined; - // table[(T_void<<4)+T_long] = T_undefined; - // table[(T_void<<4)+T_short] = T_undefined; - // table[(T_void<<4)+T_void] = T_undefined; - // table[(T_void<<4)+T_String] = T_undefined; - // table[(T_void<<4)+T_Object] = T_undefined; - // table[(T_void<<4)+T_double] = T_undefined; - // table[(T_void<<4)+T_float] = T_undefined; - // table[(T_void<<4)+T_boolean] = T_undefined; - // table[(T_void<<4)+T_char] = T_undefined; - // table[(T_void<<4)+T_int] = T_undefined; - // table[(T_void<<4)+T_null] = T_undefined; - - // table[(T_String<<4)+T_undefined] = T_undefined; - // table[(T_String<<4)+T_byte] = T_undefined; - // table[(T_String<<4)+T_long] = T_undefined; - // table[(T_String<<4)+T_short] = T_undefined; - // table[(T_String<<4)+T_void] = T_undefined; - // table[(T_String<<4)+T_String] = T_undefined; - // table[(T_String<<4)+T_Object] = T_undefined; - // table[(T_String<<4)+T_double] = T_undefined; - // table[(T_String<<4)+T_float] = T_undefined; - // table[(T_String<<4)+T_boolean] = T_undefined; - // table[(T_String<<4)+T_char] = T_undefined; - // table[(T_String<<4)+T_int] = T_undefined; - // table[(T_String<<4)+T_null] = T_undefined; - - // table[(T_Object<<4)+T_undefined] = T_undefined; - // table[(T_Object<<4)+T_byte] = T_undefined; - // table[(T_Object<<4)+T_long] = T_undefined; - // table[(T_Object<<4)+T_short] = T_undefined; - // table[(T_Object<<4)+T_void] = T_undefined; - // table[(T_Object<<4)+T_String] = T_undefined; - // table[(T_Object<<4)+T_Object] = T_undefined; - // table[(T_Object<<4)+T_double] = T_undefined; - // table[(T_Object<<4)+T_float] = T_undefined; - // table[(T_Object<<4)+T_boolean] = T_undefined; - // table[(T_Object<<4)+T_char] = T_undefined; - // table[(T_Object<<4)+T_int] = T_undefined; - // table[(T_Object<<4)+T_null] = T_undefined; - - // table[(T_double<<4)+T_undefined] = T_undefined; - // table[(T_double<<4)+T_byte] = T_undefined; - // table[(T_double<<4)+T_long] = T_undefined; - // table[(T_double<<4)+T_short] = T_undefined; - // table[(T_double<<4)+T_void] = T_undefined; - // table[(T_double<<4)+T_String] = T_undefined; - // table[(T_double<<4)+T_Object] = T_undefined; - // table[(T_double<<4)+T_double] = T_undefined; - // table[(T_double<<4)+T_float] = T_undefined; - // table[(T_double<<4)+T_boolean] = T_undefined; - // table[(T_double<<4)+T_char] = T_undefined; - // table[(T_double<<4)+T_int] = T_undefined; - // table[(T_double<<4)+T_null] = T_undefined; - - // table[(T_float<<4)+T_undefined] = T_undefined; - // table[(T_float<<4)+T_byte] = T_undefined; - // table[(T_float<<4)+T_long] = T_undefined; - // table[(T_float<<4)+T_short] = T_undefined; - // table[(T_float<<4)+T_void] = T_undefined; - // table[(T_float<<4)+T_String] = T_undefined; - // table[(T_float<<4)+T_Object] = T_undefined; - // table[(T_float<<4)+T_double] = T_undefined; - // table[(T_float<<4)+T_float] = T_undefined; - // table[(T_float<<4)+T_boolean] = T_undefined; - // table[(T_float<<4)+T_char] = T_undefined; - // table[(T_float<<4)+T_int] = T_undefined; - // table[(T_float<<4)+T_null] = T_undefined; - - // table[(T_boolean<<4)+T_undefined] = T_undefined; - // table[(T_boolean<<4)+T_byte] = T_undefined; - // table[(T_boolean<<4)+T_long] = T_undefined; - // table[(T_boolean<<4)+T_short] = T_undefined; - // table[(T_boolean<<4)+T_void] = T_undefined; - // table[(T_boolean<<4)+T_String] = T_undefined; - // table[(T_boolean<<4)+T_Object] = T_undefined; - // table[(T_boolean<<4)+T_double] = T_undefined; - // table[(T_boolean<<4)+T_float] = T_undefined; - // table[(T_boolean<<4)+T_boolean] = T_undefined; - // table[(T_boolean<<4)+T_char] = T_undefined; - // table[(T_boolean<<4)+T_int] = T_undefined; - // table[(T_boolean<<4)+T_null] = T_undefined; - - // table[(T_char<<4)+T_undefined] = T_undefined; - table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_char<<4)+T_long] = (Char2Int<<12)+(Long2Int<<4)+T_int; - table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_char<<4)+T_void] = T_undefined; - // table[(T_char<<4)+T_String] = T_undefined; - // table[(T_char<<4)+T_Object] = T_undefined; - // table[(T_char<<4)+T_double] = T_undefined; - // table[(T_char<<4)+T_float] = T_undefined; - // table[(T_char<<4)+T_boolean] = T_undefined; - table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_int; - table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_char<<4)+T_null] = T_undefined; - - // table[(T_int<<4)+T_undefined] = T_undefined; - table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_int<<4)+T_long] = (Int2Int<<12)+(Long2Int<<4)+T_int; - table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_int<<4)+T_void] = T_undefined; - // table[(T_int<<4)+T_String] = T_undefined; - // table[(T_int<<4)+T_Object] = T_undefined; - // table[(T_int<<4)+T_double] = T_undefined; - // table[(T_int<<4)+T_float] = T_undefined; - // table[(T_int<<4)+T_boolean] = T_undefined; - table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_int; - table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_int<<4)+T_null] = T_undefined; - - // table[(T_null<<4)+T_undefined] = T_undefined; - // table[(T_null<<4)+T_byte] = T_undefined; - // table[(T_null<<4)+T_long] = T_undefined; - // table[(T_null<<4)+T_short] = T_undefined; - // table[(T_null<<4)+T_void] = T_undefined; - // table[(T_null<<4)+T_String] = T_undefined; - // table[(T_null<<4)+T_Object] = T_undefined; - // table[(T_null<<4)+T_double] = T_undefined; - // table[(T_null<<4)+T_float] = T_undefined; - // table[(T_null<<4)+T_boolean] = T_undefined; - // table[(T_null<<4)+T_char] = T_undefined; - // table[(T_null<<4)+T_int] = T_undefined; - // table[(T_null<<4)+T_null] = T_undefined; - - return table; - } - - public static final int[] get_LESS(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - int[] table = new int[16*16]; - - // table[(T_undefined<<4)+T_undefined] = T_undefined; - // table[(T_undefined<<4)+T_byte] = T_undefined; - // table[(T_undefined<<4)+T_long] = T_undefined; - // table[(T_undefined<<4)+T_short] = T_undefined; - // table[(T_undefined<<4)+T_void] = T_undefined; - // table[(T_undefined<<4)+T_String] = T_undefined; - // table[(T_undefined<<4)+T_Object] = T_undefined; - // table[(T_undefined<<4)+T_double] = T_undefined; - // table[(T_undefined<<4)+T_float] = T_undefined; - // table[(T_undefined<<4)+T_boolean] = T_undefined; - // table[(T_undefined<<4)+T_char] = T_undefined; - // table[(T_undefined<<4)+T_int] = T_undefined; - // table[(T_undefined<<4)+T_null] = T_undefined; - - // table[(T_byte<<4)+T_undefined] = T_undefined; - table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_boolean; - table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_boolean; - // table[(T_byte<<4)+T_void] = T_undefined; - // table[(T_byte<<4)+T_String] = T_undefined; - // table[(T_byte<<4)+T_Object] = T_undefined; - table[(T_byte<<4)+T_double] = (Byte2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_byte<<4)+T_float] = (Byte2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_byte<<4)+T_boolean] = T_undefined; - table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_boolean; - table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_boolean; - // table[(T_byte<<4)+T_null] = T_undefined; - - // table[(T_long<<4)+T_undefined] = T_undefined; - table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_boolean; - table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_boolean; - // table[(T_long<<4)+T_void] = T_undefined; - // table[(T_long<<4)+T_String] = T_undefined; - // table[(T_long<<4)+T_Object] = T_undefined; - table[(T_long<<4)+T_double] = (Long2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_long<<4)+T_float] = (Long2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_long<<4)+T_boolean] = T_undefined; - table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_boolean; - table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_boolean; - // table[(T_long<<4)+T_null] = T_undefined; - - // table[(T_short<<4)+T_undefined] = T_undefined; - table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_boolean; - table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_boolean; - // table[(T_short<<4)+T_void] = T_undefined; - // table[(T_short<<4)+T_String] = T_undefined; - // table[(T_short<<4)+T_Object] = T_undefined; - table[(T_short<<4)+T_double] = (Short2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_short<<4)+T_float] = (Short2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_short<<4)+T_boolean] = T_undefined; - table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_boolean; - table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_boolean; - // table[(T_short<<4)+T_null] = T_undefined; - - // table[(T_void<<4)+T_undefined] = T_undefined; - // table[(T_void<<4)+T_byte] = T_undefined; - // table[(T_void<<4)+T_long] = T_undefined; - // table[(T_void<<4)+T_short] = T_undefined; - // table[(T_void<<4)+T_void] = T_undefined; - // table[(T_void<<4)+T_String] = T_undefined; - // table[(T_void<<4)+T_Object] = T_undefined; - // table[(T_void<<4)+T_double] = T_undefined; - // table[(T_void<<4)+T_float] = T_undefined; - // table[(T_void<<4)+T_boolean] = T_undefined; - // table[(T_void<<4)+T_char] = T_undefined; - // table[(T_void<<4)+T_int] = T_undefined; - // table[(T_void<<4)+T_null] = T_undefined; - - // table[(T_String<<4)+T_undefined] = T_undefined; - // table[(T_String<<4)+T_byte] = T_undefined; - // table[(T_String<<4)+T_long] = T_undefined; - // table[(T_String<<4)+T_short] = T_undefined; - // table[(T_String<<4)+T_void] = T_undefined; - // table[(T_String<<4)+T_String] = T_undefined; - // table[(T_String<<4)+T_Object] = T_undefined; - // table[(T_String<<4)+T_double] = T_undefined; - // table[(T_String<<4)+T_float] = T_undefined; - // table[(T_String<<4)+T_boolean] = T_undefined; - // table[(T_String<<4)+T_char] = T_undefined; - // table[(T_String<<4)+T_int] = T_undefined; - // table[(T_String<<4)+T_null] = T_undefined; - - // table[(T_Object<<4)+T_undefined] = T_undefined; - // table[(T_Object<<4)+T_byte] = T_undefined; - // table[(T_Object<<4)+T_long] = T_undefined; - // table[(T_Object<<4)+T_short] = T_undefined; - // table[(T_Object<<4)+T_void] = T_undefined; - // table[(T_Object<<4)+T_String] = T_undefined; - // table[(T_Object<<4)+T_Object] = T_undefined; - // table[(T_Object<<4)+T_double] = T_undefined; - // table[(T_Object<<4)+T_float] = T_undefined; - // table[(T_Object<<4)+T_boolean] = T_undefined; - // table[(T_Object<<4)+T_char] = T_undefined; - // table[(T_Object<<4)+T_int] = T_undefined; - // table[(T_Object<<4)+T_null] = T_undefined; - - // table[(T_double<<4)+T_undefined] = T_undefined; - table[(T_double<<4)+T_byte] = (Double2Double<<12)+(Byte2Double<<4)+T_boolean; - table[(T_double<<4)+T_long] = (Double2Double<<12)+(Long2Double<<4)+T_boolean; - table[(T_double<<4)+T_short] = (Double2Double<<12)+(Short2Double<<4)+T_boolean; - // table[(T_double<<4)+T_void] = T_undefined; - // table[(T_double<<4)+T_String] = T_undefined; - // table[(T_double<<4)+T_Object] = T_undefined; - table[(T_double<<4)+T_double] = (Double2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_double<<4)+T_float] = (Double2Double<<12)+(Float2Double<<4)+T_boolean; - // table[(T_double<<4)+T_boolean] = T_undefined; - table[(T_double<<4)+T_char] = (Double2Double<<12)+(Char2Double<<4)+T_boolean; - table[(T_double<<4)+T_int] = (Double2Double<<12)+(Int2Double<<4)+T_boolean; - // table[(T_double<<4)+T_null] = T_undefined; - - // table[(T_float<<4)+T_undefined] = T_undefined; - table[(T_float<<4)+T_byte] = (Float2Float<<12)+(Byte2Float<<4)+T_boolean; - table[(T_float<<4)+T_long] = (Float2Float<<12)+(Long2Float<<4)+T_boolean; - table[(T_float<<4)+T_short] = (Float2Float<<12)+(Short2Float<<4)+T_boolean; - // table[(T_float<<4)+T_void] = T_undefined; - // table[(T_float<<4)+T_String] = T_undefined; - // table[(T_float<<4)+T_Object] = T_undefined; - table[(T_float<<4)+T_double] = (Float2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_float<<4)+T_float] = (Float2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_float<<4)+T_boolean] = T_undefined; - table[(T_float<<4)+T_char] = (Float2Float<<12)+(Char2Float<<4)+T_boolean; - table[(T_float<<4)+T_int] = (Float2Float<<12)+(Int2Float<<4)+T_boolean; - // table[(T_float<<4)+T_null] = T_undefined; - - // table[(T_boolean<<4)+T_undefined] = T_undefined; - // table[(T_boolean<<4)+T_byte] = T_undefined; - // table[(T_boolean<<4)+T_long] = T_undefined; - // table[(T_boolean<<4)+T_short] = T_undefined; - // table[(T_boolean<<4)+T_void] = T_undefined; - // table[(T_boolean<<4)+T_String] = T_undefined; - // table[(T_boolean<<4)+T_Object] = T_undefined; - // table[(T_boolean<<4)+T_double] = T_undefined; - // table[(T_boolean<<4)+T_float] = T_undefined; - // table[(T_boolean<<4)+T_boolean] = T_undefined; - // table[(T_boolean<<4)+T_char] = T_undefined; - // table[(T_boolean<<4)+T_int] = T_undefined; - // table[(T_boolean<<4)+T_null] = T_undefined; - - // table[(T_char<<4)+T_undefined] = T_undefined; - table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_boolean; - table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_boolean; - // table[(T_char<<4)+T_void] = T_undefined; - // table[(T_char<<4)+T_String] = T_undefined; - // table[(T_char<<4)+T_Object] = T_undefined; - table[(T_char<<4)+T_double] = (Char2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_char<<4)+T_float] = (Char2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_char<<4)+T_boolean] = T_undefined; - table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_boolean; - table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_boolean; - // table[(T_char<<4)+T_null] = T_undefined; - - // table[(T_int<<4)+T_undefined] = T_undefined; - table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_boolean; - table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_boolean; - table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_boolean; - // table[(T_int<<4)+T_void] = T_undefined; - // table[(T_int<<4)+T_String] = T_undefined; - // table[(T_int<<4)+T_Object] = T_undefined; - table[(T_int<<4)+T_double] = (Int2Double<<12)+(Double2Double<<4)+T_boolean; - table[(T_int<<4)+T_float] = (Int2Float<<12)+(Float2Float<<4)+T_boolean; - // table[(T_int<<4)+T_boolean] = T_undefined; - table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_boolean; - table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_boolean; - // table[(T_int<<4)+T_null] = T_undefined; - - // table[(T_null<<4)+T_undefined] = T_undefined; - // table[(T_null<<4)+T_byte] = T_undefined; - // table[(T_null<<4)+T_long] = T_undefined; - // table[(T_null<<4)+T_short] = T_undefined; - // table[(T_null<<4)+T_void] = T_undefined; - // table[(T_null<<4)+T_String] = T_undefined; - // table[(T_null<<4)+T_Object] = T_undefined; - // table[(T_null<<4)+T_double] = T_undefined; - // table[(T_null<<4)+T_float] = T_undefined; - // table[(T_null<<4)+T_boolean] = T_undefined; - // table[(T_null<<4)+T_char] = T_undefined; - // table[(T_null<<4)+T_int] = T_undefined; - // table[(T_null<<4)+T_null] = T_undefined; - - return table; - } - - public static final int[] get_LESS_EQUAL(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - // int[] table = new int[16*16]; - return get_LESS(); - } - - public static final int[] get_MINUS(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - int[] table = get_PLUS().clone(); - - // customization - table[(T_JavaLangString<<4)+T_byte] = T_undefined; - table[(T_JavaLangString<<4)+T_long] = T_undefined; - table[(T_JavaLangString<<4)+T_short] = T_undefined; - table[(T_JavaLangString<<4)+T_void] = T_undefined; - table[(T_JavaLangString<<4)+T_JavaLangString] = T_undefined; - table[(T_JavaLangString<<4)+T_JavaLangObject] = T_undefined; - table[(T_JavaLangString<<4)+T_double] = T_undefined; - table[(T_JavaLangString<<4)+T_float] = T_undefined; - table[(T_JavaLangString<<4)+T_boolean] = T_undefined; - table[(T_JavaLangString<<4)+T_char] = T_undefined; - table[(T_JavaLangString<<4)+T_int] = T_undefined; - table[(T_JavaLangString<<4)+T_null] = T_undefined; - - table[(T_byte<<4) +T_JavaLangString] = T_undefined; - table[(T_long<<4) +T_JavaLangString] = T_undefined; - table[(T_short<<4) +T_JavaLangString] = T_undefined; - table[(T_void<<4) +T_JavaLangString] = T_undefined; - table[(T_JavaLangObject<<4) +T_JavaLangString] = T_undefined; - table[(T_double<<4) +T_JavaLangString] = T_undefined; - table[(T_float<<4) +T_JavaLangString] = T_undefined; - table[(T_boolean<<4)+T_JavaLangString] = T_undefined; - table[(T_char<<4) +T_JavaLangString] = T_undefined; - table[(T_int<<4) +T_JavaLangString] = T_undefined; - table[(T_null<<4) +T_JavaLangString] = T_undefined; - - table[(T_null<<4) +T_null] = T_undefined; - - return table; - } - - public static final int[] get_MULTIPLY(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - // int[] table = new int[16*16]; - return get_MINUS(); - } - - public static final int[] get_OR(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - - // int[] table = new int[16*16]; - return get_AND(); - } - - public static final int[] get_OR_OR(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - // int[] table = new int[16*16]; - return get_AND_AND(); - } - - public static final int[] get_PLUS(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - int[] table = new int[16*16]; - - // table[(T_undefined<<4)+T_undefined] = T_undefined; - // table[(T_undefined<<4)+T_byte] = T_undefined; - // table[(T_undefined<<4)+T_long] = T_undefined; - // table[(T_undefined<<4)+T_short] = T_undefined; - // table[(T_undefined<<4)+T_void] = T_undefined; - // table[(T_undefined<<4)+T_String] = T_undefined; - // table[(T_undefined<<4)+T_Object] = T_undefined; - // table[(T_undefined<<4)+T_double] = T_undefined; - // table[(T_undefined<<4)+T_float] = T_undefined; - // table[(T_undefined<<4)+T_boolean] = T_undefined; - // table[(T_undefined<<4)+T_char] = T_undefined; - // table[(T_undefined<<4)+T_int] = T_undefined; - // table[(T_undefined<<4)+T_null] = T_undefined; - - // table[(T_byte<<4)+T_undefined] = T_undefined; - table[(T_byte<<4)+T_byte] = (Byte2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_byte<<4)+T_long] = (Byte2Long<<12)+(Long2Long<<4)+T_long; - table[(T_byte<<4)+T_short] = (Byte2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_byte<<4)+T_void] = T_undefined; - table[(T_byte<<4)+T_JavaLangString] = (Byte2Byte<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_byte<<4)+T_Object] = T_undefined; - table[(T_byte<<4)+T_double] = (Byte2Double<<12)+(Double2Double<<4)+T_double; - table[(T_byte<<4)+T_float] = (Byte2Float<<12)+(Float2Float<<4)+T_float; - // table[(T_byte<<4)+T_boolean] = T_undefined; - table[(T_byte<<4)+T_char] = (Byte2Int<<12)+(Char2Int<<4)+T_int; - table[(T_byte<<4)+T_int] = (Byte2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_byte<<4)+T_null] = T_undefined; - - // table[(T_long<<4)+T_undefined] = T_undefined; - table[(T_long<<4)+T_byte] = (Long2Long<<12)+(Byte2Long<<4)+T_long; - table[(T_long<<4)+T_long] = (Long2Long<<12)+(Long2Long<<4)+T_long; - table[(T_long<<4)+T_short] = (Long2Long<<12)+(Short2Long<<4)+T_long; - // table[(T_long<<4)+T_void] = T_undefined; - table[(T_long<<4)+T_JavaLangString] = (Long2Long<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_long<<4)+T_Object] = T_undefined; - table[(T_long<<4)+T_double] = (Long2Double<<12)+(Double2Double<<4)+T_double; - table[(T_long<<4)+T_float] = (Long2Float<<12)+(Float2Float<<4)+T_float; - // table[(T_long<<4)+T_boolean] = T_undefined; - table[(T_long<<4)+T_char] = (Long2Long<<12)+(Char2Long<<4)+T_long; - table[(T_long<<4)+T_int] = (Long2Long<<12)+(Int2Long<<4)+T_long; - // table[(T_long<<4)+T_null] = T_undefined; - - // table[(T_short<<4)+T_undefined] = T_undefined; - table[(T_short<<4)+T_byte] = (Short2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_short<<4)+T_long] = (Short2Long<<12)+(Long2Long<<4)+T_long; - table[(T_short<<4)+T_short] = (Short2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_short<<4)+T_void] = T_undefined; - table[(T_short<<4)+T_JavaLangString] = (Short2Short<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_short<<4)+T_Object] = T_undefined; - table[(T_short<<4)+T_double] = (Short2Double<<12)+(Double2Double<<4)+T_double; - table[(T_short<<4)+T_float] = (Short2Float<<12)+(Float2Float<<4)+T_float; - // table[(T_short<<4)+T_boolean] = T_undefined; - table[(T_short<<4)+T_char] = (Short2Int<<12)+(Char2Int<<4)+T_int; - table[(T_short<<4)+T_int] = (Short2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_short<<4)+T_null] = T_undefined; - - // table[(T_void<<4)+T_undefined] = T_undefined; - // table[(T_void<<4)+T_byte] = T_undefined; - // table[(T_void<<4)+T_long] = T_undefined; - // table[(T_void<<4)+T_short] = T_undefined; - // table[(T_void<<4)+T_void] = T_undefined; - // table[(T_void<<4)+T_String] = T_undefined; - // table[(T_void<<4)+T_Object] = T_undefined; - // table[(T_void<<4)+T_double] = T_undefined; - // table[(T_void<<4)+T_float] = T_undefined; - // table[(T_void<<4)+T_boolean] = T_undefined; - // table[(T_void<<4)+T_char] = T_undefined; - // table[(T_void<<4)+T_int] = T_undefined; - // table[(T_void<<4)+T_null] = T_undefined; - - // table[(T_String<<4)+T_undefined] = T_undefined; - table[(T_JavaLangString<<4)+T_byte] = (String2String<<12)+(Byte2Byte<<4)+T_JavaLangString; - table[(T_JavaLangString<<4)+T_long] = (String2String<<12)+(Long2Long<<4)+T_JavaLangString; - table[(T_JavaLangString<<4)+T_short] = (String2String<<12)+(Short2Short<<4)+T_JavaLangString; - // table[(T_String<<4)+T_void] = T_undefined; - table[(T_JavaLangString<<4)+T_JavaLangString] = (String2String<<12)+(String2String<<4)+T_JavaLangString; - table[(T_JavaLangString<<4)+T_JavaLangObject] = (String2String<<12)+(Object2Object<<4)+T_JavaLangString; - table[(T_JavaLangString<<4)+T_double] = (String2String<<12)+(Double2Double<<4)+T_JavaLangString; - table[(T_JavaLangString<<4)+T_float] = (String2String<<12)+(Float2Float<<4)+T_JavaLangString; - table[(T_JavaLangString<<4)+T_boolean] = (String2String<<12)+(Boolean2Boolean<<4)+T_JavaLangString; - table[(T_JavaLangString<<4)+T_char] = (String2String<<12)+(Char2Char<<4)+T_JavaLangString; - table[(T_JavaLangString<<4)+T_int] = (String2String<<12)+(Int2Int<<4)+T_JavaLangString; - table[(T_JavaLangString<<4)+T_null] = (String2String<<12)+(T_null<<8)+(T_null<<4)+T_JavaLangString; - - // table[(T_Object<<4)+T_undefined] = T_undefined; - // table[(T_Object<<4)+T_byte] = T_undefined; - // table[(T_Object<<4)+T_long] = T_undefined; - // table[(T_Object<<4)+T_short] = T_undefined; - // table[(T_Object<<4)+T_void] = T_undefined; - table[(T_JavaLangObject<<4)+T_JavaLangString] = (Object2Object<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_Object<<4)+T_Object] = T_undefined; - // table[(T_Object<<4)+T_double] = T_undefined; - // table[(T_Object<<4)+T_float] = T_undefined; - // table[(T_Object<<4)+T_boolean] = T_undefined; - // table[(T_Object<<4)+T_char] = T_undefined; - // table[(T_Object<<4)+T_int] = T_undefined; - // table[(T_Object<<4)+T_null] = T_undefined; - - // table[(T_double<<4)+T_undefined] = T_undefined; - table[(T_double<<4)+T_byte] = (Double2Double<<12)+(Byte2Double<<4)+T_double; - table[(T_double<<4)+T_long] = (Double2Double<<12)+(Long2Double<<4)+T_double; - table[(T_double<<4)+T_short] = (Double2Double<<12)+(Short2Double<<4)+T_double; - // table[(T_double<<4)+T_void] = T_undefined; - table[(T_double<<4)+T_JavaLangString] = (Double2Double<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_double<<4)+T_Object] = T_undefined; - table[(T_double<<4)+T_double] = (Double2Double<<12)+(Double2Double<<4)+T_double; - table[(T_double<<4)+T_float] = (Double2Double<<12)+(Float2Double<<4)+T_double; - // table[(T_double<<4)+T_boolean] = T_undefined; - table[(T_double<<4)+T_char] = (Double2Double<<12)+(Char2Double<<4)+T_double; - table[(T_double<<4)+T_int] = (Double2Double<<12)+(Int2Double<<4)+T_double; - // table[(T_double<<4)+T_null] = T_undefined; - - // table[(T_float<<4)+T_undefined] = T_undefined; - table[(T_float<<4)+T_byte] = (Float2Float<<12)+(Byte2Float<<4)+T_float; - table[(T_float<<4)+T_long] = (Float2Float<<12)+(Long2Float<<4)+T_float; - table[(T_float<<4)+T_short] = (Float2Float<<12)+(Short2Float<<4)+T_float; - // table[(T_float<<4)+T_void] = T_undefined; - table[(T_float<<4)+T_JavaLangString] = (Float2Float<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_float<<4)+T_Object] = T_undefined; - table[(T_float<<4)+T_double] = (Float2Double<<12)+(Double2Double<<4)+T_double; - table[(T_float<<4)+T_float] = (Float2Float<<12)+(Float2Float<<4)+T_float; - // table[(T_float<<4)+T_boolean] = T_undefined; - table[(T_float<<4)+T_char] = (Float2Float<<12)+(Char2Float<<4)+T_float; - table[(T_float<<4)+T_int] = (Float2Float<<12)+(Int2Float<<4)+T_float; - // table[(T_float<<4)+T_null] = T_undefined; - - // table[(T_boolean<<4)+T_undefined] = T_undefined; - // table[(T_boolean<<4)+T_byte] = T_undefined; - // table[(T_boolean<<4)+T_long] = T_undefined; - // table[(T_boolean<<4)+T_short] = T_undefined; - // table[(T_boolean<<4)+T_void] = T_undefined; - table[(T_boolean<<4)+T_JavaLangString] = (Boolean2Boolean<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_boolean<<4)+T_Object] = T_undefined; - // table[(T_boolean<<4)+T_double] = T_undefined; - // table[(T_boolean<<4)+T_float] = T_undefined; - // table[(T_boolean<<4)+T_boolean] = T_undefined; - // table[(T_boolean<<4)+T_char] = T_undefined; - // table[(T_boolean<<4)+T_int] = T_undefined; - // table[(T_boolean<<4)+T_null] = T_undefined; - - // table[(T_char<<4)+T_undefined] = T_undefined; - table[(T_char<<4)+T_byte] = (Char2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_char<<4)+T_long] = (Char2Long<<12)+(Long2Long<<4)+T_long; - table[(T_char<<4)+T_short] = (Char2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_char<<4)+T_void] = T_undefined; - table[(T_char<<4)+T_JavaLangString] = (Char2Char<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_char<<4)+T_Object] = T_undefined; - table[(T_char<<4)+T_double] = (Char2Double<<12)+(Double2Double<<4)+T_double; - table[(T_char<<4)+T_float] = (Char2Float<<12)+(Float2Float<<4)+T_float; - // table[(T_char<<4)+T_boolean] = T_undefined; - table[(T_char<<4)+T_char] = (Char2Int<<12)+(Char2Int<<4)+T_int; - table[(T_char<<4)+T_int] = (Char2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_char<<4)+T_null] = T_undefined; - - // table[(T_int<<4)+T_undefined] = T_undefined; - table[(T_int<<4)+T_byte] = (Int2Int<<12)+(Byte2Int<<4)+T_int; - table[(T_int<<4)+T_long] = (Int2Long<<12)+(Long2Long<<4)+T_long; - table[(T_int<<4)+T_short] = (Int2Int<<12)+(Short2Int<<4)+T_int; - // table[(T_int<<4)+T_void] = T_undefined; - table[(T_int<<4)+T_JavaLangString] = (Int2Int<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_int<<4)+T_Object] = T_undefined; - table[(T_int<<4)+T_double] = (Int2Double<<12)+(Double2Double<<4)+T_double; - table[(T_int<<4)+T_float] = (Int2Float<<12)+(Float2Float<<4)+T_float; - // table[(T_int<<4)+T_boolean] = T_undefined; - table[(T_int<<4)+T_char] = (Int2Int<<12)+(Char2Int<<4)+T_int; - table[(T_int<<4)+T_int] = (Int2Int<<12)+(Int2Int<<4)+T_int; - // table[(T_int<<4)+T_null] = T_undefined; - - // table[(T_null<<4)+T_undefined] = T_undefined; - // table[(T_null<<4)+T_byte] = T_undefined; - // table[(T_null<<4)+T_long] = T_undefined; - // table[(T_null<<4)+T_short] = T_undefined; - // table[(T_null<<4)+T_void] = T_undefined; - table[(T_null<<4)+T_JavaLangString] = (T_null<<16)+(T_null<<12)+(String2String<<4)+T_JavaLangString; - // table[(T_null<<4)+T_Object] = T_undefined; - // table[(T_null<<4)+T_double] = T_undefined; - // table[(T_null<<4)+T_float] = T_undefined; - // table[(T_null<<4)+T_boolean] = T_undefined; - // table[(T_null<<4)+T_char] = T_undefined; - // table[(T_null<<4)+T_int] = T_undefined; - // table[(T_null<<4)+T_null] = (Null2String<<12)+(Null2String<<4)+T_String;; - - return table; - } - - public static final int[] get_REMAINDER(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - // int[] table = new int[16*16]; - return get_MINUS(); - } - - public static final int[] get_RIGHT_SHIFT(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - // int[] table = new int[16*16]; - return get_LEFT_SHIFT(); - } - - public static final int[] get_UNSIGNED_RIGHT_SHIFT(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - // int[] table = new int[16*16]; - return get_LEFT_SHIFT(); - } - - public static final int[] get_XOR(){ - - //the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 - - // int[] table = new int[16*16]; - return get_AND(); - } - - public String operatorToString() { - int op = (this.bits & OperatorMASK) >> OperatorSHIFT; - switch (op) { - case EQUAL_EQUAL : - return "=="; //$NON-NLS-1$ - case LESS_EQUAL : - return "<="; //$NON-NLS-1$ - case GREATER_EQUAL : - return ">="; //$NON-NLS-1$ - case NOT_EQUAL : - return "!="; //$NON-NLS-1$ - case LEFT_SHIFT : - return "<<"; //$NON-NLS-1$ - case RIGHT_SHIFT : - return ">>"; //$NON-NLS-1$ - case UNSIGNED_RIGHT_SHIFT : - return ">>>"; //$NON-NLS-1$ - case OR_OR : - return "||"; //$NON-NLS-1$ - case AND_AND : - return "&&"; //$NON-NLS-1$ - case PLUS : - return "+"; //$NON-NLS-1$ - case MINUS : - return "-"; //$NON-NLS-1$ - case NOT : - return "!"; //$NON-NLS-1$ - case REMAINDER : - return "%"; //$NON-NLS-1$ - case XOR : - return "^"; //$NON-NLS-1$ - case AND : - return "&"; //$NON-NLS-1$ - case MULTIPLY : - return "*"; //$NON-NLS-1$ - case OR : - return "|"; //$NON-NLS-1$ - case TWIDDLE : - return "~"; //$NON-NLS-1$ - case DIVIDE : - return "/"; //$NON-NLS-1$ - case GREATER : - return ">"; //$NON-NLS-1$ - case LESS : - return "<"; //$NON-NLS-1$ - case QUESTIONCOLON : - return "?:"; //$NON-NLS-1$ - case EQUAL : - return "="; //$NON-NLS-1$ - case INSTANCEOF : - return "instanceof"; //$NON-NLS-1$ - case PLUS_PLUS : - return "++"; //$NON-NLS-1$ - case MINUS_MINUS : - return "--"; //$NON-NLS-1$ - } - return "unknown operator " + op; //$NON-NLS-1$ - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output){ - - output.append('('); - return printExpressionNoParenthesis(0, output).append(')'); - } - - public abstract StringBuilder printExpressionNoParenthesis(int indent, StringBuilder output); -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java deleted file mode 100644 index ffd1c41..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/OperatorIds.java +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -public interface OperatorIds { - /** org.eclipse.jdt.core.dom.InfixExpression */ - public static final int AND_AND = 0; - public static final int OR_OR = 1; - public static final int AND = 2; - public static final int OR = 3; - public static final int LESS = 4; - public static final int LESS_EQUAL = 5; - public static final int GREATER = 6; - public static final int GREATER_EQUAL = 7; - public static final int XOR = 8; - public static final int DIVIDE = 9; - public static final int LEFT_SHIFT = 10; - public static final int NOT = 11; - public static final int TWIDDLE = 12; - public static final int MINUS = 13; - public static final int PLUS = 14; - public static final int MULTIPLY = 15; - public static final int REMAINDER = 16; - public static final int RIGHT_SHIFT = 17; - public static final int EQUAL_EQUAL = 18; - public static final int UNSIGNED_RIGHT_SHIFT= 19; // last org.eclipse.jdt.internal.compiler.ast.OperatorExpression - - public static final int NOT_EQUAL = 20; - public static final int EQUAL = 21; - /** others */ - public static final int QUESTIONCOLON = 22; - public static final int INSTANCEOF = 23; - /** postfix */ - public static final int PLUS_PLUS = 24; - public static final int MINUS_MINUS = 25; -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java deleted file mode 100644 index 96adb6e..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/PackageVisibilityStatement.java +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PlainPackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; -import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; - -public abstract class PackageVisibilityStatement extends ModuleStatement { - public ImportReference pkgRef; - public ModuleReference[] targets; - public char[] pkgName; - public PlainPackageBinding resolvedPackage; - - public PackageVisibilityStatement(ImportReference pkgRef, ModuleReference[] targets) { - this.pkgRef = pkgRef; - this.pkgName = CharOperation.concatWith(this.pkgRef.tokens, '.'); - this.targets = targets; - } - public boolean isQualified() { - return this.targets != null && this.targets.length > 0; - } - - public ModuleReference[] getTargetedModules() { - return this.targets; - } - - public boolean resolve(Scope scope) { - boolean errorsExist = resolvePackageReference(scope) == null; - if (this.isQualified()) { - HashtableOfObject modules = new HashtableOfObject(this.targets.length); - for (int i = 0; i < this.targets.length; i++) { - ModuleReference ref = this.targets[i]; - // targets will be resolved later (during ModuleDeclaration.resolveModuleDirectives()) - if (modules.containsKey(ref.moduleName)) { - scope.problemReporter().duplicateModuleReference(IProblem.DuplicateModuleRef, ref); - errorsExist = true; - } else { - modules.put(ref.moduleName, ref); - } - } - } - return !errorsExist; - } - public int computeSeverity(int problemId) { - return ProblemSeverities.Error; - } - protected PlainPackageBinding resolvePackageReference(Scope scope) { - if (this.resolvedPackage != null) - return this.resolvedPackage; - ModuleDeclaration exportingModule = scope.compilationUnitScope().referenceContext.moduleDeclaration; - ModuleBinding src = exportingModule.binding; - this.resolvedPackage = src != null ? src.getOrCreateDeclaredPackage(this.pkgRef.tokens) : null; - return this.resolvedPackage; - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - this.pkgRef.print(indent, output); - if (this.isQualified()) { - output.append(" to "); //$NON-NLS-1$ - for (int i = 0; i < this.targets.length; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.targets[i].print(0, output); - } - } - return output; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java deleted file mode 100644 index 55772cf..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java +++ /dev/null @@ -1,558 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 342671 - ClassCastException: org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding cannot be cast to org.eclipse.jdt.internal.compiler.lookup.ArrayBinding - * bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Bug 416181 - [1.8][compiler][null] Invalid assignment is not rejected by the compiler - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - * Bug 434600 - Incorrect null analysis error reporting on type parameters - * Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" - * Bug 456508 - Unexpected RHS PolyTypeBinding for: - * Bug 466713 - Null Annotations: NullPointerException using as Type Param - * Andy Clement - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -/** - * Syntactic representation of a reference to a generic type. - * Note that it might also have a dimension. - */ -public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeReference { - - public TypeReference[][] typeArguments; - ReferenceBinding[] typesPerToken; - - public ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, long[] positions) { - - super(tokens, dim, positions); - this.typeArguments = typeArguments; - annotationSearch: for (int i = 0, max = typeArguments.length; i < max; i++) { - TypeReference[] typeArgumentsOnTypeComponent = typeArguments[i]; - if (typeArgumentsOnTypeComponent != null) { - for (int j = 0, max2 = typeArgumentsOnTypeComponent.length; j < max2; j++) { - if ((typeArgumentsOnTypeComponent[j].bits & ASTNode.HasTypeAnnotations) != 0) { - this.bits |= ASTNode.HasTypeAnnotations; - break annotationSearch; - } - } - } - } - } - public ParameterizedQualifiedTypeReference(char[][] tokens, TypeReference[][] typeArguments, int dim, Annotation[][] annotationsOnDimensions, long[] positions) { - this(tokens, typeArguments, dim, positions); - setAnnotationsOnDimensions(annotationsOnDimensions); - if (annotationsOnDimensions != null) { - this.bits |= ASTNode.HasTypeAnnotations; - } - } - @Override - public void checkBounds(Scope scope) { - if (this.resolvedType == null || !this.resolvedType.isValidBinding()) return; - - checkBounds( - (ReferenceBinding) this.resolvedType.leafComponentType(), - scope, - this.typeArguments.length - 1); - } - public void checkBounds(ReferenceBinding type, Scope scope, int index) { - // recurse on enclosing type if any, and assuming explictly part of the reference (index>0) - if (index > 0) { - ReferenceBinding enclosingType = this.typesPerToken[index-1]; - if (enclosingType != null) - checkBounds(enclosingType, scope, index - 1); - } - if (type.isParameterizedTypeWithActualArguments()) { - ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) type; - ReferenceBinding currentType = parameterizedType.genericType(); - TypeVariableBinding[] typeVariables = currentType.typeVariables(); - if (typeVariables != null) { // argTypes may be null in error cases - parameterizedType.boundCheck(scope, this.typeArguments[index]); - } - } - } - @Override - public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { - int totalDimensions = this.dimensions() + additionalDimensions; - Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations); - ParameterizedQualifiedTypeReference pqtr = new ParameterizedQualifiedTypeReference(this.tokens, this.typeArguments, totalDimensions, allAnnotations, this.sourcePositions); - pqtr.annotations = this.annotations; - pqtr.bits |= (this.bits & ASTNode.HasTypeAnnotations); - if (!isVarargs) - pqtr.extendedDimensions = additionalDimensions; - return pqtr; - } - @Override - public boolean isParameterizedTypeReference() { - return true; - } - - @Override - public boolean hasNullTypeAnnotation(AnnotationPosition position) { - if (super.hasNullTypeAnnotation(position)) - return true; - if (position == AnnotationPosition.ANY) { - if (this.resolvedType != null && !this.resolvedType.hasNullTypeAnnotations()) - return false; // shortcut - if (this.typeArguments != null) { - for (int i = 0; i < this.typeArguments.length; i++) { - TypeReference[] arguments = this.typeArguments[i]; - if (arguments != null) { - for (int j = 0; j < arguments.length; j++) { - if (arguments[j].hasNullTypeAnnotation(position)) - return true; - } - } - } - } - } - return false; - } - - /** - * @return char[][] - */ - @Override - public char [][] getParameterizedTypeName(){ - int length = this.tokens.length; - char[][] qParamName = new char[length][]; - for (int i = 0; i < length; i++) { - TypeReference[] arguments = this.typeArguments[i]; - if (arguments == null) { - qParamName[i] = this.tokens[i]; - } else { - StringBuilder buffer = new StringBuilder(5); - buffer.append(this.tokens[i]); - buffer.append('<'); - for (int j = 0, argLength =arguments.length; j < argLength; j++) { - if (j > 0) buffer.append(','); - buffer.append(CharOperation.concatWith(arguments[j].getParameterizedTypeName(), '.')); - } - buffer.append('>'); - int nameLength = buffer.length(); - qParamName[i] = new char[nameLength]; - buffer.getChars(0, nameLength, qParamName[i], 0); - } - } - int dim = this.dimensions; - if (dim > 0) { - char[] dimChars = new char[dim*2]; - for (int i = 0; i < dim; i++) { - int index = i*2; - dimChars[index] = '['; - dimChars[index+1] = ']'; - } - qParamName[length-1] = CharOperation.concat(qParamName[length-1], dimChars); - } - return qParamName; - } - - @Override - public TypeReference[][] getTypeArguments() { - return this.typeArguments; - } - - @Override - protected TypeBinding getTypeBinding(Scope scope) { - return null; // not supported here - combined with resolveType(...) - } - - /* - * No need to check for reference to raw type per construction - */ - private TypeBinding internalResolveType(Scope scope, boolean checkBounds, int location) { - // handle the error here - this.constant = Constant.NotAConstant; - if ((this.bits & ASTNode.DidResolve) != 0) { // is a shared type reference which was already resolved - if (this.resolvedType != null) { // is a shared type reference which was already resolved - if (this.resolvedType.isValidBinding()) { - return this.resolvedType; - } else { - switch (this.resolvedType.problemId()) { - case ProblemReasons.NotFound : - case ProblemReasons.NotVisible : - case ProblemReasons.InheritedNameHidesEnclosingName : - TypeBinding type = this.resolvedType.closestMatch(); - return type; - default : - return null; - } - } - } - } - this.bits |= ASTNode.DidResolve; - TypeBinding type = internalResolveLeafType(scope, checkBounds); - createArrayType(scope); - resolveAnnotations(scope, location); - if(this.dimensions > 0) { - this.resolvedType = ArrayTypeReference.maybeMarkArrayContentsNonNull(scope, this.resolvedType, this.sourceStart, this.dimensions, null); - } - - if (this.typeArguments != null) - // relevant null annotations are on the inner most type: - checkIllegalNullAnnotations(scope, this.typeArguments[this.typeArguments.length-1]); - return type == null ? type : this.resolvedType; - } - private TypeBinding internalResolveLeafType(Scope scope, boolean checkBounds) { - boolean isClassScope = scope.kind == Scope.CLASS_SCOPE; - Binding binding = scope.getPackage(this.tokens); - if (binding != null && !binding.isValidBinding()) { - this.resolvedType = (ReferenceBinding) binding; - reportInvalidType(scope); - // be resilient, still attempt resolving arguments - for (int i = 0, max = this.tokens.length; i < max; i++) { - TypeReference[] args = this.typeArguments[i]; - if (args != null) { - int argLength = args.length; - for (int j = 0; j < argLength; j++) { - TypeReference typeArgument = args[j]; - if (isClassScope) { - typeArgument.resolveType((ClassScope) scope); - } else { - typeArgument.resolveType((BlockScope) scope, checkBounds); - } - } - } - } - return null; - } - - PackageBinding packageBinding = binding == null ? null : (PackageBinding) binding; - rejectAnnotationsOnPackageQualifiers(scope, packageBinding); - - boolean typeIsConsistent = true; - ReferenceBinding qualifyingType = null; - int max = this.tokens.length; - this.typesPerToken = new ReferenceBinding[max]; - for (int i = packageBinding == null ? 0 : packageBinding.compoundName.length; i < max; i++) { - findNextTypeBinding(i, scope, packageBinding); - if (!(this.resolvedType.isValidBinding())) { - reportInvalidType(scope); - // be resilient, still attempt resolving arguments - for (int j = i; j < max; j++) { - TypeReference[] args = this.typeArguments[j]; - if (args != null) { - int argLength = args.length; - for (int k = 0; k < argLength; k++) { - TypeReference typeArgument = args[k]; - if (isClassScope) { - typeArgument.resolveType((ClassScope) scope); - } else { - typeArgument.resolveType((BlockScope) scope); - } - } - } - } - return null; - } - ReferenceBinding currentType = (ReferenceBinding) this.resolvedType; - if (qualifyingType == null) { - qualifyingType = currentType.enclosingType(); // if member type - if (qualifyingType != null && currentType.hasEnclosingInstanceContext()) { - qualifyingType = scope.environment().convertToParameterizedType(qualifyingType); - } - } else { - if (this.annotations != null) - rejectAnnotationsOnStaticMemberQualififer(scope, currentType, this.annotations[i-1]); - if (typeIsConsistent && currentType.isStatic() - && (qualifyingType.isParameterizedTypeWithActualArguments() || qualifyingType.isGenericType())) { - scope.problemReporter().staticMemberOfParameterizedType(this, currentType, qualifyingType, i); - typeIsConsistent = false; - qualifyingType = qualifyingType.actualType(); // avoid raw/parameterized enclosing of static member - } - ReferenceBinding enclosingType = currentType.enclosingType(); - if (enclosingType != null && TypeBinding.notEquals(enclosingType.erasure(), qualifyingType.erasure())) { // qualifier != declaring/enclosing - qualifyingType = enclosingType; // inherited member type, leave it associated with its enclosing rather than subtype - } - } - - // check generic and arity - TypeReference[] args = this.typeArguments[i]; - if (args != null) { - TypeReference keep = null; - if (isClassScope) { - keep = ((ClassScope) scope).superTypeReference; - ((ClassScope) scope).superTypeReference = null; - } - int argLength = args.length; - boolean isDiamond = argLength == 0 && (i == (max -1)) && ((this.bits & ASTNode.IsDiamond) != 0); - TypeBinding[] argTypes = new TypeBinding[argLength]; - boolean argHasError = false; - ReferenceBinding currentOriginal = (ReferenceBinding)currentType.original(); - for (int j = 0; j < argLength; j++) { - TypeReference arg = args[j]; - TypeBinding argType = isClassScope - ? arg.resolveTypeArgument((ClassScope) scope, currentOriginal, j) - : arg.resolveTypeArgument((BlockScope) scope, currentOriginal, j); - if (argType == null) { - argHasError = true; - } else { - argTypes[j] = argType; - } - } - if (argHasError) { - return null; - } - if (isClassScope) { - ((ClassScope) scope).superTypeReference = keep; - if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this)) - return null; - } - - TypeVariableBinding[] typeVariables = currentOriginal.typeVariables(); - if (typeVariables == Binding.NO_TYPE_VARIABLES) { // check generic - if (scope.compilerOptions().originalSourceLevel >= ClassFileConstants.JDK1_5) { // below 1.5, already reported as syntax error - scope.problemReporter().nonGenericTypeCannotBeParameterized(i, this, currentType, argTypes); - return null; - } - this.resolvedType = (qualifyingType != null && qualifyingType.isParameterizedType()) - ? scope.environment().createParameterizedType(currentOriginal, null, qualifyingType) - : currentType; - return this.resolvedType; - } else if (argLength != typeVariables.length) { - if (!isDiamond) { // check arity - scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes, i); - return null; - } - } - // check parameterizing (non-)static member type of raw type - if (typeIsConsistent) { - if (!currentType.hasEnclosingInstanceContext()) { - if (qualifyingType != null && qualifyingType.isRawType()) - this.typesPerToken[i-1] = qualifyingType = qualifyingType.actualType(); // revert rawification of enclosing, since its generics are inaccessible - } else { - ReferenceBinding actualEnclosing = currentType.enclosingType(); - if (actualEnclosing != null && actualEnclosing.isRawType()) { - scope.problemReporter().rawMemberTypeCannotBeParameterized( - this, scope.environment().createRawType(currentOriginal, actualEnclosing), argTypes); - typeIsConsistent = false; - } - } - } - ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType(currentOriginal, argTypes, qualifyingType); - // check argument type compatibility for non <> cases - <> case needs no bounds check, we will scream foul if needed during inference. - if (!isDiamond) { - if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution - parameterizedType.boundCheck(scope, args); - else - scope.deferBoundCheck(this); - } else { - parameterizedType.arguments = ParameterizedSingleTypeReference.DIAMOND_TYPE_ARGUMENTS; - } - qualifyingType = parameterizedType; - } else { - ReferenceBinding currentOriginal = (ReferenceBinding)currentType.original(); - if (isClassScope) - if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this)) - return null; - if (currentOriginal.isGenericType()) { - if (typeIsConsistent && qualifyingType != null && qualifyingType.isParameterizedType() && currentOriginal.hasEnclosingInstanceContext()) { - scope.problemReporter().parameterizedMemberTypeMissingArguments(this, scope.environment().createParameterizedType(currentOriginal, null, qualifyingType), i); - typeIsConsistent = false; - } - qualifyingType = scope.environment().createRawType(currentOriginal, qualifyingType); // raw type - } else { - qualifyingType = scope.environment().maybeCreateParameterizedType(currentOriginal, qualifyingType); - } - } - if (isTypeUseDeprecated(qualifyingType, scope)) - reportDeprecatedType(qualifyingType, scope, i); - this.resolvedType = qualifyingType; - this.typesPerToken[i] = qualifyingType; - recordResolution(scope.environment(), this.resolvedType); - } - return this.resolvedType; - } - private void createArrayType(Scope scope) { - if (this.dimensions > 0) { - if (this.dimensions > 255) - scope.problemReporter().tooManyDimensions(this); - this.resolvedType = scope.createArrayType(this.resolvedType, this.dimensions); - } - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - int length = this.tokens.length; - for (int i = 0; i < length - 1; i++) { - if (this.annotations != null && this.annotations[i] != null) { - printAnnotations(this.annotations[i], output); - output.append(' '); - } - output.append(this.tokens[i]); - TypeReference[] typeArgument = this.typeArguments[i]; - if (typeArgument != null) { - output.append('<'); - int typeArgumentLength = typeArgument.length; - if (typeArgumentLength > 0) { - int max = typeArgumentLength - 1; - for (int j = 0; j < max; j++) { - typeArgument[j].print(0, output); - output.append(", ");//$NON-NLS-1$ - } - typeArgument[max].print(0, output); - } - output.append('>'); - } - output.append('.'); - } - if (this.annotations != null && this.annotations[length - 1] != null) { - output.append(" "); //$NON-NLS-1$ - printAnnotations(this.annotations[length - 1], output); - output.append(' '); - } - output.append(this.tokens[length - 1]); - TypeReference[] typeArgument = this.typeArguments[length - 1]; - if (typeArgument != null) { - output.append('<'); - int typeArgumentLength = typeArgument.length; - if (typeArgumentLength > 0) { - int max = typeArgumentLength - 1; - for (int j = 0; j < max; j++) { - typeArgument[j].print(0, output); - output.append(", ");//$NON-NLS-1$ - } - typeArgument[max].print(0, output); - } - output.append('>'); - } - Annotation [][] annotationsOnDimensions = this.getAnnotationsOnDimensions(); - if ((this.bits & IsVarArgs) != 0) { - for (int i= 0 ; i < this.dimensions - 1; i++) { - if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) { - output.append(" "); //$NON-NLS-1$ - printAnnotations(annotationsOnDimensions[i], output); - output.append(" "); //$NON-NLS-1$ - } - output.append("[]"); //$NON-NLS-1$ - } - if (annotationsOnDimensions != null && annotationsOnDimensions[this.dimensions - 1] != null) { - output.append(" "); //$NON-NLS-1$ - printAnnotations(annotationsOnDimensions[this.dimensions - 1], output); - output.append(" "); //$NON-NLS-1$ - } - output.append("..."); //$NON-NLS-1$ - } else { - for (int i= 0 ; i < this.dimensions; i++) { - if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) { - output.append(" "); //$NON-NLS-1$ - printAnnotations(annotationsOnDimensions[i], output); - output.append(" "); //$NON-NLS-1$ - } - output.append("[]"); //$NON-NLS-1$ - } - } - return output; - } - - @Override - public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) { - return internalResolveType(scope, checkBounds, location); - } - @Override - public TypeBinding resolveType(ClassScope scope, int location) { - return internalResolveType(scope, false, location); - } - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLevels = this.annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - int annotationsLength = this.annotations[i] == null ? 0 : this.annotations[i].length; - for (int j = 0; j < annotationsLength; j++) - this.annotations[i][j].traverse(visitor, scope); - } - } - Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true); - if (annotationsOnDimensions != null) { - for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = annotationsOnDimensions[i]; - for (int j = 0, max2 = annotations2 == null ? 0 : annotations2.length; j < max2; j++) { - Annotation annotation = annotations2[j]; - annotation.traverse(visitor, scope); - } - } - } - for (int i = 0, max = this.typeArguments.length; i < max; i++) { - if (this.typeArguments[i] != null) { - for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) { - this.typeArguments[i][j].traverse(visitor, scope); - } - } - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLevels = this.annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - int annotationsLength = this.annotations[i] == null ? 0 : this.annotations[i].length; - for (int j = 0; j < annotationsLength; j++) - this.annotations[i][j].traverse(visitor, scope); - } - } - Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true); - if (annotationsOnDimensions != null) { - for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = annotationsOnDimensions[i]; - for (int j = 0, max2 = annotations2 == null ? 0 : annotations2.length; j < max2; j++) { - Annotation annotation = annotations2[j]; - annotation.traverse(visitor, scope); - } - } - } - for (int i = 0, max = this.typeArguments.length; i < max; i++) { - if (this.typeArguments[i] != null) { - for (int j = 0, max2 = this.typeArguments[i].length; j < max2; j++) { - this.typeArguments[i][j].traverse(visitor, scope); - } - } - } - } - visitor.endVisit(this, scope); - } - - @Override - public void updateWithAnnotations(Scope scope, int location) { - int lastToken = this.tokens.length - 1; - TypeBinding updatedLeaf; - if (this.typesPerToken != null && this.typesPerToken[lastToken] != null) { - for (int i = 0; i <= lastToken; i++) { - this.typesPerToken[i] = (ReferenceBinding) updateParameterizedTypeWithAnnotations(scope, this.typesPerToken[i], this.typeArguments[i]); - } - updatedLeaf = this.typesPerToken[lastToken]; - } else { - updatedLeaf = updateParameterizedTypeWithAnnotations(scope, this.resolvedType, this.typeArguments[lastToken]); - } - if (updatedLeaf != this.resolvedType.leafComponentType()) { //$IDENTITY-COMPARISON$ - if (this.dimensions > 0 && this.dimensions <= 255) { - this.resolvedType = scope.createArrayType(updatedLeaf, this.dimensions); - } else { - this.resolvedType = updatedLeaf; - } - } - resolveAnnotations(scope, location); // see comment in super TypeReference.updateWithAnnotations() - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java deleted file mode 100644 index dc9ae7c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java +++ /dev/null @@ -1,462 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 342671 - ClassCastException: org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding cannot be cast to org.eclipse.jdt.internal.compiler.lookup.ArrayBinding - * Bug 420894 - ClassCastException in DefaultBindingResolver.resolveType(Type) - * bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - * Bug 434600 - Incorrect null analysis error reporting on type parameters - * Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" - * Bug 456508 - Unexpected RHS PolyTypeBinding for: - * Bug 466713 - Null Annotations: NullPointerException using as Type Param - * Andy Clement - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -/** - * Syntactic representation of a reference to a generic type. - * Note that it might also have a dimension. - */ -public class ParameterizedSingleTypeReference extends ArrayTypeReference { - - public static final TypeBinding[] DIAMOND_TYPE_ARGUMENTS = new TypeBinding[0]; - - public TypeReference[] typeArguments; - - public ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, long pos){ - super(name, dim, pos); - this.originalSourceEnd = this.sourceEnd; - this.typeArguments = typeArguments; - for (int i = 0, max = typeArguments.length; i < max; i++) { - if ((typeArguments[i].bits & ASTNode.HasTypeAnnotations) != 0) { - this.bits |= ASTNode.HasTypeAnnotations; - break; - } - } - } - public ParameterizedSingleTypeReference(char[] name, TypeReference[] typeArguments, int dim, Annotation[][] annotationsOnDimensions, long pos) { - this(name, typeArguments, dim, pos); - setAnnotationsOnDimensions(annotationsOnDimensions); - if (annotationsOnDimensions != null) { - this.bits |= ASTNode.HasTypeAnnotations; - } - } - @Override - public void checkBounds(Scope scope) { - if (this.resolvedType == null) return; - - if (this.resolvedType.leafComponentType() instanceof ParameterizedTypeBinding) { - ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) this.resolvedType.leafComponentType(); - TypeBinding[] argTypes = parameterizedType.arguments; - if (argTypes != null) { // may be null in error cases - parameterizedType.boundCheck(scope, this.typeArguments); - } - } - } - - @Override - public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation [][] additionalAnnotations, boolean isVarargs) { - int totalDimensions = this.dimensions() + additionalDimensions; - Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations); - ParameterizedSingleTypeReference parameterizedSingleTypeReference = new ParameterizedSingleTypeReference(this.token, this.typeArguments, totalDimensions, allAnnotations, (((long) this.sourceStart) << 32) + this.sourceEnd); - parameterizedSingleTypeReference.annotations = this.annotations; - parameterizedSingleTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations); - if (!isVarargs) - parameterizedSingleTypeReference.extendedDimensions = additionalDimensions; - return parameterizedSingleTypeReference; - } - - /** - * @return char[][] - */ - @Override - public char [][] getParameterizedTypeName(){ - StringBuilder buffer = new StringBuilder(5); - buffer.append(this.token).append('<'); - for (int i = 0, length = this.typeArguments.length; i < length; i++) { - if (i > 0) buffer.append(','); - buffer.append(CharOperation.concatWith(this.typeArguments[i].getParameterizedTypeName(), '.')); - } - buffer.append('>'); - int nameLength = buffer.length(); - char[] name = new char[nameLength]; - buffer.getChars(0, nameLength, name, 0); - int dim = this.dimensions; - if (dim > 0) { - char[] dimChars = new char[dim*2]; - for (int i = 0; i < dim; i++) { - int index = i*2; - dimChars[index] = '['; - dimChars[index+1] = ']'; - } - name = CharOperation.concat(name, dimChars); - } - return new char[][]{ name }; - } - - @Override - public TypeReference[][] getTypeArguments() { - return new TypeReference[][] { this.typeArguments }; - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope) - */ - @Override - protected TypeBinding getTypeBinding(Scope scope) { - return null; // not supported here - combined with resolveType(...) - } - - @Override - public boolean isParameterizedTypeReference() { - return true; - } - - @Override - public boolean hasNullTypeAnnotation(AnnotationPosition position) { - if (super.hasNullTypeAnnotation(position)) - return true; - if (position == AnnotationPosition.ANY) { - if (this.resolvedType != null && !this.resolvedType.hasNullTypeAnnotations()) - return false; // shortcut - if (this.typeArguments != null) { - for (int i = 0; i < this.typeArguments.length; i++) { - if (this.typeArguments[i].hasNullTypeAnnotation(position)) - return true; - } - } - } - return false; - } - - /* - * No need to check for reference to raw type per construction - */ - private TypeBinding internalResolveType(Scope scope, ReferenceBinding enclosingType, boolean checkBounds, int location) { - // handle the error here - this.constant = Constant.NotAConstant; - if ((this.bits & ASTNode.DidResolve) != 0) { // is a shared type reference which was already resolved - if (this.resolvedType != null) { // is a shared type reference which was already resolved - if (this.resolvedType.isValidBinding()) { - return this.resolvedType; - } else { - switch (this.resolvedType.problemId()) { - case ProblemReasons.NotFound : - case ProblemReasons.NotVisible : - case ProblemReasons.InheritedNameHidesEnclosingName : - TypeBinding type = this.resolvedType.closestMatch(); - return type; - default : - return null; - } - } - } - } - this.bits |= ASTNode.DidResolve; - TypeBinding type = internalResolveLeafType(scope, enclosingType, checkBounds); - - // handle three different outcomes: - if (type == null) { - this.resolvedType = createArrayType(scope, this.resolvedType); - resolveAnnotations(scope, 0); // no defaultNullness for buggy type - return null; // (1) no useful type, but still captured dimensions into this.resolvedType - } else { - type = createArrayType(scope, type); - if (!this.resolvedType.isValidBinding() && this.resolvedType.dimensions() == type.dimensions()) { - resolveAnnotations(scope, 0); // no defaultNullness for buggy type - return type; // (2) found some error, but could recover useful type (like closestMatch) - } else { - this.resolvedType = type; // (3) no complaint, keep fully resolved type (incl. dimensions) - resolveAnnotations(scope, location); - if(this.dimensions > 0) { - this.resolvedType = ArrayTypeReference.maybeMarkArrayContentsNonNull(scope, this.resolvedType, this.sourceStart, this.dimensions, - leafType -> this.leafComponentTypeWithoutDefaultNullness = leafType); - } - return this.resolvedType; // pick up any annotated type. - } - } - } - private TypeBinding internalResolveLeafType(Scope scope, ReferenceBinding enclosingType, boolean checkBounds) { - ReferenceBinding currentType; - if (enclosingType == null) { - this.resolvedType = scope.getType(this.token); - if (this.resolvedType.isValidBinding()) { - currentType = (ReferenceBinding) this.resolvedType; - } else { - reportInvalidType(scope); - switch (this.resolvedType.problemId()) { - case ProblemReasons.NotFound : - case ProblemReasons.NotVisible : - case ProblemReasons.InheritedNameHidesEnclosingName : - TypeBinding type = this.resolvedType.closestMatch(); - if (type instanceof ReferenceBinding) { - currentType = (ReferenceBinding) type; - break; - } - //$FALL-THROUGH$ - unable to complete type binding, but still resolve type arguments - default : - boolean isClassScope = scope.kind == Scope.CLASS_SCOPE; - int argLength = this.typeArguments.length; - for (int i = 0; i < argLength; i++) { - TypeReference typeArgument = this.typeArguments[i]; - if (isClassScope) { - typeArgument.resolveType((ClassScope) scope); - } else { - typeArgument.resolveType((BlockScope) scope, checkBounds); - } - } - return null; - } - // be resilient, still attempt resolving arguments - } - enclosingType = currentType.enclosingType(); // if member type - if (enclosingType != null && currentType.hasEnclosingInstanceContext()) { - enclosingType = scope.environment().convertToParameterizedType(enclosingType); - } - } else { // resolving member type (relatively to enclosingType) - this.resolvedType = currentType = scope.getMemberType(this.token, enclosingType); - if (!this.resolvedType.isValidBinding()) { - scope.problemReporter().invalidEnclosingType(this, currentType, enclosingType); - return null; - } - if (isTypeUseDeprecated(currentType, scope)) - scope.problemReporter().deprecatedType(currentType, this); - ReferenceBinding currentEnclosing = currentType.enclosingType(); - if (currentEnclosing != null && TypeBinding.notEquals(currentEnclosing.erasure(), enclosingType.erasure())) { - enclosingType = currentEnclosing; // inherited member type, leave it associated with its enclosing rather than subtype - } - } - - // check generic and arity - boolean isClassScope = scope.kind == Scope.CLASS_SCOPE; - TypeReference keep = null; - if (isClassScope) { - keep = ((ClassScope) scope).superTypeReference; - ((ClassScope) scope).superTypeReference = null; - } - final boolean isDiamond = (this.bits & ASTNode.IsDiamond) != 0; - int argLength = this.typeArguments.length; - TypeBinding[] argTypes = new TypeBinding[argLength]; - boolean argHasError = false; - ReferenceBinding currentOriginal = (ReferenceBinding)currentType.original(); - for (int i = 0; i < argLength; i++) { - TypeReference typeArgument = this.typeArguments[i]; - TypeBinding argType = isClassScope - ? typeArgument.resolveTypeArgument((ClassScope) scope, currentOriginal, i) - : typeArgument.resolveTypeArgument((BlockScope) scope, currentOriginal, i); - this.bits |= (typeArgument.bits & ASTNode.HasTypeAnnotations); - if (argType == null) { - argHasError = true; - } else { - argTypes[i] = argType; - } - } - if (argHasError) { - return null; - } - if (isClassScope) { - ((ClassScope) scope).superTypeReference = keep; - if (((ClassScope) scope).detectHierarchyCycle(currentOriginal, this)) - return null; - } - - TypeVariableBinding[] typeVariables = currentOriginal.typeVariables(); - if (typeVariables == Binding.NO_TYPE_VARIABLES) { // non generic invoked with arguments - boolean isCompliant15 = scope.compilerOptions().originalSourceLevel >= ClassFileConstants.JDK1_5; - if ((currentOriginal.tagBits & TagBits.HasMissingType) == 0) { - if (isCompliant15) { // below 1.5, already reported as syntax error - this.resolvedType = currentType; - scope.problemReporter().nonGenericTypeCannotBeParameterized(0, this, currentType, argTypes); - return null; - } - } - // resilience do not rebuild a parameterized type unless compliance is allowing it - if (!isCompliant15) { - if (!this.resolvedType.isValidBinding()) - return currentType; - return this.resolvedType = currentType; - } - // if missing generic type, and compliance >= 1.5, then will rebuild a parameterized binding - } else if (argLength != typeVariables.length) { - if (!isDiamond) { // check arity, IsDiamond never set for 1.6- - scope.problemReporter().incorrectArityForParameterizedType(this, currentType, argTypes); - return null; - } - } else if (!currentType.isStatic()) { - ReferenceBinding actualEnclosing = currentType.enclosingType(); - if (actualEnclosing != null && actualEnclosing.isRawType()){ - scope.problemReporter().rawMemberTypeCannotBeParameterized( - this, scope.environment().createRawType(currentOriginal, actualEnclosing), argTypes); - return null; - } - } - - ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType(currentOriginal, argTypes, enclosingType); - // check argument type compatibility for non <> cases - <> case needs no bounds check, we will scream foul if needed during inference. - if (!isDiamond) { - if (checkBounds) // otherwise will do it in Scope.connectTypeVariables() or generic method resolution - parameterizedType.boundCheck(scope, this.typeArguments); - else - scope.deferBoundCheck(this); - } else { - parameterizedType.arguments = DIAMOND_TYPE_ARGUMENTS; - } - if (isTypeUseDeprecated(parameterizedType, scope)) - reportDeprecatedType(parameterizedType, scope); - - checkIllegalNullAnnotations(scope, this.typeArguments); - - if (!this.resolvedType.isValidBinding()) { - return parameterizedType; - } - return this.resolvedType = parameterizedType; - } - private TypeBinding createArrayType(Scope scope, TypeBinding type) { - if (this.dimensions > 0) { - if (this.dimensions > 255) - scope.problemReporter().tooManyDimensions(this); - return scope.createArrayType(type, this.dimensions); - } - return type; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output){ - if (this.annotations != null && this.annotations[0] != null) { - printAnnotations(this.annotations[0], output); - output.append(' '); - } - output.append(this.token); - output.append("<"); //$NON-NLS-1$ - int length = this.typeArguments.length; - if (length > 0) { - int max = length - 1; - for (int i= 0; i < max; i++) { - this.typeArguments[i].print(0, output); - output.append(", ");//$NON-NLS-1$ - } - this.typeArguments[max].print(0, output); - } - output.append(">"); //$NON-NLS-1$ - Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(); - if ((this.bits & IsVarArgs) != 0) { - for (int i= 0 ; i < this.dimensions - 1; i++) { - if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) { - output.append(" "); //$NON-NLS-1$ - printAnnotations(annotationsOnDimensions[i], output); - output.append(" "); //$NON-NLS-1$ - } - output.append("[]"); //$NON-NLS-1$ - } - if (annotationsOnDimensions != null && annotationsOnDimensions[this.dimensions - 1] != null) { - output.append(" "); //$NON-NLS-1$ - printAnnotations(annotationsOnDimensions[this.dimensions - 1], output); - output.append(" "); //$NON-NLS-1$ - } - output.append("..."); //$NON-NLS-1$ - } else { - for (int i= 0 ; i < this.dimensions; i++) { - if (annotationsOnDimensions != null && annotationsOnDimensions[i] != null) { - output.append(" "); //$NON-NLS-1$ - printAnnotations(annotationsOnDimensions[i], output); - output.append(" "); //$NON-NLS-1$ - } - output.append("[]"); //$NON-NLS-1$ - } - } - return output; - } - - @Override - public void updateWithAnnotations(Scope scope, int location) { - this.resolvedType = updateParameterizedTypeWithAnnotations(scope, this.resolvedType, this.typeArguments); - resolveAnnotations(scope, location); // see comment in super TypeReference.updateWithAnnotations() - } - - @Override - public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) { - return internalResolveType(scope, null, checkBounds, location); - } - - @Override - public TypeBinding resolveType(ClassScope scope, int location) { - return internalResolveType(scope, null, false /*no bounds check in classScope*/, location); - } - - @Override - public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) { - return internalResolveType(scope, enclosingType, true/*check bounds*/, 0); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - Annotation [] typeAnnotations = this.annotations[0]; - for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) { - typeAnnotations[i].traverse(visitor, scope); - } - } - Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true); - if (annotationsOnDimensions != null) { - for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = annotationsOnDimensions[i]; - if (annotations2 != null) { - for (int j = 0, max2 = annotations2.length; j < max2; j++) { - Annotation annotation = annotations2[j]; - annotation.traverse(visitor, scope); - } - } - } - } - for (int i = 0, max = this.typeArguments.length; i < max; i++) { - this.typeArguments[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - Annotation [] typeAnnotations = this.annotations[0]; - for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) { - typeAnnotations[i].traverse(visitor, scope); - } - } - Annotation [][] annotationsOnDimensions = getAnnotationsOnDimensions(true); - if (annotationsOnDimensions != null) { - for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotations2 = annotationsOnDimensions[i]; - for (int j = 0, max2 = annotations2.length; j < max2; j++) { - Annotation annotation = annotations2[j]; - annotation.traverse(visitor, scope); - } - } - } - for (int i = 0, max = this.typeArguments.length; i < max; i++) { - this.typeArguments[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Pattern.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Pattern.java deleted file mode 100644 index d5f0657..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Pattern.java +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -public abstract class Pattern extends Expression { - - /* package */ boolean isTotalTypeNode = false; - - private Pattern enclosingPattern; - protected MethodBinding accessorMethod; - /* package */ BranchLabel elseTarget; - /* package */ BranchLabel thenTarget; - - public int index = -1; // index of this in enclosing record pattern, or -1 for top level patterns - - @Override - public boolean containsPatternVariable() { - class PatternVariablesVisitor extends ASTVisitor { - public boolean hasPatternVar = false; - public boolean typeElidedVar = false; - - @Override - public boolean visit(TypePattern typePattern, BlockScope blockScope) { - this.hasPatternVar = typePattern.local != null; - this.typeElidedVar |= typePattern.getType() == null || typePattern.getType().isTypeNameVar(blockScope); - return !(this.hasPatternVar && this.typeElidedVar); - } - } - - PatternVariablesVisitor pvv = new PatternVariablesVisitor(); - this.traverse(pvv, (BlockScope) null); - return pvv.hasPatternVar; - } - - /** - * @return the enclosingPattern - */ - public Pattern getEnclosingPattern() { - return this.enclosingPattern; - } - - /** - * @param enclosingPattern the enclosingPattern to set - */ - public void setEnclosingPattern(RecordPattern enclosingPattern) { - this.enclosingPattern = enclosingPattern; - } - /** - * Implement the rules in the spec under 14.11.1.1 Exhaustive Switch Blocks - * - * @return whether pattern covers the given type or not - */ - public boolean coversType(TypeBinding type) { - return false; - } - public boolean isAlwaysTrue() { - return true; - } - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - setTargets(codeStream); - generateOptimizedBoolean(currentScope, codeStream, this.thenTarget, this.elseTarget); - } - /* package */ void setTargets(CodeStream codeStream) { - if (this.elseTarget == null) - this.elseTarget = new BranchLabel(codeStream); - if (this.thenTarget == null) - this.thenTarget = new BranchLabel(codeStream); - } - public void suspendVariables(CodeStream codeStream, BlockScope scope) { - // nothing by default - } - public void resumeVariables(CodeStream codeStream, BlockScope scope) { - // nothing by default - } - public abstract void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel); - - public TypeReference getType() { - return null; - } - - protected abstract boolean isPatternTypeCompatible(TypeBinding other, BlockScope scope); - - public abstract boolean dominates(Pattern p); - - @Override - public StringBuilder print(int indent, StringBuilder output) { - return this.printExpression(indent, output); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java deleted file mode 100644 index 8fcee0f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/PostfixExpression.java +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class PostfixExpression extends CompoundAssignment { - -public PostfixExpression(Expression lhs, Expression expression, int operator, int pos) { - super(lhs, expression, operator, pos); - this.sourceStart = lhs.sourceStart; - this.sourceEnd = pos; -} -@Override -public boolean checkCastCompatibility() { - return false; -} -/** - * Code generation for PostfixExpression - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - // various scenarii are possible, setting an array reference, - // a field reference, a blank final field reference, a field of an enclosing instance or - // just a local variable. - - int pc = codeStream.position; - ((Reference) this.lhs).generatePostIncrement(currentScope, codeStream, this, valueRequired); - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public String operatorToString() { - switch (this.operator) { - case PLUS : - return "++"; //$NON-NLS-1$ - case MINUS : - return "--"; //$NON-NLS-1$ - } - return "unknown operator"; //$NON-NLS-1$ -} - -@Override -public StringBuilder printExpressionNoParenthesis(int indent, StringBuilder output) { - return this.lhs.printExpression(indent, output).append(' ').append(operatorToString()); -} - -@Override -public boolean restrainUsageToNumericTypes() { - return true; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - - if (visitor.visit(this, scope)) { - this.lhs.traverse(visitor, scope); - } - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java deleted file mode 100644 index 1702d9c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/PrefixExpression.java +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class PrefixExpression extends CompoundAssignment { - -/** - * PrefixExpression constructor comment. - * @param lhs org.eclipse.jdt.internal.compiler.ast.Expression - * @param expression org.eclipse.jdt.internal.compiler.ast.Expression - * @param operator int - */ -public PrefixExpression(Expression lhs, Expression expression, int operator, int pos) { - super(lhs, expression, operator, lhs.sourceEnd); - this.sourceStart = pos; - this.sourceEnd = lhs.sourceEnd; -} -@Override -public boolean checkCastCompatibility() { - return false; -} -@Override -public String operatorToString() { - switch (this.operator) { - case PLUS : - return "++"; //$NON-NLS-1$ - case MINUS : - return "--"; //$NON-NLS-1$ - } - return "unknown operator"; //$NON-NLS-1$ -} - -@Override -public StringBuilder printExpressionNoParenthesis(int indent, StringBuilder output) { - - output.append(operatorToString()).append(' '); - return this.lhs.printExpression(0, output); -} - -@Override -public boolean restrainUsageToNumericTypes() { - return true; -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.lhs.traverse(visitor, scope); - } - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ProvidesStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ProvidesStatement.java deleted file mode 100644 index 6cf87c9..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ProvidesStatement.java +++ /dev/null @@ -1,136 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; - -public class ProvidesStatement extends ModuleStatement { - - public TypeReference serviceInterface; - public TypeReference[] implementations; - - public boolean resolve(BlockScope scope) { - ModuleDeclaration module = scope.referenceCompilationUnit().moduleDeclaration; - ModuleBinding src = module.binding; - TypeBinding infBinding = this.serviceInterface.resolveType(scope); - boolean hasErrors = false; - if (infBinding == null || !infBinding.isValidBinding()) { - return false; - } - if (!(infBinding.isClass() || infBinding.isInterface() || infBinding.isAnnotationType())) { - scope.problemReporter().invalidServiceRef(IProblem.InvalidServiceIntfType, this.serviceInterface); - } - ReferenceBinding intf = (ReferenceBinding) this.serviceInterface.resolvedType; - Set impls = new HashSet<>(); - for (int i = 0; i < this.implementations.length; i++) { - ReferenceBinding impl = (ReferenceBinding) this.implementations[i].resolveType(scope); - if (impl == null || !impl.isValidBinding() || !impl.canBeSeenBy(scope)) { - hasErrors = true; - continue; - } - if (!impls.add(impl)) { - scope.problemReporter().duplicateTypeReference(IProblem.DuplicateServices, this.implementations[i]); - continue; - } - int problemId = ProblemReasons.NoError; - ModuleBinding declaringModule = impl.module(); - - if (declaringModule != src) { - problemId = IProblem.ServiceImplNotDefinedByModule; - } else if (!impl.isClass() && !impl.isInterface()) { - problemId = IProblem.InvalidServiceImplType; - } else if (impl.isNestedType() && !impl.isStatic()) { - problemId = IProblem.NestedServiceImpl; - } else { - MethodBinding provider = impl.getExactMethod(TypeConstants.PROVIDER, Binding.NO_PARAMETERS, scope.compilationUnitScope()); - if (provider != null && (!provider.isValidBinding() || !(provider.isPublic() && provider.isStatic()))) { - provider = null; - } - TypeBinding implType = impl; - if (provider != null) { - implType = provider.returnType; - if (implType instanceof ReferenceBinding && !implType.canBeSeenBy(scope)) { - ReferenceBinding referenceBinding = (ReferenceBinding) implType; - scope.problemReporter().invalidType(this.implementations[i], new ProblemReferenceBinding( - referenceBinding.compoundName, referenceBinding, ProblemReasons.NotVisible)); - hasErrors = true; - } - } else { - if (impl.isAbstract()) { - problemId = IProblem.AbstractServiceImplementation; - } else { - MethodBinding defaultConstructor = impl.getExactConstructor(Binding.NO_PARAMETERS); - if (defaultConstructor == null || !defaultConstructor.isValidBinding()) { - problemId = IProblem.ProviderMethodOrConstructorRequiredForServiceImpl; - } else if (!defaultConstructor.isPublic()) { - problemId = IProblem.ServiceImplDefaultConstructorNotPublic; - } - } - } - if (implType.findSuperTypeOriginatingFrom(intf) == null) { - scope.problemReporter().typeMismatchError(implType, intf, this.implementations[i], null); - hasErrors = true; - } - } - if (problemId != ProblemReasons.NoError) { - scope.problemReporter().invalidServiceRef(problemId, this.implementations[i]); - hasErrors = true; - } - } - return hasErrors; - } - - public List getResolvedImplementations() { - List resolved = new ArrayList<>(); - if (this.implementations != null) { - for (TypeReference implRef : this.implementations) { - TypeBinding one = implRef.resolvedType; - if (one != null) - resolved.add(one); - } - } - return resolved; - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - printIndent(indent, output); - output.append("provides "); //$NON-NLS-1$ - this.serviceInterface.print(0, output); - //output.append(" "); //$NON-NLS-1$ - //printIndent(indent + 1, output); - output.append(" with "); //$NON-NLS-1$ - for (int i = 0; i < this.implementations.length; i++) { - this.implementations[i].print(0, output); - if (i < this.implementations.length - 1) - output.append(", "); //$NON-NLS-1$ - } - output.append(";"); //$NON-NLS-1$ - return output; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java deleted file mode 100644 index 3b1fce6..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java +++ /dev/null @@ -1,714 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * 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 186342 - [compiler][null] Using annotations for null checking - * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK - * bug 370639 - [compiler][resource] restore the default for resource leak warnings - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 388996 - [compiler][resource] Incorrect 'potential resource leak' - * bug 395977 - [compiler][resource] Resource leak warning behavior possibly incorrect for anonymous inner class - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 416267 - NPE in QualifiedAllocationExpression.resolveType - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 424415 - [1.8][compiler] Eventual resolution of ReferenceExpression is not seen to be happening. - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Jesper S Moller - Contributions for - * bug 378674 - "The method can be declared as static" is wrong - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - * Bug 409245 - [1.8][compiler] Type annotations dropped when call is routed through a synthetic bridge method - * Till Brychcy - Contributions for - * bug 413460 - NonNullByDefault is not inherited to Constructors when accessed via Class File - ******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.INVOCATION_CONTEXT; - -import java.util.Arrays; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -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.impl.CompilerOptions; -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.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier; -import org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBindingVisitor; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -/** - * Variation on allocation, where can optionally be specified any of: - * - leading enclosing instance - * - trailing anonymous type - * - generic type arguments for generic constructor invocation - */ -public class QualifiedAllocationExpression extends AllocationExpression { - - //qualification may be on both side - public Expression enclosingInstance; - public TypeDeclaration anonymousType; - - public QualifiedAllocationExpression() { - // for subtypes - } - - public QualifiedAllocationExpression(TypeDeclaration anonymousType) { - this.anonymousType = anonymousType; - anonymousType.allocation = this; - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // analyse the enclosing instance - if (this.enclosingInstance != null) { - flowInfo = this.enclosingInstance.analyseCode(currentScope, flowContext, flowInfo); - } else { - if (this.binding != null && this.binding.declaringClass != null) { - ReferenceBinding superclass = this.binding.declaringClass.superclass(); - if (superclass != null && superclass.isMemberType() && !superclass.isStatic()) { - // creating an anonymous type of a non-static member type without an enclosing instance of parent type - currentScope.tagAsAccessingEnclosingInstanceStateOf(superclass.enclosingType(), false /* type variable access */); - // Reviewed for https://bugs.eclipse.org/bugs/show_bug.cgi?id=378674 : - // The corresponding problem (when called from static) is not produced until during code generation - } - } - - } - - // check captured variables are initialized in current context (26134) - checkCapturedLocalInitializationIfNecessary( - (ReferenceBinding)(this.anonymousType == null - ? this.binding.declaringClass.erasure() - : this.binding.declaringClass.superclass().erasure()), - currentScope, - flowInfo); - - // process arguments - if (this.arguments != null) { - boolean analyseResources = currentScope.compilerOptions().analyseResourceLeaks; - boolean hasResourceWrapperType = analyseResources - && this.resolvedType instanceof ReferenceBinding - && ((ReferenceBinding)this.resolvedType).hasTypeBit(TypeIds.BitWrapperCloseable); - for (int i = 0, count = this.arguments.length; i < count; i++) { - flowInfo = this.arguments[i].analyseCode(currentScope, flowContext, flowInfo); - if (analyseResources && !hasResourceWrapperType) { // allocation of wrapped closeables is analyzed specially - flowInfo = handleResourcePassedToInvocation(currentScope, this.binding, this.arguments[i], i, flowContext, flowInfo); - } - this.arguments[i].checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - } - analyseArguments(currentScope, flowContext, flowInfo, this.binding, this.arguments); - } - - // analyse the anonymous nested type - if (this.anonymousType != null) { - flowInfo = this.anonymousType.analyseCode(currentScope, flowContext, flowInfo); - } - - // record some dependency information for exception types - ReferenceBinding[] thrownExceptions; - if (((thrownExceptions = this.binding.thrownExceptions).length) != 0) { - if ((this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6 - thrownExceptions = currentScope.environment().convertToRawTypes(this.binding.thrownExceptions, true, true); - } - // check exception handling - flowContext.checkExceptionHandlers( - thrownExceptions, - this, - flowInfo.unconditionalCopy(), - currentScope); - } - - // after having analysed exceptions above start tracking newly allocated resource: - if (currentScope.compilerOptions().analyseResourceLeaks && FakedTrackingVariable.isAnyCloseable(this.resolvedType)) { - FakedTrackingVariable.analyseCloseableAllocation(currentScope, flowInfo, flowContext, this); - } - - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - manageSyntheticAccessIfNecessary(currentScope, flowInfo); - - // account for possible exceptions thrown by constructor execution: - flowContext.recordAbruptExit(); - - return flowInfo; - } - - @Override - public Expression enclosingInstance() { - - return this.enclosingInstance; - } - - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - cleanUpInferenceContexts(); - if (!valueRequired) - currentScope.problemReporter().unusedObjectAllocation(this); - int pc = codeStream.position; - MethodBinding codegenBinding = this.binding.original(); - ReferenceBinding allocatedType = codegenBinding.declaringClass; - codeStream.new_(this.type, allocatedType); - boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; - if (valueRequired || isUnboxing) { - codeStream.dup(); - } - // better highlight for allocation: display the type individually - if (this.type != null) { // null for enum constant body - codeStream.recordPositionsFrom(pc, this.type.sourceStart); - } else { - // push enum constant name and ordinal - codeStream.ldc(String.valueOf(this.enumConstant.name)); - codeStream.generateInlinedValue(this.enumConstant.binding.id); - } - // handling innerclass instance allocation - enclosing instance arguments - if (allocatedType.isNestedType()) { - codeStream.generateSyntheticEnclosingInstanceValues( - currentScope, - allocatedType, - enclosingInstance(), - this); - } - // generate the arguments for constructor - generateArguments(this.binding, this.arguments, currentScope, codeStream); - // handling innerclass instance allocation - outer local arguments - if (allocatedType.isNestedType()) { - codeStream.generateSyntheticOuterArgumentValues( - currentScope, - allocatedType, - this); - } - - // invoke constructor - if (this.syntheticAccessor == null) { - codeStream.invoke(Opcodes.OPC_invokespecial, codegenBinding, null /* default declaringClass */, this.typeArguments); - } else { - // synthetic accessor got some extra arguments appended to its signature, which need values - for (int i = 0, - max = this.syntheticAccessor.parameters.length - codegenBinding.parameters.length; - i < max; - i++) { - codeStream.aconst_null(); - } - codeStream.invoke(Opcodes.OPC_invokespecial, this.syntheticAccessor, null /* default declaringClass */, this.typeArguments); - } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else if (isUnboxing) { - // conversion only generated if unboxing - codeStream.generateImplicitConversion(this.implicitConversion); - switch (postConversionType(currentScope).id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - - if (this.anonymousType != null) { - this.anonymousType.generateCode(currentScope, codeStream); - } - } - - @Override - public boolean isSuperAccess() { - - // necessary to lookup super constructor of anonymous type - return this.anonymousType != null; - } - - /* Inner emulation consists in either recording a dependency - * link only, or performing one level of propagation. - * - * Dependency mechanism is used whenever dealing with source target - * types, since by the time we reach them, we might not yet know their - * exact need. - */ - @Override - public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - ReferenceBinding allocatedTypeErasure = (ReferenceBinding) this.binding.declaringClass.erasure(); - - // perform some extra emulation work in case there is some and we are inside a local type only - if (allocatedTypeErasure.isNestedType() - && (currentScope.enclosingSourceType().isLocalType() || currentScope.isLambdaSubscope())) { - - if (allocatedTypeErasure.isLocalType()) { - ((LocalTypeBinding) allocatedTypeErasure).addInnerEmulationDependent(currentScope, this.enclosingInstance != null); - } else { - // locally propagate, since we already now the desired shape for sure - currentScope.propagateInnerEmulation(allocatedTypeErasure, this.enclosingInstance != null); - } - } - } - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - if (this.enclosingInstance != null) - this.enclosingInstance.printExpression(0, output).append('.'); - super.printExpression(0, output); - if (this.anonymousType != null) { - this.anonymousType.print(indent, output); - } - return output; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - // added for code assist...cannot occur with 'normal' code - if (this.anonymousType == null && this.enclosingInstance == null) { - return super.resolveType(scope); - } - TypeBinding result = resolveTypeForQualifiedAllocationExpression(scope); - if (result != null && !result.isPolyType() && this.binding != null) { - final CompilerOptions compilerOptions = scope.compilerOptions(); - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { - ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope); - if (scope.environment().usesNullTypeAnnotations()) { - if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) { - TypeVariableBinding[] typeVariables = this.binding.original().typeVariables(); - for (int i = 0; i < this.typeArguments.length; i++) - this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i); - } - if (this.resolvedType.isValidBinding()) { - this.resolvedType = scope.environment().createNonNullAnnotatedType(this.resolvedType); - } - } - } - if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8 && - this.binding.getTypeAnnotations() != Binding.NO_ANNOTATIONS) { - this.resolvedType = scope.environment().createAnnotatedType(this.resolvedType, this.binding.getTypeAnnotations()); - } - } - return result; - } - - private TypeBinding resolveTypeForQualifiedAllocationExpression(BlockScope scope) { - // Propagate the type checking to the arguments, and checks if the constructor is defined. - // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt - // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt - final boolean isDiamond = this.type != null && (this.type.bits & ASTNode.IsDiamond) != 0; - TypeBinding enclosingInstanceType = null; - TypeBinding receiverType = null; - long sourceLevel = scope.compilerOptions().sourceLevel; - if (this.constant != Constant.NotAConstant) { - this.constant = Constant.NotAConstant; - ReferenceBinding enclosingInstanceReference = null; - boolean hasError = false; - boolean enclosingInstanceContainsCast = false; - - if (this.enclosingInstance != null) { - if (this.enclosingInstance instanceof CastExpression) { - this.enclosingInstance.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - enclosingInstanceContainsCast = true; - } - if ((enclosingInstanceType = this.enclosingInstance.resolveType(scope)) == null){ - hasError = true; - } else if (enclosingInstanceType.isBaseType() || enclosingInstanceType.isArrayType()) { - scope.problemReporter().illegalPrimitiveOrArrayTypeForEnclosingInstance( - enclosingInstanceType, - this.enclosingInstance); - hasError = true; - } else if (this.type instanceof QualifiedTypeReference) { - scope.problemReporter().illegalUsageOfQualifiedTypeReference((QualifiedTypeReference)this.type); - hasError = true; - } else if (!(enclosingInstanceReference = (ReferenceBinding) enclosingInstanceType).canBeSeenBy(scope)) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=317212 - enclosingInstanceType = new ProblemReferenceBinding( - enclosingInstanceReference.compoundName, - enclosingInstanceReference, - ProblemReasons.NotVisible); - scope.problemReporter().invalidType(this.enclosingInstance, enclosingInstanceType); - hasError = true; - } else { - this.resolvedType = receiverType = ((SingleTypeReference) this.type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType); - checkIllegalNullAnnotation(scope, receiverType); - if (receiverType != null && enclosingInstanceContainsCast) { - CastExpression.checkNeedForEnclosingInstanceCast(scope, this.enclosingInstance, enclosingInstanceType, receiverType); - } - } - } else { - if (this.type == null) { - // initialization of an enum constant - receiverType = scope.enclosingSourceType(); - } else { - receiverType = this.type.resolveType(scope, true /* check bounds*/); - checkIllegalNullAnnotation(scope, receiverType); - checkParameterizedAllocation: { - if (receiverType == null || !receiverType.isValidBinding()) break checkParameterizedAllocation; - if (this.type instanceof ParameterizedQualifiedTypeReference) { // disallow new X.Y() - ReferenceBinding currentType = (ReferenceBinding)receiverType; - do { - // isStatic() is answering true for toplevel types - if ((currentType.modifiers & ClassFileConstants.AccStatic) != 0) break checkParameterizedAllocation; - if (currentType.isRawType()) break checkParameterizedAllocation; - } while ((currentType = currentType.enclosingType())!= null); - ParameterizedQualifiedTypeReference qRef = (ParameterizedQualifiedTypeReference) this.type; - for (int i = qRef.typeArguments.length - 2; i >= 0; i--) { - if (qRef.typeArguments[i] != null) { - scope.problemReporter().illegalQualifiedParameterizedTypeAllocation(this.type, receiverType); - break; - } - } - } - } - } - } - if (receiverType == null || !receiverType.isValidBinding()) { - hasError = true; - } - - // resolve type arguments (for generic constructor call) - if (this.typeArguments != null) { - int length = this.typeArguments.length; - this.argumentsHaveErrors = sourceLevel < ClassFileConstants.JDK1_5; - this.genericTypeArguments = new TypeBinding[length]; - for (int i = 0; i < length; i++) { - TypeReference typeReference = this.typeArguments[i]; - if ((this.genericTypeArguments[i] = typeReference.resolveType(scope, true /* check bounds*/)) == null) { - this.argumentsHaveErrors = true; - } - if (this.argumentsHaveErrors && typeReference instanceof Wildcard) { - scope.problemReporter().illegalUsageOfWildcard(typeReference); - } - } - if (isDiamond) { - scope.problemReporter().diamondNotWithExplicitTypeArguments(this.typeArguments); - return null; - } - if (this.argumentsHaveErrors) { - if (this.arguments != null) { // still attempt to resolve arguments - for (int i = 0, max = this.arguments.length; i < max; i++) { - this.arguments[i].resolveType(scope); - } - } - return null; - } - } - - // will check for null after args are resolved - this.argumentTypes = Binding.NO_PARAMETERS; - if (this.arguments != null) { - int length = this.arguments.length; - this.argumentTypes = new TypeBinding[length]; - for (int i = 0; i < length; i++) { - Expression argument = this.arguments[i]; - if (argument instanceof CastExpression) { - argument.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on - this.argsContainCast = true; - } - argument.setExpressionContext(INVOCATION_CONTEXT); - if ((this.argumentTypes[i] = argument.resolveType(scope)) == null){ - this.argumentsHaveErrors = hasError = true; - } - } - } - - // limit of fault-tolerance - if (hasError) { - /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=345359, if arguments have errors, completely bail out in the <> case. - No meaningful type resolution is possible since inference of the elided types is fully tied to argument types. Do - not return the partially resolved type. - */ - if (isDiamond) { - return null; // not the partially cooked this.resolvedType - } - if (receiverType instanceof ReferenceBinding) { - ReferenceBinding referenceReceiver = (ReferenceBinding) receiverType; - if (receiverType.isValidBinding()) { - // record a best guess, for clients who need hint about possible contructor match - int length = this.arguments == null ? 0 : this.arguments.length; - TypeBinding[] pseudoArgs = new TypeBinding[length]; - for (int i = length; --i >= 0;) { - pseudoArgs[i] = this.argumentTypes[i] == null ? TypeBinding.NULL : this.argumentTypes[i]; // replace args with errors with null type - } - this.binding = scope.findMethod(referenceReceiver, TypeConstants.INIT, pseudoArgs, this, false); - if (this.binding != null && !this.binding.isValidBinding()) { - MethodBinding closestMatch = ((ProblemMethodBinding)this.binding).closestMatch; - // record the closest match, for clients who may still need hint about possible method match - if (closestMatch != null) { - if (closestMatch.original().typeVariables != Binding.NO_TYPE_VARIABLES) { // generic method - // shouldn't return generic method outside its context, rather convert it to raw method (175409) - closestMatch = scope.environment().createParameterizedGenericMethod(closestMatch.original(), (RawTypeBinding)null); - } - this.binding = closestMatch; - MethodBinding closestMatchOriginal = closestMatch.original(); - if (closestMatchOriginal.isOrEnclosedByPrivateType() && !scope.isDefinedInMethod(closestMatchOriginal)) { - // ignore cases where method is used from within inside itself (e.g. direct recursions) - closestMatchOriginal.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - } - } - } - if (this.anonymousType != null) { - // insert anonymous type in scope (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=210070) - scope.addAnonymousType(this.anonymousType, referenceReceiver); - this.anonymousType.resolve(scope); - return this.resolvedType = this.anonymousType.binding; - } - } - return this.resolvedType = receiverType; - } - if (this.anonymousType == null) { - // qualified allocation with no anonymous type - if (!receiverType.canBeInstantiated()) { - scope.problemReporter().cannotInstantiate(this.type, receiverType); - return this.resolvedType = receiverType; - } - } else { - if (isDiamond) { - if (sourceLevel < ClassFileConstants.JDK9) { - scope.problemReporter().diamondNotWithAnoymousClasses(this.type); - return null; - } - } - ReferenceBinding superType = (ReferenceBinding) receiverType; - if (superType.isTypeVariable()) { - superType = new ProblemReferenceBinding(new char[][]{superType.sourceName()}, superType, ProblemReasons.IllegalSuperTypeVariable); - scope.problemReporter().invalidType(this, superType); - return null; - } else if (this.type != null && superType.isEnum()) { // tolerate enum constant body - scope.problemReporter().cannotInstantiate(this.type, superType); - return this.resolvedType = superType; - } - this.resolvedType = receiverType; - } - } else { - if (this.enclosingInstance != null) { - enclosingInstanceType = this.enclosingInstance.resolvedType; - this.resolvedType = receiverType = this.type.resolvedType; - } - } - MethodBinding constructorBinding = null; - if (isDiamond) { - this.binding = constructorBinding = inferConstructorOfElidedParameterizedType(scope); - if (this.binding == null || !this.binding.isValidBinding()) { - scope.problemReporter().cannotInferElidedTypes(this); - return this.resolvedType = null; - } - if (this.typeExpected == null && sourceLevel >= ClassFileConstants.JDK1_8 && this.expressionContext.definesTargetType()) { - return new PolyTypeBinding(this); - } - this.resolvedType = this.type.resolvedType = receiverType = this.binding.declaringClass; - if (this.anonymousType != null) { - constructorBinding = getAnonymousConstructorBinding((ReferenceBinding) receiverType, scope); - if (constructorBinding == null) - return null; - this.resolvedType = this.anonymousType.binding; - // Check that inferred type is valid - if (!validate((ParameterizedTypeBinding) receiverType, scope)) { - return this.resolvedType; - } - } else { - // 15.9.3 - If the compile-time declaration is applicable by variable arity invocation... - if (this.binding.isVarargs()) { - TypeBinding lastArg = this.binding.parameters[this.binding.parameters.length - 1].leafComponentType(); - if (!lastArg.erasure().canBeSeenBy(scope)) { - scope.problemReporter().invalidType(this, new ProblemReferenceBinding(new char[][] {lastArg.readableName()}, (ReferenceBinding)lastArg, ProblemReasons.NotVisible)); - return this.resolvedType = null; - } - } - } - this.binding = resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope); - } else { - if (this.anonymousType != null) { - constructorBinding = getAnonymousConstructorBinding((ReferenceBinding) receiverType, scope); - if (constructorBinding == null) - return null; - this.resolvedType = this.anonymousType.binding; - } else { - this.binding = constructorBinding = findConstructorBinding(scope, this, (ReferenceBinding) receiverType, this.argumentTypes); - } - } - ReferenceBinding receiver = (ReferenceBinding) receiverType; - ReferenceBinding superType = receiver.isInterface() ? scope.getJavaLangObject() : receiver; - if (constructorBinding.isValidBinding()) { - if (isMethodUseDeprecated(constructorBinding, scope, true, this)) { - scope.problemReporter().deprecatedMethod(constructorBinding, this); - } - if (checkInvocationArguments(scope, null, superType, constructorBinding, this.arguments, - this.argumentTypes, this.argsContainCast, this)) { - this.bits |= ASTNode.Unchecked; - } - if (this.typeArguments != null && constructorBinding.original().typeVariables == Binding.NO_TYPE_VARIABLES) { - scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(constructorBinding, - this.genericTypeArguments, this.typeArguments); - } - } else { - if (constructorBinding.declaringClass == null) { - constructorBinding.declaringClass = superType; - } - if (this.type != null && !this.type.resolvedType.isValidBinding()) { - // problem already got signaled on type reference, do not report secondary problem - return null; - } - scope.problemReporter().invalidConstructor(this, constructorBinding); - return this.resolvedType; - } - if ((constructorBinding.tagBits & TagBits.HasMissingType) != 0) { - scope.problemReporter().missingTypeInConstructor(this, constructorBinding); - } - if (this.enclosingInstance != null) { - ReferenceBinding targetEnclosing = constructorBinding.declaringClass.enclosingType(); - if (targetEnclosing == null) { - scope.problemReporter().unnecessaryEnclosingInstanceSpecification(this.enclosingInstance, receiver); - return this.resolvedType; - } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing) && !scope.isBoxingCompatibleWith(enclosingInstanceType, targetEnclosing)) { - scope.problemReporter().typeMismatchError(enclosingInstanceType, targetEnclosing, this.enclosingInstance, null); - return this.resolvedType; - } - this.enclosingInstance.computeConversion(scope, targetEnclosing, enclosingInstanceType); - } - if (!isDiamond && receiverType.isParameterizedTypeWithActualArguments() && - (this.anonymousType == null || sourceLevel >= ClassFileConstants.JDK9)) { - checkTypeArgumentRedundancy((ParameterizedTypeBinding) receiverType, scope); - } - if (this.anonymousType != null) { - // anonymous type scenario - // Update the anonymous inner class : superclass, interface - LookupEnvironment environment=scope.environment(); - if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { - ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(constructorBinding, scope); - } - this.binding = this.anonymousType.createDefaultConstructorWithBinding(constructorBinding, (this.bits & ASTNode.Unchecked) != 0 && this.genericTypeArguments == null); - return this.resolvedType; - } else { - return this.resolvedType = receiverType; - } - } - - private boolean validate(final ParameterizedTypeBinding allocationType, final Scope scope) { - class ValidityInspector extends TypeBindingVisitor { - private boolean noErrors; - - public ValidityInspector() { - this.noErrors = true; - } - - @Override - public boolean visit(IntersectionTypeBinding18 intersectionTypeBinding18) { - Arrays.sort(intersectionTypeBinding18.intersectingTypes, (t1, t2) -> t1.id - t2.id); - scope.problemReporter().anonymousDiamondWithNonDenotableTypeArguments(QualifiedAllocationExpression.this.type, allocationType); - return this.noErrors = false; // stop traversal - } - @Override - public boolean visit(TypeVariableBinding typeVariable) { - if (typeVariable.isCapture()) { - scope.problemReporter().anonymousDiamondWithNonDenotableTypeArguments(QualifiedAllocationExpression.this.type, allocationType); - return this.noErrors = false; // stop traversal - } - return true; // continue traversal - } - @Override - public boolean visit(ReferenceBinding ref) { - if (!ref.canBeSeenBy(scope)) { - scope.problemReporter().invalidType(QualifiedAllocationExpression.this.anonymousType, new ProblemReferenceBinding(ref.compoundName, ref, ProblemReasons.NotVisible)); - return this.noErrors = false; - } - return true; - } - public boolean isValid() { - TypeBindingVisitor.visit(this, allocationType); - return this.noErrors; - } - } - - return new ValidityInspector().isValid(); - } - private MethodBinding getAnonymousConstructorBinding(ReferenceBinding receiverType, BlockScope scope) { - ReferenceBinding superType = receiverType; - // an anonymous class inherits from java.lang.Object when declared "after" an interface - ReferenceBinding anonymousSuperclass = superType.isInterface() ? scope.getJavaLangObject() : superType; - // insert anonymous type in scope - scope.addAnonymousType(this.anonymousType, superType); - this.anonymousType.resolve(scope); - - // find anonymous super constructor - this.resolvedType = this.anonymousType.binding; // 1.2 change - if ((this.resolvedType.tagBits & TagBits.HierarchyHasProblems) != 0) { - return null; // stop secondary errors - } - return findConstructorBinding(scope, this, anonymousSuperclass, this.argumentTypes); - } - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.enclosingInstance != null) - this.enclosingInstance.traverse(visitor, scope); - if (this.typeArguments != null) { - for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) { - this.typeArguments[i].traverse(visitor, scope); - } - } - if (this.type != null) // case of enum constant - this.type.traverse(visitor, scope); - if (this.arguments != null) { - int argumentsLength = this.arguments.length; - for (int i = 0; i < argumentsLength; i++) - this.arguments[i].traverse(visitor, scope); - } - if (this.anonymousType != null) - this.anonymousType.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } - @Override - protected void reportTypeArgumentRedundancyProblem(ParameterizedTypeBinding allocationType, final BlockScope scope) { - if (diamondOperatorCanbeDeployed(scope)) { - scope.problemReporter().redundantSpecificationOfTypeArguments(this.type, allocationType.arguments); - } - } - private boolean diamondOperatorCanbeDeployed(final BlockScope scope) { - if (this.anonymousType != null && - this.anonymousType.methods != null && - this.anonymousType.methods.length > 0) { - //diamond operator is allowed for anonymous types only from java 9 - if (scope.compilerOptions().complianceLevel < ClassFileConstants.JDK9) return false; - for (AbstractMethodDeclaration method : this.anonymousType.methods) { - if (method.binding != null && !method.binding.isConstructor() && !method.binding.isPrivate() && (method.binding.modifiers & (ExtraCompilerModifiers.AccOverriding | ExtraCompilerModifiers.AccImplementing)) == 0) - return false; - } - } - return true; - } -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java deleted file mode 100644 index fc75646..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java +++ /dev/null @@ -1,1208 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 185682 - Increment/decrement operators mark local variables as read - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 365519 - editorial cleanup after bug 186342 and bug 365387 - * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * Bug 414380 - [compiler][internal] QualifiedNameReference#indexOfFirstFieldBinding does not point to the first field - * Bug 458396 - NPE in CodeStream.invoke() - * Jesper S Moller - Contributions for - * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check - * Jesper S Moller - Contributions for - * bug 378674 - "The method can be declared as static" is wrong - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.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.impl.CompilerOptions; -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.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -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.SyntheticMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; - -public class QualifiedNameReference extends NameReference { - - public char[][] tokens; - public long[] sourcePositions; - public FieldBinding[] otherBindings; - int[] otherDepths; - public int indexOfFirstFieldBinding; // points into tokens & sourcePositions for the first token that corresponds to first FieldBinding - // *** the index is 1-based *** - // during BlockScope#getBinding(..) it will walk through positions until it finds the first field - public SyntheticMethodBinding syntheticWriteAccessor; - public SyntheticMethodBinding[] syntheticReadAccessors; - public TypeBinding genericCast; - public TypeBinding[] otherGenericCasts; - -public QualifiedNameReference(char[][] tokens, long[] positions, int sourceStart, int sourceEnd) { - this.tokens = tokens; - this.sourcePositions = positions; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; -} - -@Override -public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { - // determine the rank until which we now we do not need any actual value for the field access - int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length; - boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); - boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; - FieldBinding lastFieldBinding = null; - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - lastFieldBinding = (FieldBinding) this.binding; - if (needValue || complyTo14) { - manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, 0, flowInfo); - } - // check if final blank field - if (lastFieldBinding.isBlankFinal() - && this.otherBindings != null // the last field binding is only assigned - && currentScope.needBlankFinalFieldInitializationCheck(lastFieldBinding)) { - FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(lastFieldBinding.declaringClass.original(), flowInfo); - if (!fieldInits.isDefinitelyAssigned(lastFieldBinding)) { - currentScope.problemReporter().uninitializedBlankFinalField(lastFieldBinding, this); - } - } - if (needValue) { - checkInternalNPE(currentScope, flowContext, flowInfo, true); - } - break; - case Binding.LOCAL : - // first binding is a local variable - LocalVariableBinding localBinding; - if (!flowInfo - .isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) { - currentScope.problemReporter().uninitializedLocalVariable(localBinding, this, currentScope); - } - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { - localBinding.useFlag = LocalVariableBinding.USED; - } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { - localBinding.useFlag = LocalVariableBinding.FAKE_USED; - } - if (needValue) { - checkInternalNPE(currentScope, flowContext, flowInfo, true); - } - } - - if (needValue) { - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - // only for first binding - } - // all intermediate field accesses are read accesses - if (this.otherBindings != null) { - for (int i = 0; i < otherBindingsCount-1; i++) { - lastFieldBinding = this.otherBindings[i]; - needValue = !this.otherBindings[i+1].isStatic(); - if (needValue || complyTo14) { - manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, i + 1, flowInfo); - } - } - lastFieldBinding = this.otherBindings[otherBindingsCount-1]; - } - - if (isCompound) { - if (otherBindingsCount == 0 - && lastFieldBinding.isBlankFinal() - && currentScope.needBlankFinalFieldInitializationCheck(lastFieldBinding)) { - FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(lastFieldBinding.declaringClass, flowInfo); - if (!fieldInits.isDefinitelyAssigned(lastFieldBinding)) { - currentScope.problemReporter().uninitializedBlankFinalField(lastFieldBinding, this); - } - } - manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, otherBindingsCount, flowInfo); - } - - if (assignment.expression != null) { - flowInfo = - assignment - .expression - .analyseCode(currentScope, flowContext, flowInfo) - .unconditionalInits(); - } - - // the last field access is a write access - if (lastFieldBinding.isFinal()) { - // in a context where it can be assigned? - if (otherBindingsCount == 0 - && this.indexOfFirstFieldBinding == 1 - && lastFieldBinding.isBlankFinal() - && !isCompound - && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { - if (flowInfo.isPotentiallyAssigned(lastFieldBinding)) { - currentScope.problemReporter().duplicateInitializationOfBlankFinalField(lastFieldBinding, this); - } else { - flowContext.recordSettingFinal(lastFieldBinding, this, flowInfo); - } - flowInfo.markAsDefinitelyAssigned(lastFieldBinding); - } else { - currentScope.problemReporter().cannotAssignToFinalField(lastFieldBinding, this); - if (otherBindingsCount == 0 && currentScope.allowBlankFinalFieldAssignment(lastFieldBinding)) { // pretend it got assigned - flowInfo.markAsDefinitelyAssigned(lastFieldBinding); - } - } - } - // note: not covering def.assign for @NonNull: QNR cannot provably refer to a variable of the current object - manageSyntheticAccessIfNecessary(currentScope, lastFieldBinding, -1 /*write-access*/, flowInfo); - - return flowInfo; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return analyseCode(currentScope, flowContext, flowInfo, true); -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { - // determine the rank until which we now we do not need any actual value for the field access - int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length; - - boolean needValue = otherBindingsCount == 0 ? valueRequired : !this.otherBindings[0].isStatic(); - boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - if (needValue || complyTo14) { - manageSyntheticAccessIfNecessary(currentScope, (FieldBinding) this.binding, 0, flowInfo); - } - FieldBinding fieldBinding = (FieldBinding) this.binding; - if (this.indexOfFirstFieldBinding == 1) { // was an implicit reference to the first field binding - // check if reading a final blank field - if (fieldBinding.isBlankFinal() - && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { - FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo); - if (!fieldInits.isDefinitelyAssigned(fieldBinding)) { - currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); - } - } - } - break; - case Binding.LOCAL : // reading a local variable - LocalVariableBinding localBinding; - if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) { - currentScope.problemReporter().uninitializedLocalVariable(localBinding, this, currentScope); - } - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { - localBinding.useFlag = LocalVariableBinding.USED; - } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { - localBinding.useFlag = LocalVariableBinding.FAKE_USED; - } - } - if (needValue) { - checkInternalNPE(currentScope, flowContext, flowInfo, true); - } - if (needValue) { - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - // only for first binding (if value needed only) - } - if (this.otherBindings != null) { - for (int i = 0; i < otherBindingsCount; i++) { - needValue = i < otherBindingsCount-1 ? !this.otherBindings[i+1].isStatic() : valueRequired; - if (needValue || complyTo14) { - manageSyntheticAccessIfNecessary(currentScope, this.otherBindings[i], i + 1, flowInfo); - } - } - } - return flowInfo; -} - -/* check if any dot in this QNR may trigger an NPE. */ -private void checkInternalNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, boolean checkString) { - if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) { - LocalVariableBinding local = (LocalVariableBinding) this.binding; - if (local != null && - (local.type.tagBits & TagBits.IsBaseType) == 0 && - (checkString || local.type.id != TypeIds.T_JavaLangString)) { - if ((this.bits & ASTNode.IsNonNull) == 0) { - flowContext.recordUsingNullReference(scope, local, this, - FlowContext.MAY_NULL, flowInfo); - } - flowInfo.markAsComparedEqualToNonNull(local); - // from thereon it is set - flowContext.markFinallyNullStatus(local, FlowInfo.NON_NULL); - } - } - if (this.otherBindings != null) { - if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.FIELD) { - // is the first field dereferenced annotated Nullable? If so, report immediately - checkNullableFieldDereference(scope, (FieldBinding) this.binding, this.sourcePositions[this.indexOfFirstFieldBinding-1], flowContext, 0); - } - // look for annotated fields, they do not depend on flow context -> check immediately: - int length = this.otherBindings.length - 1; // don't check the last binding - for (int i = 0; i < length; i++) { - checkNullableFieldDereference(scope, this.otherBindings[i], this.sourcePositions[this.indexOfFirstFieldBinding+i], flowContext, 0); - } - } -} - -@Override -public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - if (super.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck)) { - return true; - } - FieldBinding fieldBinding = null; - long position = 0L; - if (this.otherBindings == null) { - if ((this.bits & RestrictiveFlagMASK) == Binding.FIELD) { - fieldBinding = (FieldBinding) this.binding; - position = this.sourcePositions[0]; - } - } else { - fieldBinding = this.otherBindings[this.otherBindings.length - 1]; - position = this.sourcePositions[this.sourcePositions.length - 1]; - } - if (fieldBinding != null) { - return checkNullableFieldDereference(scope, fieldBinding, position, flowContext, ttlForFieldCheck); - } - return false; -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) - */ -@Override -public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { - if (runtimeTimeType == null || compileTimeType == null) - return; - // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast) - FieldBinding field = null; - int length = this.otherBindings == null ? 0 : this.otherBindings.length; - if (length == 0) { - if ((this.bits & Binding.FIELD) != 0 && this.binding != null && this.binding.isValidBinding()) { - field = (FieldBinding) this.binding; - } - } else { - field = this.otherBindings[length-1]; - } - if (field != null) { - FieldBinding originalBinding = field.original(); - TypeBinding originalType = originalBinding.type; - // extra cast needed if field type is type variable - if (originalType.leafComponentType().isTypeVariable()) { - TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) - ? compileTimeType // unboxing: checkcast before conversion - : runtimeTimeType; - TypeBinding typeCast = originalType.genericCast(targetType); - setGenericCast(length, typeCast); - if (typeCast instanceof ReferenceBinding) { - ReferenceBinding referenceCast = (ReferenceBinding) typeCast; - if (!referenceCast.canBeSeenBy(scope)) { - scope.problemReporter().invalidType(this, - new ProblemReferenceBinding( - CharOperation.splitOn('.', referenceCast.shortReadableName()), - referenceCast, - ProblemReasons.NotVisible)); - } - } - } - } - super.computeConversion(scope, runtimeTimeType, compileTimeType); -} - -@Override -public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { - int pc = codeStream.position; - FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); - codeStream.recordPositionsFrom(pc , this.sourceStart); - assignment.expression.generateCode(currentScope, codeStream, true); - fieldStore(currentScope, codeStream, lastFieldBinding, this.syntheticWriteAccessor, getFinalReceiverType(), false /*implicit this*/, valueRequired); - // equivalent to valuesRequired[maxOtherBindings] - if (valueRequired) { - codeStream.generateImplicitConversion(assignment.implicitConversion); - } -} - -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (this.constant != Constant.NotAConstant) { - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - } else { - FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); - if (lastFieldBinding != null) { - boolean isStatic = lastFieldBinding.isStatic(); - Constant fieldConstant = lastFieldBinding.constant(); - if (fieldConstant != Constant.NotAConstant) { - if (!isStatic){ - codeStream.invokeObjectGetClass(); - codeStream.pop(); - } - if (valueRequired) { // inline the last field constant - codeStream.generateConstant(fieldConstant, this.implicitConversion); - } - } else { - boolean isFirst = lastFieldBinding == this.binding - && (this.indexOfFirstFieldBinding == 1 || TypeBinding.equalsEquals(lastFieldBinding.declaringClass, currentScope.enclosingReceiverType())) - && this.otherBindings == null; // could be dup: next.next.next - TypeBinding requiredGenericCast = getGenericCast(this.otherBindings == null ? 0 : this.otherBindings.length); - if (valueRequired - || (!isFirst && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) - || ((this.implicitConversion & TypeIds.UNBOXING) != 0) - || requiredGenericCast != null) { - int lastFieldPc = codeStream.position; - if (lastFieldBinding.declaringClass == null) { // array length - codeStream.arraylength(); - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - // could occur if !valueRequired but compliance >= 1.4 - codeStream.pop(); - } - } else { - SyntheticMethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1]; - if (accessor == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, getFinalReceiverType(), isFirst); - if (isStatic) { - codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass); - } else { - codeStream.fieldAccess(Opcodes.OPC_getfield, lastFieldBinding, constantPoolDeclaringClass); - } - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */); - } - if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast); - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; - // conversion only generated if unboxing - if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion); - switch (isUnboxing ? postConversionType(currentScope).id : lastFieldBinding.type.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - break; - } - } - } - - int fieldPosition = (int) (this.sourcePositions[this.sourcePositions.length - 1] >>> 32); - codeStream.recordPositionsFrom(lastFieldPc, fieldPosition); - } else { - if (!isStatic){ - codeStream.invokeObjectGetClass(); // perform null check - codeStream.pop(); - } - } - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { - FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); - // check if compound assignment is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired); - boolean isFirst = lastFieldBinding == this.binding - && (this.indexOfFirstFieldBinding == 1 || TypeBinding.equalsEquals(lastFieldBinding.declaringClass, currentScope.enclosingReceiverType())) - && this.otherBindings == null; // could be dup: next.next.next - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, getFinalReceiverType(), isFirst); - SyntheticMethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1]; - if (lastFieldBinding.isStatic()) { - if (accessor == null) { - codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */); - } - } else { - codeStream.dup(); - if (accessor == null) { - codeStream.fieldAccess(Opcodes.OPC_getfield, lastFieldBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */); - } - } - // the last field access is a write access - // perform the actual compound operation - int operationTypeID; - switch(operationTypeID = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { - case T_JavaLangString : - case T_JavaLangObject : - case T_undefined : - codeStream.generateStringConcatenationAppend(currentScope, null, expression); - break; - default : - TypeBinding requiredGenericCast = getGenericCast(this.otherBindings == null ? 0 : this.otherBindings.length); - if (requiredGenericCast != null) codeStream.checkcast(requiredGenericCast); - // promote the array reference to the suitable operation type - codeStream.generateImplicitConversion(this.implicitConversion); - // generate the increment value (will by itself be promoted to the operation value) - if (expression == IntLiteral.One) { // prefix operation - codeStream.generateConstant(expression.constant, this.implicitConversion); - } else { - expression.generateCode(currentScope, codeStream, true); - } - // perform the operation - codeStream.sendOperator(operator, operationTypeID); - // cast the value back to the array reference type - codeStream.generateImplicitConversion(assignmentImplicitConversion); - } - // actual assignment - fieldStore(currentScope, codeStream, lastFieldBinding, this.syntheticWriteAccessor, getFinalReceiverType(), false /*implicit this*/, valueRequired); - // equivalent to valuesRequired[maxOtherBindings] -} - -@Override -public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { - FieldBinding lastFieldBinding = generateReadSequence(currentScope, codeStream); - // check if this post increment is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, lastFieldBinding, valueRequired); - boolean isFirst = lastFieldBinding == this.binding - && (this.indexOfFirstFieldBinding == 1 || TypeBinding.equalsEquals(lastFieldBinding.declaringClass, currentScope.enclosingReceiverType())) - && this.otherBindings == null; // could be dup: next.next.next - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, getFinalReceiverType(), isFirst); - SyntheticMethodBinding accessor = this.syntheticReadAccessors == null - ? null - : this.syntheticReadAccessors[this.syntheticReadAccessors.length - 1]; - if (lastFieldBinding.isStatic()) { - if (accessor == null) { - codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, accessor, constantPoolDeclaringClass); - } - } else { - codeStream.dup(); - if (accessor == null) { - codeStream.fieldAccess(Opcodes.OPC_getfield, lastFieldBinding, null /* default declaringClass */); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */); - } - } - TypeBinding requiredGenericCast = getGenericCast(this.otherBindings == null ? 0 : this.otherBindings.length); - TypeBinding operandType; - if (requiredGenericCast != null) { - codeStream.checkcast(requiredGenericCast); - operandType = requiredGenericCast; - } else { - operandType = lastFieldBinding.type; - } - // duplicate the old field value - if (valueRequired) { - if (lastFieldBinding.isStatic()) { - switch (operandType.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2(); - break; - default: - codeStream.dup(); - break; - } - } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] - switch (operandType.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2_x1(); - break; - default: - codeStream.dup_x1(); - break; - } - } - } - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateConstant( - postIncrement.expression.constant, - this.implicitConversion); - codeStream.sendOperator(postIncrement.operator, this.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.generateImplicitConversion( - postIncrement.preAssignImplicitConversion); - fieldStore(currentScope, codeStream, lastFieldBinding, this.syntheticWriteAccessor, getFinalReceiverType(), false /*implicit this*/, false); -} - -/* - * Generate code for all bindings (local and fields) excluding the last one, which may then be generated code - * for a read or write access. - */ -public FieldBinding generateReadSequence(BlockScope currentScope, CodeStream codeStream) { - // determine the rank until which we now we do not need any actual value for the field access - int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length; - boolean needValue = otherBindingsCount == 0 || !this.otherBindings[0].isStatic(); - FieldBinding lastFieldBinding; - TypeBinding lastGenericCast; - TypeBinding lastReceiverType; - boolean complyTo14 = currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4; - - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : - lastFieldBinding = ((FieldBinding) this.binding).original(); - lastGenericCast = this.genericCast; - lastReceiverType = this.actualReceiverType; - // if first field is actually constant, we can inline it - if (lastFieldBinding.constant() != Constant.NotAConstant) { - break; - } - if ((needValue && !lastFieldBinding.isStatic()) || lastGenericCast != null) { - int pc = codeStream.position; - if ((this.bits & ASTNode.DepthMASK) != 0) { - ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); - Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); - codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); - } else { - generateReceiver(codeStream); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - break; - case Binding.LOCAL : // reading the first local variable - lastFieldBinding = null; - lastGenericCast = null; - LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - lastReceiverType = localBinding.type; - // checkEffectiveFinality() returns if it's outer local - boolean capturedInOuter = checkEffectiveFinality(localBinding, currentScope); - if (!needValue) break; // no value needed - // regular local variable read - Constant localConstant = localBinding.constant(); - if (localConstant != Constant.NotAConstant) { - codeStream.generateConstant(localConstant, 0); - // no implicit conversion - } else { - if (capturedInOuter) { - // outer local can be reached either through a synthetic arg or a synthetic field - VariableBinding[] path = currentScope.getEmulationPath(localBinding); - codeStream.generateOuterAccess(path, this, localBinding, currentScope); - } else { - codeStream.load(localBinding); - } - } - break; - default : // should not occur - return null; - } - - // all intermediate field accesses are read accesses - // only the last field binding is a write access - int positionsLength = this.sourcePositions.length; - FieldBinding initialFieldBinding = lastFieldBinding; // can be null if initial was a local binding - if (this.otherBindings != null) { - for (int i = 0; i < otherBindingsCount; i++) { - int pc = codeStream.position; - FieldBinding nextField = this.otherBindings[i].original(); - TypeBinding nextGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[i]; - if (lastFieldBinding != null) { - needValue = !nextField.isStatic(); - Constant fieldConstant = lastFieldBinding.constant(); - if (fieldConstant != Constant.NotAConstant) { - if (i > 0 && !lastFieldBinding.isStatic()) { - codeStream.invokeObjectGetClass(); // perform null check - codeStream.pop(); - } - if (needValue) { - codeStream.generateConstant(fieldConstant, 0); - } - } else { - if (needValue || (i > 0 && complyTo14) || lastGenericCast != null) { - MethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[i]; - if (accessor == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, lastReceiverType, i == 0 && this.indexOfFirstFieldBinding == 1); - if (lastFieldBinding.isStatic()) { - codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass); - } else { - codeStream.fieldAccess(Opcodes.OPC_getfield, lastFieldBinding, constantPoolDeclaringClass); - } - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */); - } - if (lastGenericCast != null) { - codeStream.checkcast(lastGenericCast); - lastReceiverType = lastGenericCast; - } else { - lastReceiverType = lastFieldBinding.type; - } - if (!needValue) codeStream.pop(); - } else { - if (lastFieldBinding == initialFieldBinding) { - if (lastFieldBinding.isStatic()){ - // if no valueRequired, still need possible side-effects of invocation, if field belongs to different class - if (TypeBinding.notEquals(initialFieldBinding.declaringClass, this.actualReceiverType.erasure())) { - MethodBinding accessor = this.syntheticReadAccessors == null ? null : this.syntheticReadAccessors[i]; - if (accessor == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, lastFieldBinding, lastReceiverType, i == 0 && this.indexOfFirstFieldBinding == 1); - codeStream.fieldAccess(Opcodes.OPC_getstatic, lastFieldBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, accessor, null /* default declaringClass */); - } - codeStream.pop(); - } - } - } else if (!lastFieldBinding.isStatic()){ - codeStream.invokeObjectGetClass(); // perform null check - codeStream.pop(); - } - lastReceiverType = lastFieldBinding.type; - } - if ((positionsLength - otherBindingsCount + i - 1) >= 0) { - int fieldPosition = (int) (this.sourcePositions[positionsLength - otherBindingsCount + i - 1] >>>32); - codeStream.recordPositionsFrom(pc, fieldPosition); - } - } - } - lastFieldBinding = nextField; - lastGenericCast = nextGenericCast; - } - } - return lastFieldBinding; -} - -public void generateReceiver(CodeStream codeStream) { - codeStream.aload_0(); -} - -/** - * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() - */ -@Override -public TypeBinding[] genericTypeArguments() { - return null; -} - -protected FieldBinding getCodegenBinding(int index) { - if (index == 0){ - return ((FieldBinding)this.binding).original(); - } else { - return this.otherBindings[index-1].original(); - } -} - -/** - * Returns the receiver type for the final field in sequence (i.e. the return type of the previous binding) - * @return receiver type for the final field in sequence - */ -protected TypeBinding getFinalReceiverType() { - int otherBindingsCount = this.otherBindings == null ? 0 : this.otherBindings.length; - switch (otherBindingsCount) { - case 0 : - return this.actualReceiverType; - case 1 : - return this.genericCast != null ? this.genericCast : ((VariableBinding)this.binding).type; - default: - TypeBinding previousGenericCast = this.otherGenericCasts == null ? null : this.otherGenericCasts[otherBindingsCount-2]; - return previousGenericCast != null ? previousGenericCast : this.otherBindings[otherBindingsCount-2].type; - } -} - -// get the matching generic cast -protected TypeBinding getGenericCast(int index) { - if (index == 0){ - return this.genericCast; - } else { - if (this.otherGenericCasts == null) return null; - return this.otherGenericCasts[index-1]; - } -} -public TypeBinding getOtherFieldBindings(BlockScope scope) { - // At this point restrictiveFlag may ONLY have two potential value : FIELD LOCAL (i.e cast <<(VariableBinding) binding>> is valid) - int length = this.tokens.length; - FieldBinding field = ((this.bits & Binding.FIELD) != 0) ? (FieldBinding) this.binding : null; - TypeBinding type = ((VariableBinding) this.binding).type; - int index = this.indexOfFirstFieldBinding; - if (index == length) { // restrictiveFlag == FIELD - this.constant = ((FieldBinding) this.binding).constant(scope); - // perform capture conversion if read access - return (type != null && (this.bits & ASTNode.IsStrictlyAssigned) == 0) - ? type.capture(scope, this.sourceStart, this.sourceEnd) - : type; - } - // allocation of the fieldBindings array and its respective constants - int otherBindingsLength = length - index; - this.otherBindings = new FieldBinding[otherBindingsLength]; - this.otherDepths = new int[otherBindingsLength]; - - // fill the first constant (the one of the binding) - this.constant = ((VariableBinding) this.binding).constant(scope); - // save first depth, since will be updated by visibility checks of other bindings - int firstDepth = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT; - // iteration on each field - while (index < length) { - char[] token = this.tokens[index]; - if (type == null) - return null; // could not resolve type prior to this point - - this.bits &= ~ASTNode.DepthMASK; // flush previous depth if any - FieldBinding previousField = field; - field = scope.getField(type.capture(scope, (int) (this.sourcePositions[index] >>> 32), (int)this.sourcePositions[index]), token, this); - int place = index - this.indexOfFirstFieldBinding; - this.otherBindings[place] = field; - this.otherDepths[place] = (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT; - if (field.isValidBinding()) { - // set generic cast of for previous field (if any) - if (previousField != null) { - TypeBinding fieldReceiverType = type; - TypeBinding oldReceiverType = fieldReceiverType; - fieldReceiverType = fieldReceiverType.getErasureCompatibleType(field.declaringClass);// handle indirect inheritance thru variable secondary bound - FieldBinding originalBinding = previousField.original(); - if (TypeBinding.notEquals(fieldReceiverType, oldReceiverType) || originalBinding.type.leafComponentType().isTypeVariable()) { // record need for explicit cast at codegen - setGenericCast(place,originalBinding.type.genericCast(fieldReceiverType)); // type cannot be base-type even in boxing case - } - } - // only last field is actually a write access if any - if (isFieldUseDeprecated(field, scope, index+1 == length ? this.bits : 0)) { - scope.problemReporter().deprecatedField(field, this); - } - // constant propagation can only be performed as long as the previous one is a constant too. - if (this.constant != Constant.NotAConstant) { - this.constant = field.constant(scope); - } - - if (field.isStatic()) { - if ((field.modifiers & ClassFileConstants.AccEnum) != 0 && scope.kind != Scope.MODULE_SCOPE) { - // enum constants are checked even when qualified -- modules don't contain field declarations - ReferenceBinding declaringClass = field.original().declaringClass; - MethodScope methodScope = scope.methodScope(); - SourceTypeBinding sourceType = methodScope.enclosingSourceType(); - if ((this.bits & ASTNode.IsStrictlyAssigned) == 0 - && TypeBinding.equalsEquals(sourceType, declaringClass) - && methodScope.lastVisibleFieldID >= 0 - && field.id >= methodScope.lastVisibleFieldID - && (!field.isStatic() || methodScope.isStatic)) { - scope.problemReporter().forwardReference(this, index, field); - } - // check if accessing enum static field in initializer - if ((TypeBinding.equalsEquals(sourceType, declaringClass) || TypeBinding.equalsEquals(sourceType.superclass, declaringClass)) // enum constant body - && field.constant(scope) == Constant.NotAConstant - && !methodScope.isStatic - && methodScope.isInsideInitializerOrConstructor()) { - scope.problemReporter().enumStaticFieldUsedDuringInitialization(field, this); - } - } - // static field accessed through receiver? legal but unoptimal (optional warning) - scope.problemReporter().nonStaticAccessToStaticField(this, field, index); - // indirect static reference ? - if (TypeBinding.notEquals(field.declaringClass, type)) { - scope.problemReporter().indirectAccessToStaticField(this, field); - } - } - type = field.type; - index++; - } else { - this.constant = Constant.NotAConstant; //don't fill other constants slots... - scope.problemReporter().invalidField(this, field, index, type); - setDepth(firstDepth); - return null; - } - } - setDepth(firstDepth); - type = (this.otherBindings[otherBindingsLength - 1]).type; - // perform capture conversion if read access - return (type != null && (this.bits & ASTNode.IsStrictlyAssigned) == 0) - ? type.capture(scope, this.sourceStart, this.sourceEnd) - : type; -} - -@Override -public boolean isEquivalent(Reference reference) { - if (reference instanceof FieldReference) { - return reference.isEquivalent(this); // comparison FR <-> QNR is implemented only once - } - if (!(reference instanceof QualifiedNameReference)) return false; - // straight-forward test of equality of two QNRs: - QualifiedNameReference qualifiedReference = (QualifiedNameReference) reference; - if (this.tokens.length != qualifiedReference.tokens.length) return false; - if (this.binding != qualifiedReference.binding) return false; - if (this.otherBindings != null) { - if (qualifiedReference.otherBindings == null) return false; - int len = this.otherBindings.length; - if (len != qualifiedReference.otherBindings.length) return false; - for (int i=0; i 0 denotes one of the 'otherBindings', index < 0 denotes a write access (to last binding) - if (fieldBinding.constant(currentScope) != Constant.NotAConstant) - return; - - if (fieldBinding.isPrivate()) { // private access - FieldBinding codegenField = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index); - ReferenceBinding declaringClass = codegenField.declaringClass; - if (!currentScope.enclosingSourceType().isNestmateOf(declaringClass) && - TypeBinding.notEquals(declaringClass, currentScope.enclosingSourceType())) { - setSyntheticAccessor(fieldBinding, index, ((SourceTypeBinding) declaringClass).addSyntheticMethod(codegenField, index >= 0 /*read-access?*/, false /*not super access*/)); - currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, index >= 0 /*read-access?*/); - return; - } - } else if (fieldBinding.isProtected()){ - int depth = (index == 0 || (index < 0 && this.otherDepths == null)) - ? (this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT - : this.otherDepths[index < 0 ? this.otherDepths.length-1 : index-1]; - - // implicit protected access - if (depth > 0 && (fieldBinding.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage())) { - FieldBinding codegenField = getCodegenBinding(index < 0 ? (this.otherBindings == null ? 0 : this.otherBindings.length) : index); - setSyntheticAccessor(fieldBinding, index, - ((SourceTypeBinding) currentScope.enclosingSourceType().enclosingTypeAt(depth)).addSyntheticMethod(codegenField, index >= 0 /*read-access?*/, false /*not super access*/)); - currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, index >= 0 /*read-access?*/); - return; - } - } -} - -@Override -public Constant optimizedBooleanConstant() { - if (this.binding.isValidBinding() && this.resolvedType != null) { - switch (this.resolvedType.id) { - case T_boolean : - case T_JavaLangBoolean : - if (this.constant != Constant.NotAConstant) return this.constant; - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - if (this.otherBindings == null) - return ((FieldBinding)this.binding).constant(); - //$FALL-THROUGH$ - case Binding.LOCAL : // reading a local variable - return this.otherBindings[this.otherBindings.length-1].constant(); - } - } - } - return Constant.NotAConstant; -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope) - */ -@Override -public TypeBinding postConversionType(Scope scope) { - TypeBinding convertedType = this.resolvedType; - TypeBinding requiredGenericCast = getGenericCast(this.otherBindings == null ? 0 : this.otherBindings.length); - if (requiredGenericCast != null) - convertedType = requiredGenericCast; - int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; - switch (runtimeType) { - case T_boolean : - convertedType = TypeBinding.BOOLEAN; - break; - case T_byte : - convertedType = TypeBinding.BYTE; - break; - case T_short : - convertedType = TypeBinding.SHORT; - break; - case T_char : - convertedType = TypeBinding.CHAR; - break; - case T_int : - convertedType = TypeBinding.INT; - break; - case T_float : - convertedType = TypeBinding.FLOAT; - break; - case T_long : - convertedType = TypeBinding.LONG; - break; - case T_double : - convertedType = TypeBinding.DOUBLE; - break; - default : - } - if ((this.implicitConversion & TypeIds.BOXING) != 0) { - convertedType = scope.environment().computeBoxingType(convertedType); - } - return convertedType; -} - -@Override -public StringBuilder printExpression(int indent, StringBuilder output) { - for (int i = 0; i < this.tokens.length; i++) { - if (i > 0) output.append('.'); - output.append(this.tokens[i]); - } - return output; -} - -/** - * Normal field binding did not work, try to bind to a field of the delegate receiver. - */ -public TypeBinding reportError(BlockScope scope) { - Binding inaccessible = scope.environment().getInaccessibleBinding(this.tokens, scope.module()); - if (inaccessible instanceof TypeBinding) { - this.indexOfFirstFieldBinding = -1; - this.binding = inaccessible; - scope.problemReporter().invalidType(this, (TypeBinding) this.binding); - } else if (this.binding instanceof ProblemFieldBinding) { - scope.problemReporter().invalidField(this, (FieldBinding) this.binding); - } else if (this.binding instanceof ProblemReferenceBinding || this.binding instanceof MissingTypeBinding) { - scope.problemReporter().invalidType(this, (TypeBinding) this.binding); - } else { - scope.problemReporter().unresolvableReference(this, this.binding); - } - return null; -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - // field and/or local are done before type lookups - // the only available value for the restrictiveFlag BEFORE - // the TC is Flag_Type Flag_LocalField and Flag_TypeLocalField - this.actualReceiverType = scope.enclosingReceiverType(); - this.constant = Constant.NotAConstant; - if ((this.binding = scope.getBinding(this.tokens, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/)).isValidBinding()) { - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.VARIABLE : //============only variable=========== - case Binding.TYPE | Binding.VARIABLE : - if (this.binding instanceof LocalVariableBinding) { - this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits - this.bits |= Binding.LOCAL; - LocalVariableBinding local = (LocalVariableBinding) this.binding; - if (!local.isFinal() && (this.bits & ASTNode.IsCapturedOuterLocal) != 0) { - if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) // for 8, defer till effective finality could be ascertained. - scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding) this.binding, this); - } - if (local.type != null && (local.type.tagBits & TagBits.HasMissingType) != 0) { - // only complain if field reference (for local, its type got flagged already) - return null; - } - this.resolvedType = getOtherFieldBindings(scope); - if (this.resolvedType != null && (this.resolvedType.tagBits & TagBits.HasMissingType) != 0) { - FieldBinding lastField = this.otherBindings[this.otherBindings.length - 1]; - scope.problemReporter().invalidField(this, new ProblemFieldBinding(lastField.declaringClass, lastField.name, ProblemReasons.NotFound), this.tokens.length, this.resolvedType.leafComponentType()); - return null; - } - return this.resolvedType; - } - if (this.binding instanceof FieldBinding) { - this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits - this.bits |= Binding.FIELD; - FieldBinding fieldBinding = (FieldBinding) this.binding; - ReferenceBinding declaringClass = fieldBinding.original().declaringClass; - MethodScope methodScope = null; - SourceTypeBinding sourceType = null; - if (scope.kind != Scope.MODULE_SCOPE) { - methodScope = scope.methodScope(); - sourceType = methodScope.enclosingSourceType(); - } - // check for forward references - if (scope.kind != Scope.MODULE_SCOPE) { - if ((this.indexOfFirstFieldBinding == 1 || (fieldBinding.modifiers & ClassFileConstants.AccEnum) != 0 || (!fieldBinding.isFinal() && declaringClass.isEnum())) // enum constants are checked even when qualified - && TypeBinding.equalsEquals(sourceType, declaringClass) - && methodScope.lastVisibleFieldID >= 0 - && fieldBinding.id >= methodScope.lastVisibleFieldID - && (!fieldBinding.isStatic() || methodScope.isStatic)) { - if (methodScope.insideTypeAnnotation && fieldBinding.id == methodScope.lastVisibleFieldID) { - // false alarm, location is NOT a field initializer but the value in a memberValuePair - } else { - scope.problemReporter().forwardReference(this, this.indexOfFirstFieldBinding-1, fieldBinding); - } - } - } - if (isFieldUseDeprecated(fieldBinding, scope, this.indexOfFirstFieldBinding == this.tokens.length ? this.bits : 0)) { - scope.problemReporter().deprecatedField(fieldBinding, this); - } - if (fieldBinding.isStatic()) { - // only last field is actually a write access if any - // check if accessing enum static field in initializer - if (declaringClass.isEnum() && scope.kind != Scope.MODULE_SCOPE) { - if ((TypeBinding.equalsEquals(sourceType, declaringClass) || TypeBinding.equalsEquals(sourceType.superclass, declaringClass)) // enum constant body - && fieldBinding.constant(scope) == Constant.NotAConstant - && !methodScope.isStatic - && methodScope.isInsideInitializerOrConstructor()) { - scope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this); - } - } - if (this.indexOfFirstFieldBinding > 1 - && TypeBinding.notEquals(fieldBinding.declaringClass, this.actualReceiverType) - && fieldBinding.declaringClass.canBeSeenBy(scope)) { - scope.problemReporter().indirectAccessToStaticField(this, fieldBinding); - } - } else { - boolean inStaticContext = scope.methodScope().isStatic; - if (this.indexOfFirstFieldBinding == 1) { - if (scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) { - scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding); - } - if (!inStaticContext) { - scope.tagAsAccessingEnclosingInstanceStateOf(fieldBinding.declaringClass, false /* type variable access */); - } - } - //must check for the static status.... - if (this.indexOfFirstFieldBinding > 1 //accessing to a field using a type as "receiver" is allowed only with static field - || inStaticContext) { // the field is the first token of the qualified reference.... - scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding); - return null; - } - } - - this.resolvedType = getOtherFieldBindings(scope); - if (this.resolvedType != null - && (this.resolvedType.tagBits & TagBits.HasMissingType) != 0) { - FieldBinding lastField = this.indexOfFirstFieldBinding == this.tokens.length ? (FieldBinding)this.binding : this.otherBindings[this.otherBindings.length - 1]; - scope.problemReporter().invalidField(this, new ProblemFieldBinding(lastField.declaringClass, lastField.name, ProblemReasons.NotFound), this.tokens.length, this.resolvedType.leafComponentType()); - return null; - } - return this.resolvedType; - } - // thus it was a type - this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits - this.bits |= Binding.TYPE; - //$FALL-THROUGH$ - case Binding.TYPE : //=============only type ============== - TypeBinding type = (TypeBinding) this.binding; -// if (isTypeUseDeprecated(type, scope)) -// scope.problemReporter().deprecatedType(type, this); - type = scope.environment().convertToRawType(type, false /*do not force conversion of enclosing types*/); - return this.resolvedType = type; - } - } - //========error cases=============== - return this.resolvedType = reportError(scope); -} - -@Override -public void setFieldIndex(int index) { - this.indexOfFirstFieldBinding = index; -} - -// set the matching codegenBinding and generic cast -protected void setGenericCast(int index, TypeBinding someGenericCast) { - if (someGenericCast == null) return; - if (index == 0){ - this.genericCast = someGenericCast; - } else { - if (this.otherGenericCasts == null) { - this.otherGenericCasts = new TypeBinding[this.otherBindings.length]; - } - this.otherGenericCasts[index-1] = someGenericCast; - } -} - -// set the matching synthetic accessor -protected void setSyntheticAccessor(FieldBinding fieldBinding, int index, SyntheticMethodBinding syntheticAccessor) { - if (index < 0) { // write-access ? - this.syntheticWriteAccessor = syntheticAccessor; - } else { - if (this.syntheticReadAccessors == null) { - this.syntheticReadAccessors = new SyntheticMethodBinding[this.otherBindings == null ? 1 : this.otherBindings.length + 1]; - } - this.syntheticReadAccessors[index] = syntheticAccessor; - } -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} - -@Override -public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} - -@Override -public String unboundReferenceErrorName() { - return new String(this.tokens[0]); -} - -@Override -public char[][] getName() { - return this.tokens; -} - -@Override -public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotations) { - if (this.binding != null && isFieldAccess()) { - FieldBinding fieldBinding; - if (this.otherBindings == null) { - fieldBinding = (FieldBinding) this.binding; - } else { - fieldBinding = this.otherBindings[this.otherBindings.length - 1]; - } - if (supportTypeAnnotations || fieldBinding.isNullable() || fieldBinding.isNonNull()) { - return fieldBinding; - } - } - return null; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java deleted file mode 100644 index aadd723..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedSuperReference.java +++ /dev/null @@ -1,135 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 382350 - [1.8][compiler] Unable to invoke inherited default method via I.super.m() syntax - * bug 404649 - [1.8][compiler] detect illegal reference to indirect or redundant super - * bug 404728 - [1.8]NPE on QualifiedSuperReference error - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -public class QualifiedSuperReference extends QualifiedThisReference { - -public QualifiedSuperReference(TypeReference name, int pos, int sourceEnd) { - super(name, pos, sourceEnd); -} - -@Override -public boolean isSuper() { - return true; -} - -@Override -public boolean isQualifiedSuper() { - return true; -} - -@Override -public boolean isThis() { - return false; -} - -@Override -public StringBuilder printExpression(int indent, StringBuilder output) { - return this.qualification.print(0, output).append(".super"); //$NON-NLS-1$ -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - if ((this.bits & ParenthesizedMASK) != 0) { - scope.problemReporter().invalidParenthesizedExpression(this); - return null; - } - super.resolveType(scope); - if (this.resolvedType != null && !this.resolvedType.isValidBinding()) { - scope.problemReporter().illegalSuperAccess(this.qualification.resolvedType, this.resolvedType, this); - return null; - } - if (this.currentCompatibleType == null) - return null; // error case - - if (this.currentCompatibleType.id == T_JavaLangObject) { - scope.problemReporter().cannotUseSuperInJavaLangObject(this); - return null; - } - return this.resolvedType = (this.currentCompatibleType.isInterface() - ? this.currentCompatibleType - : this.currentCompatibleType.superclass()); -} - -@Override -int findCompatibleEnclosing(ReferenceBinding enclosingType, TypeBinding type, BlockScope scope) { - if (type.isInterface()) { - // super call to an overridden default method? (not considering outer enclosings) - CompilerOptions compilerOptions = scope.compilerOptions(); - ReferenceBinding[] supers = enclosingType.superInterfaces(); - int length = supers.length; - boolean isJava8 = compilerOptions.complianceLevel >= ClassFileConstants.JDK1_8; - boolean isLegal = true; // false => compoundName != null && closestMatch != null - char[][] compoundName = null; - ReferenceBinding closestMatch = null; - for (int i = 0; i < length; i++) { - if (TypeBinding.equalsEquals(supers[i].erasure(), type)) { - this.currentCompatibleType = closestMatch = supers[i]; - } else if (supers[i].erasure().isCompatibleWith(type)) { - isLegal = false; - compoundName = supers[i].compoundName; - if (closestMatch == null) - closestMatch = supers[i]; - // keep looking to ensure we always find the referenced type (even if illegal) - } - } - if (!isLegal || !isJava8) { - this.currentCompatibleType = null; - // Please note the slightly unconventional use of the ProblemReferenceBinding: - // we use the problem's compoundName to report the type being illegally bypassed, - // whereas the closestMatch denotes the resolved (though illegal) target type - // for downstream resolving. - this.resolvedType = new ProblemReferenceBinding(compoundName, - closestMatch, isJava8 ? ProblemReasons.AttemptToBypassDirectSuper : ProblemReasons.InterfaceMethodInvocationNotBelow18); - } - return 0; // never an outer enclosing type - } - return super.findCompatibleEnclosing(enclosingType, type, scope); -} - -@Override -public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.qualification.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); -} -@Override -public void traverse( - ASTVisitor visitor, - ClassScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.qualification.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java deleted file mode 100644 index 2edde0a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedThisReference.java +++ /dev/null @@ -1,180 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 382350 - [1.8][compiler] Unable to invoke inherited default method via I.super.m() syntax - * bug 404649 - [1.8][compiler] detect illegal reference to indirect or redundant super - * Jesper S Moller - Contributions for - * bug 378674 - "The method can be declared as static" is wrong - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class QualifiedThisReference extends ThisReference { - - public TypeReference qualification; - ReferenceBinding currentCompatibleType; - - public QualifiedThisReference(TypeReference name, int sourceStart, int sourceEnd) { - super(sourceStart, sourceEnd); - this.qualification = name; - name.bits |= IgnoreRawTypeCheck; // no need to worry about raw type usage - this.sourceStart = name.sourceStart; - } - - @Override - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - return flowInfo; - } - - @Override - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo, - boolean valueRequired) { - - return flowInfo; - } - - /** - * Code generation for QualifiedThisReference - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ - @Override - public void generateCode( - BlockScope currentScope, - CodeStream codeStream, - boolean valueRequired) { - - int pc = codeStream.position; - if (valueRequired) { - if ((this.bits & DepthMASK) != 0) { - Object[] emulationPath = - currentScope.getEmulationPath(this.currentCompatibleType, true /*only exact match*/, false/*consider enclosing arg*/); - codeStream.generateOuterAccess(emulationPath, this, this.currentCompatibleType, currentScope); - } else { - // nothing particular after all - codeStream.aload_0(); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - - this.constant = Constant.NotAConstant; - // X.this is not a param/raw type as denoting enclosing instance - TypeBinding type = this.qualification.resolveType(scope, true /* check bounds*/); - if (type == null || !type.isValidBinding()) return null; - // X.this is not a param/raw type as denoting enclosing instance - type = type.erasure(); - - // resolvedType needs to be converted to parameterized - if (type instanceof ReferenceBinding) { - this.resolvedType = scope.environment().convertToParameterizedType((ReferenceBinding) type); - } else { - // error case - this.resolvedType = type; - } - - // the qualification MUST exactly match some enclosing type name - // It is possible to qualify 'this' by the name of the current class - int depth = findCompatibleEnclosing(scope.referenceType().binding, type, scope); - this.bits &= ~DepthMASK; // flush previous depth if any - this.bits |= (depth & 0xFF) << DepthSHIFT; // encoded depth into 8 bits - - if (this.currentCompatibleType == null) { - if (this.resolvedType.isValidBinding()) - scope.problemReporter().noSuchEnclosingInstance(type, this, false); - // otherwise problem will be reported by the caller - return this.resolvedType; - } else { - scope.tagAsAccessingEnclosingInstanceStateOf(this.currentCompatibleType, false /* type variable access */); - } - - // Ensure one cannot write code like: B() { super(B.this); } - if (depth == 0) { - checkAccess(scope, null); - } // if depth>0, path emulation will diagnose bad scenarii - else if (scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK16) { - MethodScope ms = scope.methodScope(); - if (ms.isStatic) - ms.problemReporter().errorThisSuperInStatic(this); - } - MethodScope methodScope = scope.namedMethodScope(); - if (methodScope != null) { - MethodBinding method = methodScope.referenceMethodBinding(); - if (method != null) { - TypeBinding receiver = method.receiver; - while (receiver != null) { - if (TypeBinding.equalsEquals(receiver, this.resolvedType)) - return this.resolvedType = receiver; - receiver = receiver.enclosingType(); - } - } - } - return this.resolvedType; - } - - int findCompatibleEnclosing(ReferenceBinding enclosingType, TypeBinding type, BlockScope scope) { - int depth = 0; - this.currentCompatibleType = enclosingType; - while (this.currentCompatibleType != null && TypeBinding.notEquals(this.currentCompatibleType, type)) { - depth++; - this.currentCompatibleType = this.currentCompatibleType.isStatic() ? null : this.currentCompatibleType.enclosingType(); - } - return depth; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - - return this.qualification.print(0, output).append(".this"); //$NON-NLS-1$ - } - - @Override - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.qualification.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); - } - - @Override - public void traverse( - ASTVisitor visitor, - ClassScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.qualification.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java deleted file mode 100644 index f6db182..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java +++ /dev/null @@ -1,251 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; - -public class QualifiedTypeReference extends TypeReference { - - public char[][] tokens; - public long[] sourcePositions; - - public QualifiedTypeReference(char[][] sources , long[] poss) { - - this.tokens = sources ; - this.sourcePositions = poss ; - this.sourceStart = (int) (this.sourcePositions[0]>>>32) ; - this.sourceEnd = (int)(this.sourcePositions[this.sourcePositions.length-1] & 0x00000000FFFFFFFFL ) ; - } - - @Override - public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { - int totalDimensions = this.dimensions() + additionalDimensions; - Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations); - ArrayQualifiedTypeReference arrayQualifiedTypeReference = new ArrayQualifiedTypeReference(this.tokens, totalDimensions, allAnnotations, this.sourcePositions); - arrayQualifiedTypeReference.annotations = this.annotations; - arrayQualifiedTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations); - if (!isVarargs) - arrayQualifiedTypeReference.extendedDimensions = additionalDimensions; - return arrayQualifiedTypeReference; - } - - protected TypeBinding findNextTypeBinding(int tokenIndex, Scope scope, PackageBinding packageBinding) { - LookupEnvironment env = scope.environment(); - try { - env.missingClassFileLocation = this; - if (this.resolvedType == null) { - this.resolvedType = scope.getType(this.tokens[tokenIndex], packageBinding); - } else { - this.resolvedType = scope.getMemberType(this.tokens[tokenIndex], (ReferenceBinding) this.resolvedType); - if (!this.resolvedType.isValidBinding()) { - this.resolvedType = new ProblemReferenceBinding( - CharOperation.subarray(this.tokens, 0, tokenIndex + 1), - (ReferenceBinding)this.resolvedType.closestMatch(), - this.resolvedType.problemId()); - } - } - return this.resolvedType; - } catch (AbortCompilation e) { - e.updateContext(this, scope.referenceCompilationUnit().compilationResult); - throw e; - } finally { - env.missingClassFileLocation = null; - } - } - - @Override - public char[] getLastToken() { - return this.tokens[this.tokens.length-1]; - } - - protected void rejectAnnotationsOnPackageQualifiers(Scope scope, PackageBinding packageBinding) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=390882 - if (packageBinding == null || this.annotations == null) return; - - int i = packageBinding.compoundName.length; - for (int j = 0; j < i; j++) { - Annotation[] qualifierAnnot = this.annotations[j]; - if (qualifierAnnot != null && qualifierAnnot.length > 0) { - if (j == 0) { - for (int k = 0; k < qualifierAnnot.length; k++) { - scope.problemReporter().typeAnnotationAtQualifiedName(qualifierAnnot[k]); - } - } else { - scope.problemReporter().misplacedTypeAnnotations(qualifierAnnot[0], - qualifierAnnot[qualifierAnnot.length - 1]); - this.annotations[j] = null; - } - } - } - } - - protected static void rejectAnnotationsOnStaticMemberQualififer(Scope scope, ReferenceBinding currentType, Annotation[] qualifierAnnot) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=385137 - if (currentType.isMemberType() && currentType.isStatic() && qualifierAnnot != null && qualifierAnnot.length > 0) { - scope.problemReporter().illegalTypeAnnotationsInStaticMemberAccess(qualifierAnnot[0], - qualifierAnnot[qualifierAnnot.length - 1]); - } - } - - @Override - protected TypeBinding getTypeBinding(Scope scope) { - - if (this.resolvedType != null) { - return this.resolvedType; - } - Binding binding = scope.getPackage(this.tokens); - if (this.resolvedType != null) { // recheck in case we had re-entrance - return this.resolvedType; - } - if (binding != null && !binding.isValidBinding()) { - if (binding instanceof ProblemReferenceBinding && binding.problemId() == ProblemReasons.NotFound) { - ProblemReferenceBinding problemBinding = (ProblemReferenceBinding) binding; - Binding pkg = scope.getTypeOrPackage(this.tokens); - return new ProblemReferenceBinding(problemBinding.compoundName, pkg instanceof PackageBinding ? null : scope.environment().createMissingType(null, this.tokens), ProblemReasons.NotFound); - } - return (ReferenceBinding) binding; // not found - } - PackageBinding packageBinding = binding == null ? null : (PackageBinding) binding; - int typeStart = packageBinding == null ? 0 : packageBinding.compoundName.length; - - if (packageBinding != null) { - PackageBinding uniquePackage = packageBinding.getVisibleFor(scope.module(), false); - if (uniquePackage instanceof SplitPackageBinding) { - CompilerOptions compilerOptions = scope.compilerOptions(); - boolean inJdtDebugCompileMode = compilerOptions.enableJdtDebugCompileMode; - if (!inJdtDebugCompileMode) { - SplitPackageBinding splitPackage = (SplitPackageBinding) uniquePackage; - scope.problemReporter().conflictingPackagesFromModules(splitPackage, scope.module(), this.sourceStart, (int)this.sourcePositions[typeStart-1]); - this.resolvedType = new ProblemReferenceBinding(this.tokens, null, ProblemReasons.Ambiguous); - return null; - } - } - } - rejectAnnotationsOnPackageQualifiers(scope, packageBinding); - - boolean isClassScope = scope.kind == Scope.CLASS_SCOPE; - ReferenceBinding qualifiedType = null; - for (int i = typeStart, max = this.tokens.length, last = max-1; i < max; i++) { - findNextTypeBinding(i, scope, packageBinding); - if (!this.resolvedType.isValidBinding()) - return this.resolvedType; - if (i == 0 && this.resolvedType.isTypeVariable() && ((TypeVariableBinding) this.resolvedType).firstBound == null) { // cannot select from a type variable - scope.problemReporter().illegalAccessFromTypeVariable((TypeVariableBinding) this.resolvedType, this); - return null; - } - if (i <= last && isTypeUseDeprecated(this.resolvedType, scope)) { - reportDeprecatedType(this.resolvedType, scope, i); - } - if (isClassScope) - if (((ClassScope) scope).detectHierarchyCycle(this.resolvedType, this)) // must connect hierarchy to find inherited member types - return null; - ReferenceBinding currentType = (ReferenceBinding) this.resolvedType; - if (qualifiedType != null) { - if (this.annotations != null) { - rejectAnnotationsOnStaticMemberQualififer(scope, currentType, this.annotations[i-1]); - } - ReferenceBinding enclosingType = currentType.enclosingType(); - if (enclosingType != null && TypeBinding.notEquals(enclosingType.erasure(), qualifiedType.erasure())) { - qualifiedType = enclosingType; // inherited member type, leave it associated with its enclosing rather than subtype - } - if (currentType.isGenericType()) { - qualifiedType = scope.environment().createRawType(currentType, qualifiedType); - } else if (!currentType.hasEnclosingInstanceContext()) { - qualifiedType = currentType; // parameterization of enclosing is irrelevant in this case - } else { - boolean rawQualified = qualifiedType.isRawType(); - if (rawQualified) { - qualifiedType = scope.environment().createRawType((ReferenceBinding)currentType.erasure(), qualifiedType); - } else if (qualifiedType.isParameterizedType() && TypeBinding.equalsEquals(qualifiedType.erasure(), currentType.enclosingType().erasure())) { - qualifiedType = scope.environment().createParameterizedType((ReferenceBinding)currentType.erasure(), null, qualifiedType); - } else { - qualifiedType = currentType; - } - } - } else { - qualifiedType = currentType.isGenericType() ? (ReferenceBinding)scope.environment().convertToRawType(currentType, false /*do not force conversion of enclosing types*/) : currentType; - } - recordResolution(scope.environment(), qualifiedType); - } - this.resolvedType = qualifiedType; - return this.resolvedType; - } - - void recordResolution(LookupEnvironment env, TypeBinding typeFound) { - if (typeFound != null && typeFound.isValidBinding()) { - synchronized (env.root) { - for (int i = 0; i < env.root.resolutionListeners.length; i++) { - env.root.resolutionListeners[i].recordResolution(this, typeFound); - } - } - } - } - - @Override - public char[][] getTypeName(){ - - return this.tokens; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - for (int i = 0; i < this.tokens.length; i++) { - if (i > 0) output.append('.'); - if (this.annotations != null && this.annotations[i] != null) { - printAnnotations(this.annotations[i], output); - output.append(' '); - } - output.append(this.tokens[i]); - } - return output; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLevels = this.annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - int annotationsLength = this.annotations[i] == null ? 0 : this.annotations[i].length; - for (int j = 0; j < annotationsLength; j++) - this.annotations[i][j].traverse(visitor, scope); - } - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLevels = this.annotations.length; - for (int i = 0; i < annotationsLevels; i++) { - int annotationsLength = this.annotations[i] == null ? 0 : this.annotations[i].length; - for (int j = 0; j < annotationsLength; j++) - this.annotations[i][j].traverse(visitor, scope); - } - } - } - visitor.endVisit(this, scope); - } - @Override - public int getAnnotatableLevels() { - return this.tokens.length; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Receiver.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Receiver.java deleted file mode 100644 index 0ad7b94..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Receiver.java +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.ast; - -public class Receiver extends Argument { - public NameReference qualifyingName; - public Receiver(char[] name, long posNom, TypeReference typeReference, NameReference qualifyingName, int modifiers) { - super(name, posNom, typeReference, modifiers); - this.qualifyingName = qualifyingName; - } - @Override - public boolean isReceiver() { - return true; - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - - printIndent(indent, output); - printModifiers(this.modifiers, output); - - if (this.type == null) { - output.append(" "); //$NON-NLS-1$ - } else { - this.type.print(0, output).append(' '); - } - if (this.qualifyingName != null) { - this.qualifyingName.print(indent, output); - output.append('.'); - } - return output.append(this.name); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/RecordComponent.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/RecordComponent.java deleted file mode 100644 index eab24c5..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/RecordComponent.java +++ /dev/null @@ -1,172 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.List; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class RecordComponent extends AbstractVariableDeclaration { - - public RecordComponentBinding binding; - - public RecordComponent( - char[] name, - int sourceStart, - int sourceEnd) { - - this.name = name; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - this.declarationEnd = sourceEnd; - } - public RecordComponent(char[] name, long posNom, TypeReference tr, int modifiers) { - this(name, (int) (posNom >>> 32), (int) posNom); - this.declarationSourceEnd = (int) posNom; - this.modifiers = modifiers; - this.type = tr; - if (tr != null) { - this.bits |= (tr.bits & ASTNode.HasTypeAnnotations); - } - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - //TODO: Add error checking if relevant. - return flowInfo; - } - - public void checkModifiers() { - - //only potential valid modifier is <> - if (((this.modifiers & ExtraCompilerModifiers.AccJustFlag) & ~ClassFileConstants.AccFinal) != 0) - //AccModifierProblem -> other (non-visibility problem) - //AccAlternateModifierProblem -> duplicate modifier - //AccModifierProblem | AccAlternateModifierProblem -> visibility problem" - - this.modifiers = (this.modifiers & ~ExtraCompilerModifiers.AccAlternateModifierProblem) | ExtraCompilerModifiers.AccModifierProblem; - } - - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - - if ((this.bits & IsReachable) == 0) { - return; // TODO: can this ever happen? - } - codeStream.recordPositionsFrom(codeStream.position, this.sourceStart); - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind() - */ - @Override - public int getKind() { - return RECORD_COMPONENT; - } - - public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, allAnnotationContexts); - for (int i = 0, max = this.annotations.length; i < max; i++) { - Annotation annotation = this.annotations[i]; - annotation.traverse(collector, (BlockScope) null); - } - } - - public boolean isVarArgs() { - return this.type != null && (this.type.bits & IsVarArgs) != 0; - } - - @Override - public void resolve(BlockScope scope) { - resolveAnnotations(scope, this.annotations, this.binding); - // Check if this declaration should now have the type annotations bit set - if (this.annotations != null) { - for (int i = 0, max = this.annotations.length; i < max; i++) { - TypeBinding resolvedAnnotationType = this.annotations[i].resolvedType; - if (resolvedAnnotationType != null && (resolvedAnnotationType.getAnnotationTagBits() & TagBits.AnnotationForTypeUse) != 0) { - this.bits |= ASTNode.HasTypeAnnotations; - // also update the accessor's return type: - if (this.binding != null && this.binding.declaringRecord != null) { - for (MethodBinding methodBinding : this.binding.declaringRecord.methods()) { - if (methodBinding instanceof SyntheticMethodBinding) { - SyntheticMethodBinding smb = (SyntheticMethodBinding) methodBinding; - if (smb.purpose == SyntheticMethodBinding.FieldReadAccess && smb.recordComponentBinding == this.binding) { - smb.returnType = this.binding.type; - break; - } - } - } - } - break; - } - } - } - // check @Deprecated annotation presence - Mostly in the future :) -// if ((this.binding.getAnnotationTagBits() & TagBits.AnnotationDeprecated) == 0 -// && (this.binding.modifiers & ClassFileConstants.AccDeprecated) != 0 -// && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) { -// scope.problemReporter().missingDeprecatedAnnotationForRecordComponent(this); -// } - } - // TODO: check when to call/relevance? - void validateNullAnnotations(BlockScope scope) { - if (!scope.validateNullAnnotation(this.binding.tagBits, this.type, this.annotations)) - this.binding.tagBits &= ~TagBits.AnnotationNullMASK; - } - - @Override - public StringBuilder print(int indent, StringBuilder output) { - - printIndent(indent, output); - printModifiers(this.modifiers, output); - if (this.annotations != null) { - printAnnotations(this.annotations, output); - output.append(' '); - } - - if (this.type == null) { - output.append(" "); //$NON-NLS-1$ - } else { - this.type.print(0, output).append(' '); - } - return output.append(this.name); - } - - @Override - public StringBuilder printStatement(int indent, StringBuilder output) { - - return print(indent, output).append(';'); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, scope); - } - this.type.traverse(visitor, scope); - if (this.initialization != null) - this.initialization.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java deleted file mode 100644 index a87fb27..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/RecordPattern.java +++ /dev/null @@ -1,314 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2022, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.List; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel; -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.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -public class RecordPattern extends TypePattern { - - public Pattern[] patterns; - public TypeReference type; - int thenInitStateIndex1 = -1; - int thenInitStateIndex2 = -1; - - /* package */ BranchLabel guardedElseTarget; - - private TypeBinding expectedType; // for record pattern type inference - - public RecordPattern(TypeReference type, int sourceStart, int sourceEnd) { - this.type = type; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - } - @Override - public TypeReference getType() { - return this.type; - } - @Override - public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { - if (!castType.isReifiable()) - return CastExpression.checkUnsafeCast(this, scope, castType, expressionType, match, isNarrowing); - else - return super.checkUnsafeCast(scope, castType, expressionType, match, isNarrowing); - } - @Override - public LocalVariableBinding[] bindingsWhenTrue() { - LocalVariableBinding [] variables = NO_VARIABLES; - for (Pattern p : this.patterns) { - variables = LocalVariableBinding.merge(variables, p.bindingsWhenTrue()); - } - return variables; - } - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - this.thenInitStateIndex1 = currentScope.methodScope().recordInitializationStates(flowInfo); - for (Pattern p : this.patterns) { - flowInfo = p.analyseCode(currentScope, flowContext, flowInfo); - } - flowInfo = flowInfo.safeInitsWhenTrue(); // TODO: is this really needed? - this.thenInitStateIndex2 = currentScope.methodScope().recordInitializationStates(flowInfo); - return flowInfo; - } - @Override - public boolean coversType(TypeBinding t) { - if (TypeBinding.equalsEquals(t, this.resolvedType)) { - // return the already computed value - return this.isTotalTypeNode; - } - if (!t.isRecord()) - return false; - RecordComponentBinding[] components = t.components(); - if (components == null || components.length != this.patterns.length) { - return false; - } - for (int i = 0; i < components.length; i++) { - Pattern p = this.patterns[i]; - RecordComponentBinding componentBinding = components[i]; - if (!p.coversType(componentBinding.type)) { - return false; - } - } - return true; - } - - @Override - public void setExpectedType(TypeBinding expectedType) { - this.expectedType = expectedType; - } - - @Override - public TypeBinding expectedType() { - return this.expectedType; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - - if (this.resolvedType != null) - return this.resolvedType; - - this.type.bits |= ASTNode.IgnoreRawTypeCheck; - this.resolvedType = this.type.resolveType(scope); - - if (!this.resolvedType.isRecord()) { - scope.problemReporter().unexpectedTypeinRecordPattern(this.resolvedType, this.type); - return this.resolvedType; - } - if (this.resolvedType.components().length != this.patterns.length) { - scope.problemReporter().recordPatternSignatureMismatch(this.resolvedType, this); - return this.resolvedType = null; - } - - LocalVariableBinding [] bindings = NO_VARIABLES; - for (Pattern p : this.patterns) { - p.resolveTypeWithBindings(bindings, scope); - bindings = LocalVariableBinding.merge(bindings, p.bindingsWhenTrue()); - } - for (LocalVariableBinding binding : bindings) - binding.useFlag = LocalVariableBinding.USED; // syntactically required even if untouched - - if (this.resolvedType.isRawType()) { - TypeBinding expressionType = expectedType(); - if (expressionType instanceof ReferenceBinding) { - ReferenceBinding binding = inferRecordParameterization(scope, (ReferenceBinding) expressionType); - if (binding == null || !binding.isValidBinding()) { - scope.problemReporter().cannotInferRecordPatternTypes(this); - return this.resolvedType = null; - } - this.resolvedType = binding; - } - } - - if (this.resolvedType == null || !this.resolvedType.isValidBinding()) { - return this.resolvedType; - } - - this.isTotalTypeNode = super.coversType(this.resolvedType); - RecordComponentBinding[] components = this.resolvedType.capture(scope, this.sourceStart, this.sourceEnd).components(); - for (int i = 0; i < components.length; i++) { - Pattern p1 = this.patterns[i]; - if (p1 instanceof TypePattern tp) { - RecordComponentBinding componentBinding = components[i]; - if (p1.getType() == null || p1.getType().isTypeNameVar(scope)) { - if (tp.local.binding != null) // rewrite with the inferred type - tp.local.binding.type = componentBinding.type; - } - TypeBinding expressionType = componentBinding.type; - if (p1.isPatternTypeCompatible(expressionType, scope)) { - p1.isTotalTypeNode = p1.coversType(componentBinding.type); - MethodBinding[] methods = this.resolvedType.getMethods(componentBinding.name); - if (methods != null && methods.length > 0) { - p1.accessorMethod = methods[0]; - } - } - this.isTotalTypeNode &= p1.isTotalTypeNode; - } - } - return this.resolvedType; - } - private ReferenceBinding inferRecordParameterization(BlockScope scope, ReferenceBinding proposedMatchingType) { - InferenceContext18 freshInferenceContext = new InferenceContext18(scope); - try { - return freshInferenceContext.inferRecordPatternParameterization(this, scope, proposedMatchingType); - } finally { - freshInferenceContext.cleanUp(); - } - } - @Override - public boolean isAlwaysTrue() { - return false; - } - @Override - public boolean dominates(Pattern p) { - if (!this.resolvedType.isValidBinding()) - return false; - if (!super.coversType(p.resolvedType)) { - return false; - } - if (p instanceof RecordPattern) { - RecordPattern rp = (RecordPattern) p; - if (this.patterns.length != rp.patterns.length) - return false; - for(int i = 0; i < this.patterns.length; i++) { - if (!this.patterns[i].dominates(rp.patterns[i])) { - return false; - } - } - } - return true; - } - - @Override - public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel) { - - /* JVM Stack on entry - [expression] // && expression instanceof this.resolvedType - JVM stack on exit with successful pattern match or failed match -> [] - Notation: 'R' : record pattern, 'C': component - */ - codeStream.checkcast(this.resolvedType); // [R] - List labels = new ArrayList<>(); - for (int i = 0, length = this.patterns.length; i < length; i++) { - Pattern p = this.patterns[i]; - /* For all but the last component, dup the record instance to use - as receiver for accessor invocation. The last component uses the - original record instance as receiver - leaving the stack drained. - */ - boolean lastComponent = i == length - 1; - if (!lastComponent) - codeStream.dup(); // lastComponent ? [R] : [R, R] - ExceptionLabel exceptionLabel = new ExceptionLabel(codeStream, - TypeBinding.wellKnownType(currentScope, T_JavaLangThrowable)); - exceptionLabel.placeStart(); - codeStream.invoke(Opcodes.OPC_invokevirtual, p.accessorMethod.original(), this.resolvedType, null); - // lastComponent ? [C] : [R, C] - exceptionLabel.placeEnd(); - labels.add(exceptionLabel); - - if (TypeBinding.notEquals(p.accessorMethod.original().returnType.erasure(), - p.accessorMethod.returnType.erasure())) - codeStream.checkcast(p.accessorMethod.returnType); // lastComponent ? [C] : [R, C] - if (p instanceof RecordPattern || !p.isTotalTypeNode) { - codeStream.dup(); // lastComponent ? [C, C] : [R, C, C] - codeStream.instance_of(p.resolvedType); // lastComponent ? [C, boolean] : [R, C, boolean] - BranchLabel target = falseLabel != null ? falseLabel : new BranchLabel(codeStream); - BranchLabel innerTruthLabel = new BranchLabel(codeStream); - codeStream.ifne(innerTruthLabel); // lastComponent ? [C] : [R, C] - int pops = 1; // Not going to store into the component pattern binding, so need to pop, the duped value. - Pattern current = p; - RecordPattern outer = this; - while (outer != null) { - if (current.index != outer.patterns.length - 1) - pops++; - current = outer; - outer = outer.getEnclosingPattern() instanceof RecordPattern rp ? rp : null; - } - while (pops > 1) { - codeStream.pop2(); - pops -= 2; - } - if (pops > 0) - codeStream.pop(); - - codeStream.goto_(target); - innerTruthLabel.place(); - } - p.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel); - } - - if (labels.size() > 0) { - BlockScope trapScope = codeStream.accessorExceptionTrapScopes.peek(); - List eLabels = codeStream.patternAccessorMap.get(trapScope); - if (eLabels == null || eLabels.isEmpty()) { - eLabels = labels; - } else { - eLabels.addAll(labels); - } - codeStream.patternAccessorMap.put(trapScope, eLabels); - } - if (this.thenInitStateIndex2 != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex2); - codeStream.addDefinitelyAssignedVariables(currentScope, this.thenInitStateIndex2); - } - } - - @Override - public void suspendVariables(CodeStream codeStream, BlockScope scope) { - codeStream.removeNotDefinitelyAssignedVariables(scope, this.thenInitStateIndex1); - } - @Override - public void resumeVariables(CodeStream codeStream, BlockScope scope) { - codeStream.addDefinitelyAssignedVariables(scope, this.thenInitStateIndex2); - } - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.type != null) { - this.type.traverse(visitor, scope); - } - for (Pattern p : this.patterns) { - p.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - output.append(this.type).append('('); - if (this.patterns != null) { - for (int i = 0; i < this.patterns.length; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - this.patterns[i].print(0, output); - } - } - output.append(')'); - return output; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Reference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Reference.java deleted file mode 100644 index c50f5aa..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Reference.java +++ /dev/null @@ -1,240 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 185682 - Increment/decrement operators mark local variables as read - * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 411964 - [1.8][null] leverage null type annotation in foreach statement - * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -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.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -public abstract class Reference extends Expression { -/** - * BaseLevelReference constructor comment. - */ -public Reference() { - super(); -} -public abstract FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound); - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return flowInfo; -} - -@Override -public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - if (flowContext.isNullcheckedFieldAccess(this)) { - return true; // enough seen - } - return super.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck); -} - -protected boolean checkNullableFieldDereference(Scope scope, FieldBinding field, long sourcePosition, FlowContext flowContext, int ttlForFieldCheck) { - if (field != null) { - if (ttlForFieldCheck > 0 && scope.compilerOptions().enableSyntacticNullAnalysisForFields) - flowContext.recordNullCheckedFieldReference(this, ttlForFieldCheck); - // preference to type annotations if we have any - if ((field.type.tagBits & TagBits.AnnotationNullable) != 0) { - scope.problemReporter().dereferencingNullableExpression(sourcePosition, scope.environment()); - return true; - } - if (field.type.isFreeTypeVariable()) { - scope.problemReporter().fieldFreeTypeVariableReference(field, sourcePosition); - return true; - } - if ((field.tagBits & TagBits.AnnotationNullable) != 0) { - scope.problemReporter().nullableFieldDereference(field, sourcePosition); - return true; - } - } - return false; -} - -public FieldBinding fieldBinding() { - //this method should be sent one FIELD-tagged references - // (ref.bits & BindingIds.FIELD != 0)() - return null ; -} - -public void fieldStore(Scope currentScope, CodeStream codeStream, FieldBinding fieldBinding, MethodBinding syntheticWriteAccessor, TypeBinding receiverType, boolean isImplicitThisReceiver, boolean valueRequired) { - int pc = codeStream.position; - if (fieldBinding.isStatic()) { - if (valueRequired) { - switch (fieldBinding.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2(); - break; - default : - codeStream.dup(); - break; - } - } - if (syntheticWriteAccessor == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, fieldBinding, receiverType, isImplicitThisReceiver); - codeStream.fieldAccess(Opcodes.OPC_putstatic, fieldBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, syntheticWriteAccessor, null /* default declaringClass */); - } - } else { // Stack: [owner][new field value] ---> [new field value][owner][new field value] - if (valueRequired) { - switch (fieldBinding.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2_x1(); - break; - default : - codeStream.dup_x1(); - break; - } - } - if (syntheticWriteAccessor == null) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, fieldBinding, receiverType, isImplicitThisReceiver); - codeStream.fieldAccess(Opcodes.OPC_putfield, fieldBinding, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, syntheticWriteAccessor, null /* default declaringClass */); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -public abstract void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired); - -public abstract void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired); - -public abstract void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired); - -/** - * Is the given reference equivalent to the receiver, - * meaning that both denote the same path of field reads? - * Used from {@link FlowContext#isNullcheckedFieldAccess(Reference)}. - */ -public boolean isEquivalent(Reference reference) { - return false; -} - -public FieldBinding lastFieldBinding() { - // override to answer the field designated by the entire reference - // (as opposed to fieldBinding() which answers the first field in a QNR) - return null; -} - -@Override -public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - if ((this.implicitConversion & TypeIds.BOXING) != 0) - return FlowInfo.NON_NULL; - FieldBinding fieldBinding = lastFieldBinding(); - if (fieldBinding != null) { - if (fieldBinding.isFinal() && fieldBinding.constant() != Constant.NotAConstant) - return FlowInfo.NON_NULL; - if (fieldBinding.isNonNull() || flowContext.isNullcheckedFieldAccess(this)) { - return FlowInfo.NON_NULL; - } else if (fieldBinding.isNullable()) { - return FlowInfo.POTENTIALLY_NULL; - } else if (fieldBinding.type.isFreeTypeVariable()) { - return FlowInfo.FREE_TYPEVARIABLE; - } - } - if (this.resolvedType != null) { - return FlowInfo.tagBitsToNullStatus(this.resolvedType.tagBits); - } - return FlowInfo.UNKNOWN; -} - -/* report if a private field is only read from a 'special operator', - * i.e., in a postIncrement expression or a compound assignment, - * where the information is never flowing out off the field. */ -void reportOnlyUselesslyReadPrivateField(BlockScope currentScope, FieldBinding fieldBinding, boolean valueRequired) { - if (valueRequired) { - // access is relevant, turn compound use into real use: - fieldBinding.compoundUseFlag = 0; - fieldBinding.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } else { - if (fieldBinding.isUsedOnlyInCompound()) { - fieldBinding.compoundUseFlag--; // consume one - if (fieldBinding.compoundUseFlag == 0 // report only the last usage - && fieldBinding.isOrEnclosedByPrivateType() - && (this.implicitConversion & TypeIds.UNBOXING) == 0) // don't report if unboxing is involved (might cause NPE) - { - // compoundAssignment/postIncrement is the only usage of this field - currentScope.problemReporter().unusedPrivateField(fieldBinding.sourceField()); - } - } - } -} -/* report a local/arg that is only read from a 'special operator', - * i.e., in a postIncrement expression or a compound assignment, - * where the information is never flowing out off the local/arg. */ -static void reportOnlyUselesslyReadLocal(BlockScope currentScope, LocalVariableBinding localBinding, boolean valueRequired) { - if (localBinding.declaration == null) - return; // secret local - if ((localBinding.declaration.bits & ASTNode.IsLocalDeclarationReachable) == 0) - return; // declaration is unreachable - if (localBinding.useFlag >= LocalVariableBinding.USED) - return; // we're only interested in cases with only compound access (negative count) - - if (valueRequired) { - // access is relevant - localBinding.useFlag = LocalVariableBinding.USED; - return; - } else { - localBinding.useFlag++; - if (localBinding.useFlag != LocalVariableBinding.UNUSED) // have all negative counts been consumed? - return; // still waiting to see more usages of this kind - } - // at this point we know we have something to report - if (localBinding.declaration instanceof Argument) { - // check compiler options to report against unused arguments - MethodScope methodScope = currentScope.methodScope(); - if (methodScope != null && !methodScope.isLambdaScope()) { // lambda must be congruent with the descriptor. - MethodBinding method = ((AbstractMethodDeclaration)methodScope.referenceContext()).binding; - - boolean shouldReport = !method.isMain(); - if (method.isImplementing()) { - shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenImplementingAbstract; - } else if (method.isOverriding()) { - shouldReport &= currentScope.compilerOptions().reportUnusedParameterWhenOverridingConcrete; - } - - if (shouldReport) { - // report the case of an argument that is unread except through a special operator - currentScope.problemReporter().unusedArgument(localBinding.declaration); - } - } - } else { - // report the case of a local variable that is unread except for a special operator - currentScope.problemReporter().unusedLocalVariable(localBinding.declaration); - } -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java deleted file mode 100644 index 41c1a5f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java +++ /dev/null @@ -1,1339 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Jesper S Moller - Contributions for - * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression - * Bug 384687 - [1.8] Wildcard type arguments should be rejected for lambda and reference expressions - * Bug 416885 - [1.8][compiler]IncompatibleClassChange error (edit) - * Stephan Herrmann - Contribution for - * bug 402028 - [1.8][compiler] null analysis for reference expressions - * bug 404649 - [1.8][compiler] detect illegal reference to indirect or redundant super via I.super.m() syntax - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 423504 - [1.8] Implement "18.5.3 Functional Interface Parameterization Inference" - * Bug 424637 - [1.8][compiler][null] AIOOB in ReferenceExpression.resolveType with a method reference to Files::walk - * Bug 424415 - [1.8][compiler] Eventual resolution of ReferenceExpression is not seen to be happening. - * Bug 424403 - [1.8][compiler] Generic method call with method reference argument fails to resolve properly. - * Bug 427196 - [1.8][compiler] Compiler error for method reference to overloaded method - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 428264 - [1.8] method reference of generic class causes problems (wrong inference result or NPE) - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 426537 - [1.8][inference] Eclipse compiler thinks I is compatible with I> - raw type J involved - * Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" - * Bug 435689 - [1.8][inference] Type inference not occurring with lambda expression and method reference - * Bug 438383 - [1.8][null] Bogus warning: Null type safety at method return type - * Bug 434483 - [1.8][compiler][inference] Type inference not picked up with method reference - * Bug 441734 - [1.8][inference] Generic method with nested parameterized type argument fails on method reference - * Bug 438945 - [1.8] NullPointerException InferenceContext18.checkExpression in java 8 with generics, primitives, and overloading - * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression - * Bug 448709 - [1.8][null] ensure we don't infer types that violate null constraints on a type parameter's bound - * Bug 459967 - [null] compiler should know about nullness of special methods like MyEnum.valueOf() - * Bug 466713 - Null Annotations: NullPointerException using as Type Param - * Bug 470542 - NullPointerException in ReferenceExpression.isPotentiallyCompatibleWith (962) - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contribution for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.INVOCATION_CONTEXT; - -import java.util.HashMap; -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationPosition; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; -import org.eclipse.jdt.internal.compiler.codegen.Opcodes; -import org.eclipse.jdt.internal.compiler.flow.FieldInitsFakingFlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.flow.UnconditionalFlowInfo; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.IrritantSet; -import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.ImplicitNullAnnotationVerifier; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18; -import org.eclipse.jdt.internal.compiler.lookup.InvocationSite; -import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -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.SyntheticArgumentBinding; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; -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.parser.Parser; -import org.eclipse.jdt.internal.compiler.parser.Scanner; - -public class ReferenceExpression extends FunctionalExpression implements IPolyExpression, InvocationSite { - // secret variable name - private static final String SecretReceiverVariableName = " rec_"; //$NON-NLS-1$ - private static final char[] ImplicitArgName = " arg".toCharArray(); //$NON-NLS-1$ - // secret variable for codegen - public LocalVariableBinding receiverVariable; - public Expression lhs; - public TypeReference [] typeArguments; - public char [] selector; - - public int nameSourceStart; - - public TypeBinding receiverType; - public boolean haveReceiver; - public TypeBinding[] resolvedTypeArguments; - private boolean typeArgumentsHaveErrors; - - MethodBinding syntheticAccessor; // synthetic accessor for inner-emulation - private int depth; - private MethodBinding exactMethodBinding; // != null ==> exact method reference. - private boolean receiverPrecedesParameters = false; - private TypeBinding[] freeParameters; // descriptor parameters as used for method lookup - may or may not include the receiver - private boolean checkingPotentialCompatibility; - private MethodBinding[] potentialMethods = Binding.NO_METHODS; - protected ReferenceExpression original; - private HashMap copiesPerTargetType; - private HashMap inferenceContexts; - - // the scanner used when creating this expression, may be a RecoveryScanner (with proper RecoveryScannerData), - // need to keep it so copy() can parse in the same mode (normal/recovery): - private Scanner scanner; - - public ReferenceExpression(Scanner scanner) { - super(); - this.original = this; - this.scanner = scanner; - } - - public void initialize(CompilationResult result, Expression expression, TypeReference [] optionalTypeArguments, char [] identifierOrNew, int sourceEndPosition) { - super.setCompilationResult(result); - this.lhs = expression; - this.typeArguments = optionalTypeArguments; - this.selector = identifierOrNew; - this.sourceStart = expression.sourceStart; - this.sourceEnd = sourceEndPosition; - } - - /** - * @return a virgin copy of `this' by reparsing the stashed textual form. - */ - private ReferenceExpression copy() { - final Parser parser = new Parser(this.enclosingScope.problemReporter(), false); - char [] source = new char [this.sourceEnd+1]; - System.arraycopy(this.text, 0, source, this.sourceStart, this.sourceEnd - this.sourceStart + 1); - parser.scanner = this.scanner; - ReferenceExpression copy = (ReferenceExpression) parser.parseExpression(source, this.sourceStart, this.sourceEnd - this.sourceStart + 1, - this.enclosingScope.referenceCompilationUnit(), false /* record line separators */); - copy.original = this; - copy.sourceStart = this.sourceStart; - copy.sourceEnd = this.sourceEnd; - copy.text = this.text; - return copy; - } - - private boolean shouldGenerateSecretReceiverVariable() { - if (isMethodReference() && this.haveReceiver) { - if (this.lhs instanceof Invocation) - return true; - else { - return new ASTVisitor() { - boolean accessesnonFinalOuterLocals; - - @Override - public boolean visit(SingleNameReference name, BlockScope skope) { - Binding local = skope.getBinding(name.getName(), ReferenceExpression.this); - if (local instanceof LocalVariableBinding) { - LocalVariableBinding localBinding = (LocalVariableBinding) local; - if (!localBinding.isFinal() && !localBinding.isEffectivelyFinal()) { - this.accessesnonFinalOuterLocals = true; - } - } - return false; - } - - public boolean accessesnonFinalOuterLocals() { - ReferenceExpression.this.lhs.traverse(this, ReferenceExpression.this.enclosingScope); - return this.accessesnonFinalOuterLocals; - } - }.accessesnonFinalOuterLocals(); - } - } - return false; - } - public void generateImplicitLambda(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - - ReferenceExpression copy = copy(); - - int argc = this.descriptor.parameters.length; - - LambdaExpression implicitLambda = new LambdaExpression(this.compilationResult, false, (this.binding.modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0); - Argument [] arguments = new Argument[argc]; - for (int i = 0; i < argc; i++) - arguments[i] = new Argument(CharOperation.append(ImplicitArgName, Integer.toString(i).toCharArray()), 0, null, 0, true); - implicitLambda.setArguments(arguments); - implicitLambda.setExpressionContext(this.expressionContext); - implicitLambda.setExpectedType(this.expectedType); - - int parameterShift = this.receiverPrecedesParameters ? 1 : 0; - Expression [] argv = new SingleNameReference[argc - parameterShift]; - for (int i = 0, length = argv.length; i < length; i++) { - char[] name = CharOperation.append(ImplicitArgName, Integer.toString((i + parameterShift)).toCharArray()); - argv[i] = new SingleNameReference(name, 0); - } - boolean generateSecretReceiverVariable = shouldGenerateSecretReceiverVariable(); - LocalVariableBinding[] patternVariablesInScope = NO_VARIABLES; - if (isMethodReference()) { - if (generateSecretReceiverVariable) { - this.lhs.generateCode(currentScope, codeStream, true); - codeStream.store(this.receiverVariable, false); - codeStream.addVariable(this.receiverVariable); - } - MessageSend message = new MessageSend(); - message.selector = this.selector; - Expression receiver = generateSecretReceiverVariable ? new SingleNameReference(this.receiverVariable.name, 0) : copy.lhs; - if (this.lhs instanceof NameReference nr - && nr.binding instanceof LocalVariableBinding receiverLocal - && receiverLocal.isValidBinding() - && (receiverLocal.modifiers & ExtraCompilerModifiers.AccOutOfFlowScope) != 0) { - // what was in scope during initial resolve must be in scope during resolve of synthetic AST, too: - patternVariablesInScope = new LocalVariableBinding[] { receiverLocal }; - } - message.receiver = this.receiverPrecedesParameters ? - new SingleNameReference(CharOperation.append(ImplicitArgName, Integer.toString(0).toCharArray()), 0) : receiver; - message.typeArguments = copy.typeArguments; - message.arguments = argv; - implicitLambda.setBody(message); - } else if (isArrayConstructorReference()) { - // We don't care for annotations, source positions etc. They are immaterial, just drop. - ArrayAllocationExpression arrayAllocationExpression = new ArrayAllocationExpression(); - arrayAllocationExpression.dimensions = new Expression[] { argv[0] }; - if (this.lhs instanceof ArrayTypeReference) { - ArrayTypeReference arrayTypeReference = (ArrayTypeReference) this.lhs; - arrayAllocationExpression.type = arrayTypeReference.dimensions == 1 ? new SingleTypeReference(arrayTypeReference.token, 0L) : - new ArrayTypeReference(arrayTypeReference.token, arrayTypeReference.dimensions - 1, 0L); - } else { - ArrayQualifiedTypeReference arrayQualifiedTypeReference = (ArrayQualifiedTypeReference) this.lhs; - arrayAllocationExpression.type = arrayQualifiedTypeReference.dimensions == 1 ? new QualifiedTypeReference(arrayQualifiedTypeReference.tokens, arrayQualifiedTypeReference.sourcePositions) - : new ArrayQualifiedTypeReference(arrayQualifiedTypeReference.tokens, arrayQualifiedTypeReference.dimensions - 1, - arrayQualifiedTypeReference.sourcePositions); - } - implicitLambda.setBody(arrayAllocationExpression); - } else { - AllocationExpression allocation = new AllocationExpression(); - if (this.lhs instanceof TypeReference) { - allocation.type = (TypeReference) this.lhs; - } else if (this.lhs instanceof SingleNameReference) { - allocation.type = new SingleTypeReference(((SingleNameReference) this.lhs).token, 0); - } else if (this.lhs instanceof QualifiedNameReference) { - allocation.type = new QualifiedTypeReference(((QualifiedNameReference) this.lhs).tokens, new long [((QualifiedNameReference) this.lhs).tokens.length]); - } else { - throw new IllegalStateException("Unexpected node type"); //$NON-NLS-1$ - } - allocation.typeArguments = copy.typeArguments; - allocation.arguments = argv; - implicitLambda.setBody(allocation); - } - - // Process the lambda, taking care not to double report diagnostics. Don't expect any from resolve, Any from code generation should surface, but not those from flow analysis. - BlockScope lambdaScope = this.receiverVariable != null ? this.receiverVariable.declaringScope : currentScope; - IErrorHandlingPolicy oldPolicy = lambdaScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy); - try { - implicitLambda.resolveTypeWithBindings(patternVariablesInScope, lambdaScope, true); - implicitLambda.analyseCode(lambdaScope, - new FieldInitsFakingFlowContext(null, this, Binding.NO_EXCEPTIONS, null, lambdaScope, FlowInfo.DEAD_END), - UnconditionalFlowInfo.fakeInitializedFlowInfo(implicitLambda.firstLocalLocal, lambdaScope.referenceType().maxFieldCount)); - } finally { - lambdaScope.problemReporter().switchErrorHandlingPolicy(oldPolicy); - } - SyntheticArgumentBinding[] outerLocals = this.receiverType.syntheticOuterLocalVariables(); - for (int i = 0, length = outerLocals == null ? 0 : outerLocals.length; i < length; i++) - implicitLambda.addSyntheticArgument(outerLocals[i].actualOuterLocalVariable); - - implicitLambda.generateCode(lambdaScope, codeStream, valueRequired); - if (generateSecretReceiverVariable) { - codeStream.removeVariable(this.receiverVariable); - } - } - - private boolean shouldGenerateImplicitLambda(BlockScope currentScope) { - // these cases are either too complicated, impossible to handle or result in significant code duplication - return (this.binding.isVarargs() || - (isConstructorReference() && (this.receiverType.syntheticOuterLocalVariables() != null || this.shouldCaptureInstance)) || - this.requiresBridges() || // bridges. - !isDirectCodeGenPossible()); - // To fix: We should opt for direct code generation wherever possible. - } - private boolean isDirectCodeGenPossible() { - if (this.binding != null) { - if (isMethodReference() && this.syntheticAccessor == null) { - if (TypeBinding.notEquals(this.binding.declaringClass, this.lhs.resolvedType.erasure())) { - // reference to a method declared by an inaccessible type accessed via a - // subtype - normally a bridge method would be present to facilitate - // this access, unless the method is final/static/default, in which case, direct access to - // the method is not possible, an implicit lambda is needed - if (!this.binding.declaringClass.canBeSeenBy(this.enclosingScope)) { - if (this.binding.isDefaultMethod()) - return false; // workaround for bug in MethodHandle lookup, see https://bugs.openjdk.java.net/browse/JDK-8068253 - return !(this.binding.isFinal() || this.binding.isStatic()); - } - } - } - TypeBinding[] descriptorParams = this.descriptor.parameters; - if (descriptorParams.length > 0) { - TypeBinding[] origParams = this.binding.original().parameters; - TypeBinding[] origDescParams = this.descriptor.original().parameters; - for (int i = 0; i < descriptorParams.length; i++) { - TypeBinding descType = descriptorParams[i]; - TypeBinding origDescType = origDescParams[i]; - if (descType.isIntersectionType18() - || (descType.isTypeVariable() && ((TypeVariableBinding) descType).boundsCount() > 1)) { - boolean varargs = this.binding.original().isVarargs(); - TypeBinding origParam = this.receiverPrecedesParameters - ? i == 0 ? this.receiverType : InferenceContext18.getParameter(origParams, i-1, varargs) - : InferenceContext18.getParameter(origParams, i, varargs); - if (!CharOperation.equals(origDescType.signature(), origParam.signature())) - return false; - } - } - } else if (this.haveReceiver) { - if (this.receiverType.isIntersectionType18() - || (this.receiverType.isTypeVariable() && ((TypeVariableBinding) this.receiverType).boundsCount() > 1)) { - if (!CharOperation.equals(this.binding.original().declaringClass.signature(), this.receiverType.signature())) - return false; - } - } - } - return true; - } - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - this.actualMethodBinding = this.binding; // grab before synthetics come into play. - // Handle some special cases up front and transform them into implicit lambdas. - if (shouldGenerateImplicitLambda(currentScope)) { - generateImplicitLambda(currentScope, codeStream, valueRequired); - return; - } - SourceTypeBinding sourceType = currentScope.enclosingSourceType(); - if (this.receiverType.isArrayType()) { - char [] lambdaName = CharOperation.concat(TypeConstants.ANONYMOUS_METHOD, Integer.toString(this.ordinal).toCharArray()); - if (isConstructorReference()) { - this.actualMethodBinding = this.binding = sourceType.addSyntheticArrayMethod((ArrayBinding) this.receiverType, SyntheticMethodBinding.ArrayConstructor, lambdaName); - } else if (CharOperation.equals(this.selector, TypeConstants.CLONE)) { - this.actualMethodBinding = this.binding = sourceType.addSyntheticArrayMethod((ArrayBinding) this.receiverType, SyntheticMethodBinding.ArrayClone, lambdaName); - } - } else if (this.syntheticAccessor != null) { - if (this.lhs.isSuper() || isMethodReference()) - this.binding = this.syntheticAccessor; - } else { // cf. MessageSend.generateCode()'s call to CodeStream.getConstantPoolDeclaringClass. We have extracted the relevant portions sans side effect here. - if (this.binding != null && isMethodReference()) { - if (TypeBinding.notEquals(this.binding.declaringClass, this.lhs.resolvedType.erasure())) { - if (!this.binding.declaringClass.canBeSeenBy(currentScope)) { - this.binding = new MethodBinding(this.binding.original(), (ReferenceBinding) this.lhs.resolvedType.erasure()); - } - } - } - } - int pc = codeStream.position; - StringBuilder buffer = new StringBuilder(); - int argumentsSize = 0; - buffer.append('('); - if (this.haveReceiver) { - this.lhs.generateCode(currentScope, codeStream, true); - if (isMethodReference() && !this.lhs.isThis() && !this.lhs.isSuper()) { - MethodBinding mb = currentScope.getJavaLangObject().getExactMethod(TypeConstants.GETCLASS, - Binding.NO_PARAMETERS, currentScope.compilationUnitScope()); - codeStream.dup(); - codeStream.invoke(Opcodes.OPC_invokevirtual, mb, mb.declaringClass); - codeStream.pop(); - } - if (this.lhs.isSuper() && !this.actualMethodBinding.isPrivate()) { - if (this.lhs instanceof QualifiedSuperReference) { - QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) this.lhs; - TypeReference qualification = qualifiedSuperReference.qualification; - if (qualification.resolvedType.isInterface()) { - buffer.append(sourceType.signature()); - } else { - buffer.append(((QualifiedSuperReference) this.lhs).currentCompatibleType.signature()); - } - } else { - buffer.append(sourceType.signature()); - } - } else { - buffer.append(this.receiverType.signature()); - } - argumentsSize = 1; - } else { - if (this.isConstructorReference()) { - ReferenceBinding[] enclosingInstances = Binding.UNINITIALIZED_REFERENCE_TYPES; - if (this.receiverType.isNestedType()) { - ReferenceBinding nestedType = (ReferenceBinding) this.receiverType; - if ((enclosingInstances = nestedType.syntheticEnclosingInstanceTypes()) != null) { - int length = enclosingInstances.length; - argumentsSize = length; - for (int i = 0 ; i < length; i++) { - ReferenceBinding syntheticArgumentType = enclosingInstances[i]; - buffer.append(syntheticArgumentType.signature()); - Object[] emulationPath = currentScope.getEmulationPath( - syntheticArgumentType, - false /* allow compatible match */, - true /* disallow instance reference in explicit constructor call */); - codeStream.generateOuterAccess(emulationPath, this, syntheticArgumentType, currentScope); - } - } else { - enclosingInstances = Binding.NO_REFERENCE_TYPES; - } - } - if (this.syntheticAccessor != null) { - char [] lambdaName = CharOperation.concat(TypeConstants.ANONYMOUS_METHOD, Integer.toString(this.ordinal).toCharArray()); - this.binding = sourceType.addSyntheticFactoryMethod(this.binding, this.syntheticAccessor, enclosingInstances, lambdaName); - this.syntheticAccessor = null; // add only once - } - } - } - buffer.append(')'); - buffer.append('L'); - if (this.resolvedType.isIntersectionType18()) { - buffer.append(this.descriptor.declaringClass.constantPoolName()); - } else { - buffer.append(this.resolvedType.constantPoolName()); - } - buffer.append(';'); - if (this.isSerializable) { - sourceType.addSyntheticMethod(this); - } - int invokeDynamicNumber = codeStream.classFile.recordBootstrapMethod(this); - codeStream.invokeDynamic(invokeDynamicNumber, argumentsSize, 1, this.descriptor.selector, buffer.toString().toCharArray(), - this.isConstructorReference(), (this.lhs instanceof TypeReference? (TypeReference) this.lhs : null), this.typeArguments, - this.resolvedType.id, this.resolvedType); - if (!valueRequired) - codeStream.pop(); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public void cleanUp() { - // no more rescanning needed beyond this point, so free the memory: - if (this.copiesPerTargetType != null) { - for (ReferenceExpression copy : this.copiesPerTargetType.values()) - copy.scanner = null; - } - if (this.original != null && this.original != this) { - this.original.cleanUp(); - } - this.scanner = null; - this.receiverVariable = null; - } - - public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 || this.binding == null || !this.binding.isValidBinding()) - return; - - MethodBinding codegenBinding = this.binding.original(); - if (codegenBinding.isVarargs()) - return; // completely managed by transforming into implicit lambda expression. - - SourceTypeBinding enclosingSourceType = currentScope.enclosingSourceType(); - - if (this.isConstructorReference()) { - ReferenceBinding allocatedType = codegenBinding.declaringClass; - if (codegenBinding.isPrivate() && - TypeBinding.notEquals(enclosingSourceType, (allocatedType = codegenBinding.declaringClass))) { - if ((allocatedType.tagBits & TagBits.IsLocalType) != 0) { - codegenBinding.tagBits |= TagBits.ClearPrivateModifier; - } else { - if (currentScope.enclosingSourceType().isNestmateOf(this.binding.declaringClass)) { - this.syntheticAccessor = codegenBinding; - return; - } - this.syntheticAccessor = ((SourceTypeBinding) allocatedType).addSyntheticMethod(codegenBinding, false); - currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this); - } - } - return; - } - - // ----------------------------------- Only method references from now on ----------- - if (this.binding.isPrivate()) { - if (TypeBinding.notEquals(enclosingSourceType, codegenBinding.declaringClass)){ - this.syntheticAccessor = ((SourceTypeBinding)codegenBinding.declaringClass).addSyntheticMethod(codegenBinding, false /* not super access */); - currentScope.problemReporter().checkSyntheticAccessor(codegenBinding, this); - } - return; - } - - if (this.lhs.isSuper()) { - SourceTypeBinding destinationType = enclosingSourceType; - if (this.lhs instanceof QualifiedSuperReference) { // qualified super - QualifiedSuperReference qualifiedSuperReference = (QualifiedSuperReference) this.lhs; - TypeReference qualification = qualifiedSuperReference.qualification; - if (!qualification.resolvedType.isInterface()) // we can't drop the bridge in I, it may not even be a source type. - destinationType = (SourceTypeBinding) (qualifiedSuperReference.currentCompatibleType); - } - - this.syntheticAccessor = destinationType.addSyntheticMethod(codegenBinding, true); - currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this); - return; - } - - if (this.binding.isProtected() && (this.bits & ASTNode.DepthMASK) != 0 && codegenBinding.declaringClass.getPackage() != enclosingSourceType.getPackage()) { - SourceTypeBinding currentCompatibleType = (SourceTypeBinding) enclosingSourceType.enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); - this.syntheticAccessor = currentCompatibleType.addSyntheticMethod(codegenBinding, isSuperAccess()); - currentScope.problemReporter().needToEmulateMethodAccess(codegenBinding, this); - return; - } - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // static methods with receiver value never get here - if (this.haveReceiver) { - this.lhs.analyseCode(currentScope, flowContext, flowInfo, true); - this.lhs.checkNPE(currentScope, flowContext, flowInfo); - } else if (isConstructorReference()) { - TypeBinding type = this.receiverType.leafComponentType(); - if (type.isNestedType() && - type instanceof ReferenceBinding && !((ReferenceBinding)type).isStatic()) { - currentScope.tagAsAccessingEnclosingInstanceStateOf((ReferenceBinding)type, false); - this.shouldCaptureInstance = true; - ReferenceBinding allocatedTypeErasure = (ReferenceBinding) type.erasure(); - if (allocatedTypeErasure.isLocalType()) { - ((LocalTypeBinding) allocatedTypeErasure).addInnerEmulationDependent(currentScope, false); - // request cascade of accesses - } - } - } - CompilerOptions compilerOptions = currentScope.compilerOptions(); - if (compilerOptions.isAnyEnabled(IrritantSet.UNLIKELY_ARGUMENT_TYPE) && this.binding.isValidBinding() - && this.binding != null && this.binding.parameters != null) { - if (this.binding.parameters.length == 1 - && this.descriptor.parameters.length == (this.receiverPrecedesParameters ? 2 : 1) - && !this.binding.isStatic()) { - final TypeBinding argumentType = this.descriptor.parameters[this.receiverPrecedesParameters ? 1 : 0]; - final TypeBinding actualReceiverType = this.receiverPrecedesParameters ? this.descriptor.parameters[0] : this.binding.declaringClass; - UnlikelyArgumentCheck argumentCheck = UnlikelyArgumentCheck - .determineCheckForNonStaticSingleArgumentMethod(argumentType, currentScope, this.selector, - actualReceiverType, this.binding.parameters); - if (argumentCheck != null && argumentCheck.isDangerous(currentScope)) { - currentScope.problemReporter().unlikelyArgumentType(this, this.binding, argumentType, - argumentCheck.typeToReport, argumentCheck.dangerousMethod); - } - } else if (this.binding.parameters.length == 2 && this.descriptor.parameters.length == 2 && this.binding.isStatic()) { - final TypeBinding argumentType1 = this.descriptor.parameters[0]; - final TypeBinding argumentType2 = this.descriptor.parameters[1]; - UnlikelyArgumentCheck argumentCheck = UnlikelyArgumentCheck - .determineCheckForStaticTwoArgumentMethod(argumentType2, currentScope, this.selector, - argumentType1, this.binding.parameters, this.receiverType); - if (argumentCheck != null && argumentCheck.isDangerous(currentScope)) { - currentScope.problemReporter().unlikelyArgumentType(this, this.binding, argumentType2, - argumentCheck.typeToReport, argumentCheck.dangerousMethod); - } - } - } - - if (compilerOptions.analyseResourceLeaks) { - if (this.haveReceiver && CharOperation.equals(this.selector, TypeConstants.CLOSE)) { - FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.lhs, flowInfo, flowContext, compilerOptions.isAnnotationBasedResourceAnalysisEnabled); - if (trackingVariable != null) { // null happens if target is not a local variable or not an AutoCloseable - trackingVariable.markClosedInNestedMethod(); // there is a close()-call, but we don't know if it will be invoked - } - } - } - manageSyntheticAccessIfNecessary(currentScope, flowInfo); - return flowInfo; - } - - @Override - public boolean checkingPotentialCompatibility() { - return this.checkingPotentialCompatibility; - } - - @Override - public void acceptPotentiallyCompatibleMethods(MethodBinding[] methods) { - if (this.checkingPotentialCompatibility) - this.potentialMethods = methods; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - - final CompilerOptions compilerOptions = scope.compilerOptions(); - TypeBinding lhsType; - if (this.constant != Constant.NotAConstant) { - this.constant = Constant.NotAConstant; - this.enclosingScope = scope; - if (this.original == this) - this.ordinal = recordFunctionalType(scope); - - this.lhs.bits |= ASTNode.IgnoreRawTypeCheck; - lhsType = this.lhs.resolveType(scope); - this.lhs.computeConversion(scope, lhsType, lhsType); - if (this.typeArguments != null) { - int length = this.typeArguments.length; - this.typeArgumentsHaveErrors = compilerOptions.sourceLevel < ClassFileConstants.JDK1_5; - this.resolvedTypeArguments = new TypeBinding[length]; - for (int i = 0; i < length; i++) { - TypeReference typeReference = this.typeArguments[i]; - if ((this.resolvedTypeArguments[i] = typeReference.resolveType(scope, true /* check bounds*/)) == null) { - this.typeArgumentsHaveErrors = true; - } - if (this.typeArgumentsHaveErrors && typeReference instanceof Wildcard) { // resolveType on wildcard always return null above, resolveTypeArgument is the real workhorse. - scope.problemReporter().illegalUsageOfWildcard(typeReference); - } - } - if (this.typeArgumentsHaveErrors || lhsType == null) - return this.resolvedType = null; - if (isConstructorReference() && lhsType.isRawType()) { - scope.problemReporter().rawConstructorReferenceNotWithExplicitTypeArguments(this.typeArguments); - return this.resolvedType = null; - } - } - if (this.typeArgumentsHaveErrors || lhsType == null) - return this.resolvedType = null; - - if (lhsType.problemId() == ProblemReasons.AttemptToBypassDirectSuper) - lhsType = lhsType.closestMatch(); // improve resolving experience - if (lhsType == null || !lhsType.isValidBinding()) - return this.resolvedType = null; // nope, no useful type found - - this.receiverType = lhsType; - this.haveReceiver = true; - if (this.lhs instanceof NameReference) { - if ((this.lhs.bits & ASTNode.RestrictiveFlagMASK) == Binding.TYPE) { - this.haveReceiver = false; - } else if (isConstructorReference()) { - scope.problemReporter().invalidType( - this.lhs, - new ProblemReferenceBinding(((NameReference) this.lhs).getName(), null, - ProblemReasons.NotFound)); - return this.resolvedType = null; - } - } else if (this.lhs instanceof TypeReference) { - this.haveReceiver = false; - } - if (!this.haveReceiver && !this.lhs.isSuper() && !this.isArrayConstructorReference()) - this.receiverType = lhsType.capture(scope, this.sourceStart, this.sourceEnd); - - if (!lhsType.isRawType()) // RawType::m and RawType::new are not exact method references - this.binding = this.exactMethodBinding = isMethodReference() ? scope.getExactMethod(lhsType, this.selector, this) : scope.getExactConstructor(lhsType, this); - - if (isConstructorReference() && !lhsType.canBeInstantiated()) { - scope.problemReporter().cannotInstantiate(this.lhs, lhsType); - return this.resolvedType = null; - } - - if (this.lhs instanceof TypeReference && ((TypeReference)this.lhs).hasNullTypeAnnotation(AnnotationPosition.ANY)) { - scope.problemReporter().nullAnnotationUnsupportedLocation((TypeReference) this.lhs); - } - - if (isConstructorReference() && lhsType.isArrayType()) { - final TypeBinding leafComponentType = lhsType.leafComponentType(); - if (!leafComponentType.isReifiable()) { - scope.problemReporter().illegalGenericArray(leafComponentType, this); - return this.resolvedType = null; - } - if (this.typeArguments != null) { - scope.problemReporter().invalidTypeArguments(this.typeArguments); - return this.resolvedType = null; - } - this.binding = this.exactMethodBinding = scope.getExactConstructor(lhsType, this); - } - if (isMethodReference() && this.haveReceiver && (this.original == this)) { - this.receiverVariable = new LocalVariableBinding( - (SecretReceiverVariableName + this.nameSourceStart).toCharArray(), this.lhs.resolvedType, - ClassFileConstants.AccDefault, false); - scope.addLocalVariable(this.receiverVariable); - this.receiverVariable.setConstant(Constant.NotAConstant); // not inlinable - this.receiverVariable.useFlag = LocalVariableBinding.USED; - } - - if (this.expectedType == null && this.expressionContext == INVOCATION_CONTEXT) { - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled && this.binding != null) { - ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope); - } - return new PolyTypeBinding(this); - } - - } else { - lhsType = this.lhs.resolvedType; - if (this.typeArgumentsHaveErrors || lhsType == null) - return this.resolvedType = null; - } - - super.resolveType(scope); - - /* For Reference expressions unlike other call sites, we always have a receiver _type_ since LHS of :: cannot be empty. - LHS's resolved type == actual receiver type. All code below only when a valid descriptor is available. - */ - if (this.descriptor == null || !this.descriptor.isValidBinding()) - return this.resolvedType = null; - - // Convert parameters into argument expressions for look up. - TypeBinding[] descriptorParameters = descriptorParametersAsArgumentExpressions(); - - if (lhsType.isBaseType()) { - scope.problemReporter().errorNoMethodFor(this.lhs, lhsType, this.selector, descriptorParameters); - return this.resolvedType = null; - } - - /* 15.13: "If a method reference expression has the form super :: [TypeArguments] Identifier or TypeName . super :: [TypeArguments] Identifier, - it is a compile-time error if the expression occurs in a static context. ": This is nop since the primary when it resolves - itself will complain automatically. - - 15.13: "The immediately enclosing instance of an inner class instance (15.9.2) must be provided for a constructor reference by a lexically - enclosing instance of this (8.1.3)", we will actually implement this check in code generation. Emulation path computation will fail if there - is no suitable enclosing instance. While this could be pulled up to here, leaving it to code generation is more consistent with Java 5,6,7 - modus operandi. - */ - - // handle the special case of array construction first. - final int parametersLength = descriptorParameters.length; - if (isConstructorReference() && lhsType.isArrayType()) { - if (parametersLength != 1 || scope.parameterCompatibilityLevel(descriptorParameters[0], TypeBinding.INT) == Scope.NOT_COMPATIBLE) { - scope.problemReporter().invalidArrayConstructorReference(this, lhsType, descriptorParameters); - return this.resolvedType = null; - } - if (this.descriptor.returnType.isProperType(true) && !lhsType.isCompatibleWith(this.descriptor.returnType) && this.descriptor.returnType.id != TypeIds.T_void) { - scope.problemReporter().constructedArrayIncompatible(this, lhsType, this.descriptor.returnType); - return this.resolvedType = null; - } - checkNullAnnotations(scope); - return this.resolvedType; - } - - // 15.13.1 - final boolean isMethodReference = isMethodReference(); - this.depth = 0; - this.freeParameters = descriptorParameters; - MethodBinding someMethod = null; - if (isMethodReference) { - someMethod = scope.getMethod(this.receiverType, this.selector, descriptorParameters, this); - } else { - if (argumentsTypeElided() && this.receiverType.isRawType()) { - boolean[] inferredReturnType = new boolean[1]; - someMethod = AllocationExpression.inferDiamondConstructor(scope, this, this.receiverType, this.descriptor.parameters, inferredReturnType); - } - if (someMethod == null) - someMethod = scope.getConstructor((ReferenceBinding) this.receiverType, descriptorParameters, this); - } - int someMethodDepth = this.depth, anotherMethodDepth = 0; - if (someMethod != null && someMethod.isValidBinding()) { - if (someMethod.isStatic() && (this.haveReceiver || this.receiverType.isParameterizedTypeWithActualArguments())) { - scope.problemReporter().methodMustBeAccessedStatically(this, someMethod); - return this.resolvedType = null; - } - } - - if (this.lhs.isSuper() && this.lhs.resolvedType.isInterface()) { - scope.checkAppropriateMethodAgainstSupers(this.selector, someMethod, this.descriptor.parameters, this); - } - - MethodBinding anotherMethod = null; - this.receiverPrecedesParameters = false; - if (!this.haveReceiver && isMethodReference && parametersLength > 0) { - final TypeBinding potentialReceiver = descriptorParameters[0]; - if (potentialReceiver.isCompatibleWith(this.receiverType, scope)) { - TypeBinding typeToSearch = this.receiverType; - if (this.receiverType.isRawType()) { - TypeBinding superType = potentialReceiver.findSuperTypeOriginatingFrom(this.receiverType); - if (superType != null) - typeToSearch = superType.capture(scope, this.sourceStart, this.sourceEnd); - } - TypeBinding [] parameters = Binding.NO_PARAMETERS; - if (parametersLength > 1) { - parameters = new TypeBinding[parametersLength - 1]; - System.arraycopy(descriptorParameters, 1, parameters, 0, parametersLength - 1); - } - this.depth = 0; - this.freeParameters = parameters; - anotherMethod = scope.getMethod(typeToSearch, this.selector, parameters, this); - anotherMethodDepth = this.depth; - this.depth = 0; - } - } - - if (someMethod != null && someMethod.isValidBinding() && someMethod.isStatic() && anotherMethod != null && anotherMethod.isValidBinding() && !anotherMethod.isStatic()) { - scope.problemReporter().methodReferenceSwingsBothWays(this, anotherMethod, someMethod); - return this.resolvedType = null; - } - - if (someMethod != null && someMethod.isValidBinding() && (anotherMethod == null || !anotherMethod.isValidBinding() || anotherMethod.isStatic())) { - this.binding = someMethod; - this.bits &= ~ASTNode.DepthMASK; - if (someMethodDepth > 0) { - this.bits |= (someMethodDepth & 0xFF) << ASTNode.DepthSHIFT; - } - if (!this.haveReceiver) { - if (!someMethod.isStatic() && !someMethod.isConstructor()) { - scope.problemReporter().methodMustBeAccessedWithInstance(this, someMethod); - return this.resolvedType = null; - } - } - } else if (anotherMethod != null && anotherMethod.isValidBinding() && (someMethod == null || !someMethod.isValidBinding() || !someMethod.isStatic())) { - this.binding = anotherMethod; - this.receiverPrecedesParameters = true; // 0 is receiver, real parameters start at 1 - this.bits &= ~ASTNode.DepthMASK; - if (anotherMethodDepth > 0) { - this.bits |= (anotherMethodDepth & 0xFF) << ASTNode.DepthSHIFT; - } - if (anotherMethod.isStatic()) { - scope.problemReporter().methodMustBeAccessedStatically(this, anotherMethod); - return this.resolvedType = null; - } - } else { - this.binding = null; - this.exactMethodBinding = null; - this.bits &= ~ASTNode.DepthMASK; - } - - if (this.binding == null) { - char [] visibleName = isConstructorReference() ? this.receiverType.sourceName() : this.selector; - scope.problemReporter().danglingReference(this, this.receiverType, visibleName, descriptorParameters); - return this.resolvedType = null; - } - - // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=382350#c2, I.super::abstractMethod will be handled there. - - if (this.binding.isAbstract() && this.lhs.isSuper()) - scope.problemReporter().cannotDireclyInvokeAbstractMethod(this, this.binding); - - if (this.binding.isStatic()) { - if (TypeBinding.notEquals(this.binding.declaringClass, this.receiverType)) - scope.problemReporter().indirectAccessToStaticMethod(this, this.binding); - } else { - AbstractMethodDeclaration srcMethod = this.binding.sourceMethod(); - if (srcMethod != null && srcMethod.isMethod()) - srcMethod.bits &= ~ASTNode.CanBeStatic; - } - - if (isMethodUseDeprecated(this.binding, scope, true, this)) - scope.problemReporter().deprecatedMethod(this.binding, this); - - if (this.typeArguments != null && this.binding.original().typeVariables == Binding.NO_TYPE_VARIABLES) - scope.problemReporter().unnecessaryTypeArgumentsForMethodInvocation(this.binding, this.resolvedTypeArguments, this.typeArguments); - - if ((this.binding.tagBits & TagBits.HasMissingType) != 0) - scope.problemReporter().missingTypeInMethod(this, this.binding); - - - // OK, we have a compile time declaration, see if it passes muster. - TypeBinding [] methodExceptions = this.binding.thrownExceptions; - TypeBinding [] kosherExceptions = this.descriptor.thrownExceptions; - next: for (int i = 0, iMax = methodExceptions.length; i < iMax; i++) { - if (methodExceptions[i].isUncheckedException(false)) { - continue next; - } - for (int j = 0, jMax = kosherExceptions.length; j < jMax; j++) { - if (methodExceptions[i].isCompatibleWith(kosherExceptions[j], scope)) - continue next; - } - scope.problemReporter().unhandledException(methodExceptions[i], this); - } - checkNullAnnotations(scope); - this.freeParameters = null; // not used after method lookup - - if (checkInvocationArguments(scope, null, this.receiverType, this.binding, null, descriptorParameters, false, this)) - this.bits |= ASTNode.Unchecked; - - if (this.descriptor.returnType.id != TypeIds.T_void) { - TypeBinding returnType = null; - if (this.binding.isConstructor()) { - returnType = this.receiverType; - } else { - if ((this.bits & ASTNode.Unchecked) != 0 && this.resolvedTypeArguments == null) { - returnType = this.binding.returnType; - if (returnType != null) { - returnType = scope.environment().convertToRawType(returnType.erasure(), true); - } - } else { - returnType = this.binding.returnType; - if (returnType != null) { - returnType = returnType.capture(scope, this.sourceStart, this.sourceEnd); - } - } - } - if (this.descriptor.returnType.isProperType(true) // otherwise we cannot yet check compatibility - && !returnType.isCompatibleWith(this.descriptor.returnType, scope) - && !isBoxingCompatible(returnType, this.descriptor.returnType, this, scope)) - { - scope.problemReporter().incompatibleReturnType(this, this.binding, this.descriptor.returnType); - this.binding = null; - this.resolvedType = null; - } - } - - return this.resolvedType; // Phew ! - } - - protected void checkNullAnnotations(BlockScope scope) { - CompilerOptions compilerOptions = scope.compilerOptions(); - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { - if (this.expectedType == null || !NullAnnotationMatching.hasContradictions(this.expectedType)) { // otherwise assume it has been reported and we can do nothing here - ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(this.binding, scope); - // TODO: simplify by using this.freeParameters? - int len; - int expectedlen = this.binding.parameters.length; - int providedLen = this.descriptor.parameters.length; - if (this.receiverPrecedesParameters) { - providedLen--; // one parameter is 'consumed' as the receiver - - TypeBinding descriptorParameter = this.descriptor.parameters[0]; - if((descriptorParameter.tagBits & TagBits.AnnotationNullable) != 0) { // Note: normal dereferencing of 'unchecked' values is not reported, either - final TypeBinding receiver = scope.environment().createNonNullAnnotatedType(this.binding.declaringClass); - scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, receiver, descriptorParameter, this.descriptor, -1, NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH); - } - } - boolean isVarArgs = false; - if (this.binding.isVarargs()) { - isVarArgs = (providedLen == expectedlen) - ? !this.descriptor.parameters[expectedlen-1].isCompatibleWith(this.binding.parameters[expectedlen-1]) - : true; - len = providedLen; // binding parameters will be padded from InferenceContext18.getParameter() - } else { - len = Math.min(expectedlen, providedLen); - } - for (int i = 0; i < len; i++) { - TypeBinding descriptorParameter = this.descriptor.parameters[i + (this.receiverPrecedesParameters ? 1 : 0)]; - TypeBinding bindingParameter = InferenceContext18.getParameter(this.binding.parameters, i, isVarArgs); - TypeBinding bindingParameterToCheck; - if (bindingParameter.isPrimitiveType() && !descriptorParameter.isPrimitiveType()) { - // replace primitive types by boxed equivalent for checking, e.g. int -> @NonNull Integer - bindingParameterToCheck = scope.environment().createAnnotatedType(scope.boxing(bindingParameter), - new AnnotationBinding[] { scope.environment().getNonNullAnnotation() }); - } else { - bindingParameterToCheck = bindingParameter; - } - NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(bindingParameterToCheck, descriptorParameter, FlowInfo.UNKNOWN); - if (annotationStatus.isAnyMismatch()) { - // immediate reporting: - scope.problemReporter().referenceExpressionArgumentNullityMismatch(this, bindingParameter, descriptorParameter, this.descriptor, i, annotationStatus); - } - } - TypeBinding returnType = this.binding.returnType; - if(!returnType.isPrimitiveType()) { - if (this.binding.isConstructor()) { - returnType = scope.environment().createAnnotatedType(this.receiverType, new AnnotationBinding[]{ scope.environment().getNonNullAnnotation() }); - } - NullAnnotationMatching annotationStatus = NullAnnotationMatching.analyse(this.descriptor.returnType, returnType, FlowInfo.UNKNOWN); - if (annotationStatus.isAnyMismatch()) { - scope.problemReporter().illegalReturnRedefinition(this, this.descriptor, annotationStatus.isUnchecked(), returnType); - } - } - } - } - } - - private TypeBinding[] descriptorParametersAsArgumentExpressions() { - - if (this.descriptor == null || this.descriptor.parameters == null || this.descriptor.parameters.length == 0) - return Binding.NO_PARAMETERS; - - /* 15.13.1, " ... method reference is treated as if it were an invocation with argument expressions of types P1, ..., Pn;" - This implies/requires wildcard capture. This creates interesting complications, we can't just take the descriptor parameters - and apply captures - where a single wildcard type got "fanned out" and propagated into multiple locations through type variable - substitutions, we will end up creating distinct captures defeating the very idea of capture. We need to first capture and then - fan out. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=432759. - */ - if (this.expectedType.isParameterizedType()) { - ParameterizedTypeBinding type = (ParameterizedTypeBinding) this.expectedType; - MethodBinding method = type.getSingleAbstractMethod(this.enclosingScope, true, this.sourceStart, this.sourceEnd); - return method.parameters; - } - return this.descriptor.parameters; - } - - private boolean contextHasSyntaxError() { - ReferenceContext referenceContext = this.enclosingScope.referenceContext(); - if (referenceContext instanceof AbstractMethodDeclaration) { - if ((((AbstractMethodDeclaration) referenceContext).bits & ASTNode.HasSyntaxErrors) != 0) - return true; - } - return false; - } - - // Cache resolved copies against various target types, so repeat overload resolution and possibly type inference could be avoided. - private ReferenceExpression cachedResolvedCopy(TypeBinding targetType) { - - ReferenceExpression copy = this.copiesPerTargetType != null ? this.copiesPerTargetType.get(targetType) : null; - if (copy != null) - return copy; - - if (contextHasSyntaxError()) - return null; - - IErrorHandlingPolicy oldPolicy = this.enclosingScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy); - try { - copy = copy(); - if (copy == null) { // should never happen even for code assist. - return null; - } - copy.setExpressionContext(this.expressionContext); - copy.setExpectedType(targetType); - copy.resolveType(this.enclosingScope); - - if (this.copiesPerTargetType == null) - this.copiesPerTargetType = new HashMap<>(); - this.copiesPerTargetType.put(targetType, copy); - - return copy; - } finally { - this.enclosingScope.problemReporter().switchErrorHandlingPolicy(oldPolicy); - } - } - - public void registerInferenceContext(ParameterizedGenericMethodBinding method, InferenceContext18 context) { - if (this.inferenceContexts == null) - this.inferenceContexts = new HashMap<>(); - this.inferenceContexts.put(method, context); - } - - public InferenceContext18 getInferenceContext(ParameterizedMethodBinding method) { - if (this.inferenceContexts == null) - return null; - return this.inferenceContexts.get(method); - } - - @Override - public ReferenceExpression resolveExpressionExpecting(TypeBinding targetType, Scope scope, InferenceContext18 inferenceContext) { - if (this.exactMethodBinding != null) { // We may see inference variables in target type. - MethodBinding functionType = targetType.getSingleAbstractMethod(scope, true); - if (functionType == null || functionType.problemId() == ProblemReasons.NoSuchSingleAbstractMethod) - return null; - int n = functionType.parameters.length; - int k = this.exactMethodBinding.parameters.length; - - if (!this.haveReceiver && this.isMethodReference() && !this.exactMethodBinding.isStatic()) { - k++; - } - return (n == k) ? this : null; - } - // descriptors parameters should be free of inference variables. - ReferenceExpression copy = cachedResolvedCopy(targetType); - return copy != null && copy.resolvedType != null && copy.resolvedType.isValidBinding() && copy.binding != null && copy.binding.isValidBinding() ? copy : null; - } - - public boolean isConstructorReference() { - return CharOperation.equals(this.selector, ConstantPool.Init); - } - - @Override - public boolean isExactMethodReference() { - return this.exactMethodBinding != null; - } - - public MethodBinding getExactMethod() { - return this.exactMethodBinding; - } - - public boolean isMethodReference() { - return !CharOperation.equals(this.selector, ConstantPool.Init); - } - - @Override - public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) { - if (!this.isExactMethodReference()) { - return false; - } - return super.isPertinentToApplicability(targetType, method); - } - - @Override - public TypeBinding[] genericTypeArguments() { - return this.resolvedTypeArguments; - } - - @Override - public InferenceContext18 freshInferenceContext(Scope scope) { - if (this.expressionContext != ExpressionContext.VANILLA_CONTEXT) { - Expression[] arguments = createPseudoExpressions(this.freeParameters); - return new InferenceContext18(scope, arguments, this, null); - } - return null; // shouldn't happen, actually - } - - @Override - public boolean isSuperAccess() { - return this.lhs.isSuper(); - } - - @Override - public boolean isTypeAccess() { - return !this.haveReceiver; - } - - @Override - public void setActualReceiverType(ReferenceBinding receiverType) { - return; - } - - @Override - public void setDepth(int depth) { - this.depth = depth; - } - - @Override - public void setFieldIndex(int depth) { - return; - } - - @Override - public StringBuilder printExpression(int tab, StringBuilder output) { - - this.lhs.print(0, output); - output.append("::"); //$NON-NLS-1$ - if (this.typeArguments != null) { - output.append('<'); - int max = this.typeArguments.length - 1; - for (int j = 0; j < max; j++) { - this.typeArguments[j].print(0, output); - output.append(", ");//$NON-NLS-1$ - } - this.typeArguments[max].print(0, output); - output.append('>'); - } - if (isConstructorReference()) - output.append("new"); //$NON-NLS-1$ - else - output.append(this.selector); - - return output; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - - this.lhs.traverse(visitor, blockScope); - - int length = this.typeArguments == null ? 0 : this.typeArguments.length; - for (int i = 0; i < length; i++) { - this.typeArguments[i].traverse(visitor, blockScope); - } - } - visitor.endVisit(this, blockScope); - } - - public Expression[] createPseudoExpressions(TypeBinding[] p) { - // from 15.13.1: - // ... the reference is treated as if it were an invocation with argument expressions of types P1..Pn - // ... the reference is treated as if it were an invocation with argument expressions of types P2..Pn - // (the different sets of types are passed from our resolveType to scope.getMethod(..), see someMethod, anotherMethod) - Expression[] expressions = new Expression[p.length]; - long pos = (((long)this.sourceStart)<<32)+this.sourceEnd; - for (int i = 0; i < p.length; i++) { - expressions[i] = new SingleNameReference(("fakeArg"+i).toCharArray(), pos); //$NON-NLS-1$ - expressions[i].resolvedType = p[i]; - } - return expressions; - } - - @Override - public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope) { - - final boolean isConstructorRef = isConstructorReference(); - if (isConstructorRef) { - if (this.receiverType == null) - return false; - if (this.receiverType.isArrayType()) { - final TypeBinding leafComponentType = this.receiverType.leafComponentType(); - if (!leafComponentType.isReifiable()) { - return false; - } - } - } - - // We get here only when the reference expression is NOT pertinent to applicability. - if (!super.isPertinentToApplicability(targetType, null)) - return true; - final MethodBinding sam = targetType.getSingleAbstractMethod(this.enclosingScope, true); - if (sam == null || !sam.isValidBinding()) - return false; - if (this.typeArgumentsHaveErrors || this.receiverType == null || !this.receiverType.isValidBinding()) - return false; - - int parametersLength = sam.parameters.length; - TypeBinding[] descriptorParameters = new TypeBinding[parametersLength]; - for (int i = 0; i < parametersLength; i++) { - descriptorParameters[i] = new ReferenceBinding() { - { - this.compoundName = CharOperation.NO_CHAR_CHAR; - } - @Override - public boolean isCompatibleWith(TypeBinding otherType, Scope captureScope) { - return true; - } - @Override - public TypeBinding findSuperTypeOriginatingFrom(TypeBinding otherType) { - return otherType; - } - @Override - public String toString() { - return "(wildcard)"; //$NON-NLS-1$ - } - }; - } - - // 15.13.1 - this.freeParameters = descriptorParameters; - this.checkingPotentialCompatibility = true; - try { - MethodBinding compileTimeDeclaration = getCompileTimeDeclaration(scope, isConstructorRef, descriptorParameters); - - if (compileTimeDeclaration != null && compileTimeDeclaration.isValidBinding()) // we have the mSMB. - this.potentialMethods = new MethodBinding [] { compileTimeDeclaration }; - else { - /* We EITHER have potential methods that are input to Scope.mSMb already captured in this.potentialMethods - OR there is no potentially compatible compile time declaration ... - */ - } - - /* 15.12.2.1: A method reference expression (§15.13) is potentially compatible with a functional interface type if, where the type's function type arity is n, - there exists at least one potentially applicable method for the method reference expression with arity n (§15.13.1), and one of the following is true: - – The method reference expression has the form ReferenceType ::[TypeArguments] Identifier and at least one potentially applicable method is - i) static and supports arity n, or ii) not static and supports arity n-1. - – The method reference expression has some other form and at least one potentially applicable method is not static. - */ - - for (int i = 0, length = this.potentialMethods.length; i < length; i++) { - if (this.potentialMethods[i].isStatic() || this.potentialMethods[i].isConstructor()) { - if (!this.haveReceiver) // form ReferenceType ::[TypeArguments] Identifier - return true; - } else { - if (this.haveReceiver) // some other form. - return true; - } - } - - if (this.haveReceiver || parametersLength == 0) - return false; - - System.arraycopy(descriptorParameters, 1, descriptorParameters = new TypeBinding[parametersLength - 1], 0, parametersLength - 1); - this.freeParameters = descriptorParameters; - this.potentialMethods = Binding.NO_METHODS; - compileTimeDeclaration = getCompileTimeDeclaration(scope, false, descriptorParameters); - - if (compileTimeDeclaration != null && compileTimeDeclaration.isValidBinding()) // we have the mSMB. - this.potentialMethods = new MethodBinding [] { compileTimeDeclaration }; - else { - /* We EITHER have potential methods that are input to Scope.mSMb already captured in this.potentialMethods - OR there is no potentially compatible compile time declaration ... - */ - } - for (int i = 0, length = this.potentialMethods.length; i < length; i++) { - if (!this.potentialMethods[i].isStatic() && !this.potentialMethods[i].isConstructor()) { - return true; - } - } - } finally { - this.checkingPotentialCompatibility = false; - this.potentialMethods = Binding.NO_METHODS; - this.freeParameters = null; // not used after method lookup - } - return false; - } - - MethodBinding getCompileTimeDeclaration(Scope scope, boolean isConstructorRef, TypeBinding[] parameters) { - if (this.exactMethodBinding != null) - return this.exactMethodBinding; - else if (this.receiverType.isArrayType()) - return scope.findMethodForArray((ArrayBinding) this.receiverType, this.selector, Binding.NO_PARAMETERS, this); - else if (isConstructorRef) - return scope.getConstructor((ReferenceBinding) this.receiverType, parameters, this); - else - return scope.getMethod(this.receiverType, this.selector, parameters, this); - } - - @Override - public boolean isCompatibleWith(TypeBinding targetType, Scope scope) { - ReferenceExpression copy = cachedResolvedCopy(targetType); - if (copy == null) { - return contextHasSyntaxError(); // in case of syntax error avoid secondary errors - } else if (copy.resolvedType != null && copy.resolvedType.isValidBinding() && copy.binding != null && copy.binding.isValidBinding()) { - return true; - } else { - boolean notPertinentToApplicability = targetType instanceof ParameterizedTypeBinding && !isPertinentToApplicability(targetType, null); // not mentioned in JLS (see prior art in LE.internalIsCompatibleWith() - return notPertinentToApplicability; - } - } - - @Override - public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope scope) { - - if (super.sIsMoreSpecific(s, t, scope)) - return true; - - if (this.exactMethodBinding == null || t.findSuperTypeOriginatingFrom(s) != null) - return false; - - s = s.capture(this.enclosingScope, this.sourceStart, this.sourceEnd); - MethodBinding sSam = s.getSingleAbstractMethod(this.enclosingScope, true); - if (sSam == null || !sSam.isValidBinding()) - return false; - TypeBinding r1 = sSam.returnType; - - MethodBinding tSam = t.getSingleAbstractMethod(this.enclosingScope, true); - if (tSam == null || !tSam.isValidBinding()) - return false; - TypeBinding r2 = tSam.returnType; - - TypeBinding[] sParams = sSam.parameters; - TypeBinding[] tParams = tSam.parameters; - // Both must have the same number of parameters if we got this far - for (int i = 0; i < sParams.length; i++) { - if (TypeBinding.notEquals(sParams[i], tParams[i])) - return false; - } - if (r2.id == TypeIds.T_void) - return true; - - if (r1.id == TypeIds.T_void) - return false; - - // r1 <: r2 - if (r1.isCompatibleWith(r2, scope)) - return true; - - return r1.isBaseType() != r2.isBaseType() && r1.isBaseType() == this.exactMethodBinding.returnType.isBaseType(); - } - - @Override - public org.eclipse.jdt.internal.compiler.lookup.MethodBinding getMethodBinding() { - if (this.actualMethodBinding == null) // array new/clone, no real binding. - this.actualMethodBinding = this.binding; - return this.actualMethodBinding; - } - - public boolean isArrayConstructorReference() { - return isConstructorReference() && this.lhs.resolvedType != null && this.lhs.resolvedType.isArrayType(); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/RequiresStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/RequiresStatement.java deleted file mode 100644 index 3e5090c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/RequiresStatement.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016, 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; - -public class RequiresStatement extends ModuleStatement { - - public ModuleReference module; - public ModuleBinding resolvedBinding; - public int modifiers = ClassFileConstants.AccDefault; - public int modifiersSourceStart; - - public RequiresStatement(ModuleReference module) { - this.module = module; - } - public boolean isTransitive() { - return (this.modifiers & ClassFileConstants.ACC_TRANSITIVE) != 0; - } - public boolean isStatic() { - return (this.modifiers & ClassFileConstants.ACC_STATIC_PHASE) != 0; - } - @Override - public StringBuilder print(int indent, StringBuilder output) { - output.append("requires "); //$NON-NLS-1$ - if (isTransitive()) - output.append("transitive "); //$NON-NLS-1$ - if (isStatic()) - output.append("static "); //$NON-NLS-1$ - this.module.print(indent, output); - output.append(";"); //$NON-NLS-1$ - return output; - } - public ModuleBinding resolve(Scope scope) { - if (this.resolvedBinding != null) - return this.resolvedBinding; - this.resolvedBinding = this.module.resolve(scope); - if (scope != null) { - if (this.resolvedBinding == null) { - scope.problemReporter().invalidModule(this.module); - } else if (this.resolvedBinding.hasUnstableAutoName()) { - scope.problemReporter().autoModuleWithUnstableName(this.module); - } - } - return this.resolvedBinding; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java deleted file mode 100644 index ca6eb24..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ReturnStatement.java +++ /dev/null @@ -1,407 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * 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) - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 365835 - [compiler][null] inconsistent error reporting. - * bug 365519 - editorial cleanup after bug 186342 and bug 365387 - * bug 358903 - Filter practically unimportant resource leak warnings - * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK - * bug 370639 - [compiler][resource] restore the default for resource leak warnings - * bug 365859 - [compiler][null] distinguish warnings based on flow analysis vs. null annotations - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 388996 - [compiler][resource] Incorrect 'potential resource leak' - * bug 394768 - [compiler][resource] Incorrect resource leak warning when creating stream in conditional - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 400761 - [compiler][null] null may be return as boolean without a diagnostic - * bug 401030 - [1.8][null] Null analysis support for lambda methods. - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking - * Bug 417758 - [1.8][null] Null safety compromise during array creation. - * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) - * Bug 430150 - [1.8][null] stricter checking against type variables - * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations - * Bug 452788 - [1.8][compiler] Type not correctly inferred in lambda expression - * Bug 453483 - [compiler][null][loop] Improve null analysis for loops - * Bug 455723 - Nonnull argument not correctly inferred in loop - * Jesper S Moller - Contributions for - * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.ASSIGNMENT_CONTEXT; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class ReturnStatement extends Statement { - - public Expression expression; - public SubRoutineStatement[] subroutines; - public LocalVariableBinding saveValueVariable; - public int initStateIndex = -1; - private final boolean implicitReturn; - -public ReturnStatement(Expression expression, int sourceStart, int sourceEnd) { - this(expression, sourceStart, sourceEnd, false); -} - -public ReturnStatement(Expression expression, int sourceStart, int sourceEnd, boolean implicitReturn) { - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - this.expression = expression; - this.implicitReturn = implicitReturn; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { // here requires to generate a sequence of finally blocks invocations depending corresponding - // to each of the traversed try statements, so that execution will terminate properly. - - // lookup the label, this should answer the returnContext - - if (this.expression instanceof FunctionalExpression) { - if (this.expression.resolvedType == null || !this.expression.resolvedType.isValidBinding()) { - /* Don't descend without proper target types. For lambda shape analysis, what is pertinent is value vs void return and the fact that - this constitutes an abrupt exit. The former is already gathered, the latter is handled here. - */ - flowContext.recordAbruptExit(); - return FlowInfo.DEAD_END; - } - } - - MethodScope methodScope = currentScope.methodScope(); - if (this.expression != null) { - flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); - this.expression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - if (flowInfo.reachMode() == FlowInfo.REACHABLE && currentScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) - checkAgainstNullAnnotation(currentScope, flowContext, flowInfo, this.expression); - if (currentScope.compilerOptions().analyseResourceLeaks) { - boolean returnWithoutOwning = false; - boolean useOwningAnnotations = currentScope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled; - FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(this.expression, flowInfo, flowContext, useOwningAnnotations); - if (trackingVariable != null) { - long owningTagBits = 0; - boolean delegatingToCaller = true; - if (useOwningAnnotations) { - owningTagBits = methodScope.referenceMethodBinding().tagBits & TagBits.AnnotationOwningMASK; - returnWithoutOwning = owningTagBits == 0; - delegatingToCaller = (owningTagBits & TagBits.AnnotationNotOwning) == 0; - } - if (methodScope != trackingVariable.methodScope && delegatingToCaller) - trackingVariable.markClosedInNestedMethod(); - if (delegatingToCaller) { - // by returning the method passes the responsibility to the caller: - flowInfo = FakedTrackingVariable.markPassedToOutside(currentScope, this.expression, flowInfo, flowContext, true); - } - } - // don't wait till after this statement, because then flowInfo would be DEAD_END & thus cannot serve nullStatus any more: - FakedTrackingVariable.cleanUpUnassigned(currentScope, this.expression, flowInfo, returnWithoutOwning); - } - } - this.initStateIndex = - methodScope.recordInitializationStates(flowInfo); - // compute the return sequence (running the finally blocks) - FlowContext traversedContext = flowContext; - int subCount = 0; - boolean saveValueNeeded = false; - boolean hasValueToSave = needValueStore(); - boolean noAutoCloseables = true; - do { - SubRoutineStatement sub; - if ((sub = traversedContext.subroutine()) != null) { - if (this.subroutines == null){ - this.subroutines = new SubRoutineStatement[5]; - } - if (subCount == this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount*2]), 0, subCount); // grow - } - this.subroutines[subCount++] = sub; - if (sub.isSubRoutineEscaping()) { - saveValueNeeded = false; - this.bits |= ASTNode.IsAnySubRoutineEscaping; - break; - } - if (sub instanceof TryStatement) { - if (((TryStatement) sub).resources.length > 0) { - noAutoCloseables = false; - } - } - } - traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); - - if (traversedContext instanceof InsideSubRoutineFlowContext) { - ASTNode node = traversedContext.associatedNode; - if (node instanceof SynchronizedStatement) { - this.bits |= ASTNode.IsSynchronized; - } else if (node instanceof TryStatement) { - TryStatement tryStatement = (TryStatement) node; - flowInfo.addInitializationsFrom(tryStatement.subRoutineInits); // collect inits - if (hasValueToSave) { - if (this.saveValueVariable == null){ // closest subroutine secret variable is used - prepareSaveValueLocation(tryStatement); - } - saveValueNeeded = true; - this.initStateIndex = - methodScope.recordInitializationStates(flowInfo); - } - } - } else if (traversedContext instanceof InitializationFlowContext) { - currentScope.problemReporter().cannotReturnInInitializer(this); - return FlowInfo.DEAD_END; - } else if (traversedContext.associatedNode instanceof SwitchExpression) { - currentScope.problemReporter().switchExpressionsReturnWithinSwitchExpression(this); - return FlowInfo.DEAD_END; - } - } while ((traversedContext = traversedContext.getLocalParent()) != null); - - // resize subroutines - if ((this.subroutines != null) && (subCount != this.subroutines.length)) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount); - } - - // secret local variable for return value (note that this can only occur in a real method) - if (saveValueNeeded) { - if (this.saveValueVariable != null) { - this.saveValueVariable.useFlag = LocalVariableBinding.USED; - } - } else { - this.saveValueVariable = null; - if (((this.bits & ASTNode.IsSynchronized) == 0) && this.expression != null && TypeBinding.equalsEquals(this.expression.resolvedType, TypeBinding.BOOLEAN)) { - if (noAutoCloseables) { // can't abruptly return in the presence of autocloseables. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=367566 - this.expression.bits |= ASTNode.IsReturnedValue; - } - } - } - currentScope.checkUnclosedCloseables(flowInfo, flowContext, this, currentScope); - // inside conditional structure respect that a finally-block may conditionally be entered directly from here - flowContext.recordAbruptExit(); - flowContext.expireNullCheckedFieldInfo(); - return FlowInfo.DEAD_END; -} -@Override -public boolean doesNotCompleteNormally() { - return true; -} - -@Override -public boolean canCompleteNormally() { - return false; -} - -/** - * Retrun statement code generation - * - * generate the finallyInvocationSequence. - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) { - return; - } - int pc = codeStream.position; - boolean alreadyGeneratedExpression = false; - // generate the expression - if (needValueStore()) { - alreadyGeneratedExpression = true; - this.expression.generateCode(currentScope, codeStream, needValue()); // no value needed if non-returning subroutine - generateStoreSaveValueIfNecessary(currentScope, codeStream); - } - - // generation of code responsible for invoking the finally blocks in sequence - if (this.subroutines != null) { - Object reusableJSRTarget = this.expression == null ? (Object)TypeBinding.VOID : this.expression.reusableJSRTarget(); - for (int i = 0, max = this.subroutines.length; i < max; i++) { - SubRoutineStatement sub = this.subroutines[i]; - boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, reusableJSRTarget, this.initStateIndex, this.saveValueVariable); - if (didEscape) { - codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); - return; - } - } - } - if (this.saveValueVariable != null) { - codeStream.load(this.saveValueVariable); - } - if (this.expression != null && !alreadyGeneratedExpression) { - this.expression.generateCode(currentScope, codeStream, true); - // hook necessary for Code Snippet - generateStoreSaveValueIfNecessary(currentScope, codeStream); - } - // output the suitable return bytecode or wrap the value inside a descriptor for doits - generateReturnBytecode(codeStream); - if (this.saveValueVariable != null) { - codeStream.removeVariable(this.saveValueVariable); - } - if (this.initStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); -} - -/** - * Dump the suitable return bytecode for a return statement - */ -public void generateReturnBytecode(CodeStream codeStream) { - codeStream.generateReturnBytecode(this.expression); -} - -public void generateStoreSaveValueIfNecessary(Scope scope, CodeStream codeStream){ - if (this.saveValueVariable != null) { - codeStream.store(this.saveValueVariable, false); - // the variable is visible as soon as the local is stored - codeStream.addVariable(this.saveValueVariable); - } -} - -private boolean needValueStore() { - return this.expression != null - && (this.expression.constant == Constant.NotAConstant || (this.expression.implicitConversion & TypeIds.BOXING)!= 0) - && !(this.expression instanceof NullLiteral); -} - -public boolean needValue() { - return this.saveValueVariable != null - || (this.bits & ASTNode.IsSynchronized) != 0 - || ((this.bits & ASTNode.IsAnySubRoutineEscaping) == 0); -} - -public void prepareSaveValueLocation(TryStatement targetTryStatement){ - this.saveValueVariable = targetTryStatement.secretReturnValue; -} - -@Override -public StringBuilder printStatement(int tab, StringBuilder output){ - printIndent(tab, output).append("return "); //$NON-NLS-1$ - if (this.expression != null ) - this.expression.printExpression(0, output) ; - return output.append(';'); -} - -@Override -public void resolve(BlockScope scope) { - MethodScope methodScope = scope.methodScope(); - MethodBinding methodBinding = null; - LambdaExpression lambda = methodScope.referenceContext instanceof LambdaExpression ? (LambdaExpression) methodScope.referenceContext : null; - TypeBinding methodType = - lambda != null ? lambda.expectedResultType() : - (methodScope.referenceContext instanceof AbstractMethodDeclaration) - ? ((methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding) == null - ? null - : methodBinding.returnType) - : TypeBinding.VOID; - TypeBinding expressionType; - - if (methodBinding != null && methodBinding.isCompactConstructor()) - scope.problemReporter().recordCompactConstructorHasReturnStatement(this); - - if (this.expression != null) { - this.expression.setExpressionContext(ASSIGNMENT_CONTEXT); - this.expression.setExpectedType(methodType); - if (lambda != null && lambda.argumentsTypeElided() && this.expression instanceof CastExpression) { - this.expression.bits |= ASTNode.DisableUnnecessaryCastCheck; - } - } - - if (methodType == TypeBinding.VOID) { - // the expression should be null, exceptions exist for lambda expressions. - if (this.expression == null) { - if (lambda != null) - lambda.returnsExpression(null, TypeBinding.VOID); - return; - } - expressionType = this.expression.resolveType(scope); - if (lambda != null) - lambda.returnsExpression(this.expression, expressionType); - if (this.implicitReturn && (expressionType == TypeBinding.VOID || this.expression.statementExpression())) - return; - if (expressionType != null) - scope.problemReporter().attemptToReturnNonVoidExpression(this, expressionType); - return; - } - if (this.expression == null) { - if (lambda != null) - lambda.returnsExpression(null, methodType); - if (methodType != null) scope.problemReporter().shouldReturn(methodType, this); - return; - } - - expressionType = this.expression.resolveType(scope); - if (lambda != null) - lambda.returnsExpression(this.expression, expressionType); - - if (expressionType == null) return; - if (expressionType == TypeBinding.VOID) { - scope.problemReporter().attemptToReturnVoidValue(this); - return; - } - if (methodType == null) - return; - - if (lambda != null && methodType.isProperType(true)) { - // ensure that type conversions don't leak a preliminary local type: - if (lambda.updateLocalTypes()) - methodType = lambda.expectedResultType(); - } - if (TypeBinding.notEquals(methodType, expressionType)) // must call before computeConversion() and typeMismatchError() - scope.compilationUnitScope().recordTypeConversion(methodType, expressionType); - if (this.expression.isConstantValueOfTypeAssignableToType(expressionType, methodType) - || expressionType.isCompatibleWith(methodType, scope)) { - - this.expression.computeConversion(scope, methodType, expressionType); - if (expressionType.needsUncheckedConversion(methodType)) { - scope.problemReporter().unsafeTypeConversion(this.expression, expressionType, methodType); - } - if (this.expression instanceof CastExpression) { - if ((this.expression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { - CastExpression.checkNeedForAssignedCast(scope, methodType, (CastExpression) this.expression); - } else if (lambda != null && lambda.argumentsTypeElided() && (this.expression.bits & ASTNode.UnnecessaryCast) != 0) { - if (TypeBinding.equalsEquals(((CastExpression)this.expression).expression.resolvedType, methodType)) { - scope.problemReporter().unnecessaryCast((CastExpression)this.expression); - } - } - } - return; - } else if (isBoxingCompatible(expressionType, methodType, this.expression, scope)) { - this.expression.computeConversion(scope, methodType, expressionType); - if (this.expression instanceof CastExpression - && (this.expression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { - CastExpression.checkNeedForAssignedCast(scope, methodType, (CastExpression) this.expression); - } return; - } - if ((methodType.tagBits & TagBits.HasMissingType) == 0) { - // no need to complain if return type was missing (avoid secondary error : 220967) - scope.problemReporter().typeMismatchError(expressionType, methodType, this.expression, this); - } -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.expression != null) - this.expression.traverse(visitor, scope); - } - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java deleted file mode 100644 index 649140a..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SingleMemberAnnotation.java +++ /dev/null @@ -1,91 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2013 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Jesper Steen Moller - Contributions for: - * Bug 412149: [1.8][compiler] Emit repeated annotations into the designated container - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.*; - -/** - * SingleMemberAnnotation node - */ -public class SingleMemberAnnotation extends Annotation { - - public Expression memberValue; - private MemberValuePair[] singlePairs; // fake pair set, only value has accurate positions - - public SingleMemberAnnotation(TypeReference type, int sourceStart) { - this.type = type; - this.sourceStart = sourceStart; - this.sourceEnd = type.sourceEnd; - } - - public SingleMemberAnnotation() { - // for subclasses. - } - - @Override - public ElementValuePair[] computeElementValuePairs() { - return new ElementValuePair[] {memberValuePairs()[0].compilerElementPair}; - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.Annotation#memberValuePairs() - */ - @Override - public MemberValuePair[] memberValuePairs() { - if (this.singlePairs == null) { - this.singlePairs = - new MemberValuePair[]{ - new MemberValuePair(VALUE, this.memberValue.sourceStart, this.memberValue.sourceEnd, this.memberValue) - }; - } - return this.singlePairs; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - super.printExpression(indent, output); - output.append('('); - this.memberValue.printExpression(indent, output); - return output.append(')'); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.type != null) { - this.type.traverse(visitor, scope); - } - if (this.memberValue != null) { - this.memberValue.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.type != null) { - this.type.traverse(visitor, scope); - } - if (this.memberValue != null) { - this.memberValue.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java deleted file mode 100644 index dc5a004..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java +++ /dev/null @@ -1,1117 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 292478 - Report potentially null across variable assignment, - * bug 185682 - Increment/decrement operators mark local variables as read - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * Bug 412203 - [compiler] Internal compiler error: java.lang.IllegalArgumentException: info cannot be null - * Bug 458396 - NPE in CodeStream.invoke() - * Bug 407414 - [compiler][null] Incorrect warning on a primitive type being null - * Jesper S Moller - - Contributions for - * bug 382721 - [1.8][compiler] Effectively final variables needs special treatment - * bug 378674 - "The method can be declared as static" is wrong - * bug 404657 - [1.8][compiler] Analysis for effectively final variables fails to consider loops - * bug 527554 - [18.3] Compiler support for JEP 286 Local-Variable Type - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.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.impl.CompilerOptions; -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.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.MissingTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemFieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -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.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; -import org.eclipse.jdt.internal.compiler.problem.AbortMethod; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; - -public class SingleNameReference extends NameReference implements OperatorIds { - - public static final int READ = 0; - public static final int WRITE = 1; - public char[] token; - public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor - public TypeBinding genericCast; - public boolean isLabel;// flagging for break expression when expression is SwitchExpression - java 12 preview-feature - -public SingleNameReference(char[] source, long pos) { - super(); - this.token = source; - this.sourceStart = (int) (pos >>> 32); - this.sourceEnd = (int) pos; -} - -@Override -public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { - boolean isReachable = (flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0; - // compound assignment extra work - if (isCompound) { // check the variable part is initialized if blank final - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - FieldBinding fieldBinding = (FieldBinding) this.binding; - if (fieldBinding.isBlankFinal() - && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { - FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo); - if (!fieldInits.isDefinitelyAssigned(fieldBinding)) { - currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); - } - } - manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); - break; - case Binding.LOCAL : // reading a local variable - // check if assigning a final blank field - LocalVariableBinding localBinding; - if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) { - currentScope.problemReporter().uninitializedLocalVariable(localBinding, this, currentScope); - // we could improve error msg here telling "cannot use compound assignment on final local variable" - } - if (localBinding.useFlag != LocalVariableBinding.USED) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682 - // access from compound assignment does not prevent "unused" warning, unless unboxing is involved: - if (isReachable && (this.implicitConversion & TypeIds.UNBOXING) != 0) { - localBinding.useFlag = LocalVariableBinding.USED; - } else { - // use values < 0 to count the number of compound uses: - if (localBinding.useFlag <= LocalVariableBinding.UNUSED) - localBinding.useFlag--; - } - } - } - } - if (assignment.expression != null) { - flowInfo = assignment.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - } - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // assigning to a field - manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/); - - // check if assigning a final field - FieldBinding fieldBinding = (FieldBinding) this.binding; - if (fieldBinding.isFinal()) { - // inside a context where allowed - if (!isCompound && fieldBinding.isBlankFinal() && currentScope.allowBlankFinalFieldAssignment(fieldBinding)) { - if (flowInfo.isPotentiallyAssigned(fieldBinding)) { - currentScope.problemReporter().duplicateInitializationOfBlankFinalField(fieldBinding, this); - } else { - flowContext.recordSettingFinal(fieldBinding, this, flowInfo); - } - flowInfo.markAsDefinitelyAssigned(fieldBinding); - } else { - currentScope.problemReporter().cannotAssignToFinalField(fieldBinding, this); - } - } else if (!isCompound && (fieldBinding.isNonNull() || fieldBinding.type.isTypeVariable()) - && TypeBinding.equalsEquals(fieldBinding.declaringClass, currentScope.enclosingReceiverType())) { // inherited fields are not tracked here - // record assignment for detecting uninitialized non-null fields: - flowInfo.markAsDefinitelyAssigned(fieldBinding); - } - break; - case Binding.LOCAL : // assigning to a local variable - LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - final boolean isFinal = localBinding.isFinal(); - if (!flowInfo.isDefinitelyAssigned(localBinding)){// for local variable debug attributes - this.bits |= ASTNode.FirstAssignmentToLocal; - } else { - this.bits &= ~ASTNode.FirstAssignmentToLocal; - } - if (flowInfo.isPotentiallyAssigned(localBinding) || (this.bits & ASTNode.IsCapturedOuterLocal) != 0) { - localBinding.tagBits &= ~TagBits.IsEffectivelyFinal; - if (!isFinal) { - if ((this.bits & ASTNode.IsCapturedOuterLocal) != 0) { - currentScope.problemReporter().cannotReferToNonEffectivelyFinalOuterLocal(localBinding, this); - } else if ((this.bits & ASTNode.IsUsedInPatternGuard) != 0) { - currentScope.problemReporter().cannotReferToNonFinalLocalInGuard(localBinding, this); - } - } - } - if (! isFinal && (localBinding.tagBits & TagBits.IsEffectivelyFinal) != 0 && (localBinding.tagBits & TagBits.IsArgument) == 0) { - flowContext.recordSettingFinal(localBinding, this, flowInfo); - } else if (isFinal) { - if ((this.bits & ASTNode.DepthMASK) == 0) { - // tolerate assignment to final local in unreachable code (45674) - if ((isReachable && isCompound) || !localBinding.isBlankFinal()){ - currentScope.problemReporter().cannotAssignToFinalLocal(localBinding, this); - } else if (flowInfo.isPotentiallyAssigned(localBinding)) { - currentScope.problemReporter().duplicateInitializationOfFinalLocal(localBinding, this); - } else if ((this.bits & ASTNode.IsCapturedOuterLocal) != 0) { - currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this); - } else { - flowContext.recordSettingFinal(localBinding, this, flowInfo); - } - } else { - currentScope.problemReporter().cannotAssignToFinalOuterLocal(localBinding, this); - } - } - else /* avoid double diagnostic */ if ((localBinding.tagBits & TagBits.IsArgument) != 0) { - MethodBinding owner = localBinding.getEnclosingMethod(); - if (owner == null /*lambda */ || !owner.isCompactConstructor()) - currentScope.problemReporter().parameterAssignment(localBinding, this); - } - flowInfo.markAsDefinitelyAssigned(localBinding); - } - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - return flowInfo; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return analyseCode(currentScope, flowContext, flowInfo, true); -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, boolean valueRequired) { - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) { - manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/); - } - // check if reading a final blank field - FieldBinding fieldBinding = (FieldBinding) this.binding; - if (fieldBinding.isBlankFinal() && currentScope.needBlankFinalFieldInitializationCheck(fieldBinding)) { - FlowInfo fieldInits = flowContext.getInitsForFinalBlankInitializationCheck(fieldBinding.declaringClass.original(), flowInfo); - if (!fieldInits.isDefinitelyAssigned(fieldBinding)) { - currentScope.problemReporter().uninitializedBlankFinalField(fieldBinding, this); - } - } - break; - case Binding.LOCAL : // reading a local variable - LocalVariableBinding localBinding; - if (!flowInfo.isDefinitelyAssigned(localBinding = (LocalVariableBinding) this.binding)) { - currentScope.problemReporter().uninitializedLocalVariable(localBinding, this, currentScope); - } - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE) == 0) { - localBinding.useFlag = LocalVariableBinding.USED; - } else if (localBinding.useFlag == LocalVariableBinding.UNUSED) { - localBinding.useFlag = LocalVariableBinding.FAKE_USED; - } - } - if (valueRequired) { - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - } - return flowInfo; -} - -public TypeBinding checkFieldAccess(BlockScope scope) { - FieldBinding fieldBinding = (FieldBinding) this.binding; - this.constant = fieldBinding.constant(scope); - - this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits - this.bits |= Binding.FIELD; - MethodScope methodScope = scope.methodScope(); - if (fieldBinding.isStatic()) { - // check if accessing enum static field in initializer - ReferenceBinding declaringClass = fieldBinding.declaringClass; - if (declaringClass.isEnum() && scope.kind != Scope.MODULE_SCOPE) { - SourceTypeBinding sourceType = scope.enclosingSourceType(); - if (this.constant == Constant.NotAConstant - && !methodScope.isStatic - && (TypeBinding.equalsEquals(sourceType, declaringClass) || TypeBinding.equalsEquals(sourceType.superclass, declaringClass)) // enum constant body - && methodScope.isInsideInitializerOrConstructor()) { - scope.problemReporter().enumStaticFieldUsedDuringInitialization(fieldBinding, this); - } - } - } else { - if (scope.compilerOptions().getSeverity(CompilerOptions.UnqualifiedFieldAccess) != ProblemSeverities.Ignore) { - scope.problemReporter().unqualifiedFieldAccess(this, fieldBinding); - } - // must check for the static status.... - if (methodScope.isStatic) { - scope.problemReporter().staticFieldAccessToNonStaticVariable(this, fieldBinding); - return fieldBinding.type; - } else { - scope.tagAsAccessingEnclosingInstanceStateOf(fieldBinding.declaringClass, false /* type variable access */); - } - } - - if (isFieldUseDeprecated(fieldBinding, scope, this.bits)) - scope.problemReporter().deprecatedField(fieldBinding, this); - - if ((this.bits & ASTNode.IsStrictlyAssigned) == 0 - && TypeBinding.equalsEquals(methodScope.enclosingSourceType(), fieldBinding.original().declaringClass) - && methodScope.lastVisibleFieldID >= 0 - && fieldBinding.id >= methodScope.lastVisibleFieldID - && (!fieldBinding.isStatic() || methodScope.isStatic)) { - scope.problemReporter().forwardReference(this, 0, fieldBinding); - this.bits |= ASTNode.IgnoreNoEffectAssignCheck; - } - return fieldBinding.type; - -} - -@Override -public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - if (!super.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck)) { - CompilerOptions compilerOptions = scope.compilerOptions(); - if (compilerOptions.isAnnotationBasedNullAnalysisEnabled) { - if (this.binding instanceof FieldBinding) { - return checkNullableFieldDereference(scope, (FieldBinding) this.binding, ((long)this.sourceStart<<32)+this.sourceEnd, flowContext, ttlForFieldCheck); - } - } - } - return false; -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding) - */ -@Override -public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) { - if (runtimeTimeType == null || compileTimeType == null) - return; - if (this.binding != null && this.binding.isValidBinding()) { - TypeBinding originalType = null; - if ((this.bits & Binding.FIELD) != 0) { - // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast) - FieldBinding field = (FieldBinding) this.binding; - FieldBinding originalBinding = field.original(); - originalType = originalBinding.type; - } else if ((this.bits & Binding.LOCAL) != 0) { - LocalVariableBinding local = (LocalVariableBinding) this.binding; - originalType = local.type; - } - // extra cast needed if field/local type is type variable - if (originalType != null && originalType.leafComponentType().isTypeVariable()) { - TypeBinding targetType = (!compileTimeType.isBaseType() && runtimeTimeType.isBaseType()) - ? compileTimeType // unboxing: checkcast before conversion - : runtimeTimeType; - this.genericCast = originalType.genericCast(scope.boxing(targetType)); - if (this.genericCast instanceof ReferenceBinding) { - ReferenceBinding referenceCast = (ReferenceBinding) this.genericCast; - if (!referenceCast.canBeSeenBy(scope)) { - scope.problemReporter().invalidType(this, - new ProblemReferenceBinding( - CharOperation.splitOn('.', referenceCast.shortReadableName()), - referenceCast, - ProblemReasons.NotVisible)); - } - } - } - } - super.computeConversion(scope, runtimeTimeType, compileTimeType); -} - -@Override -public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { - // optimizing assignment like: i = i + 1 or i = 1 + i - if (assignment.expression.isCompactableOperation()) { - BinaryExpression operation = (BinaryExpression) assignment.expression; - int operator = (operation.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT; - SingleNameReference variableReference; - if ((operation.left instanceof SingleNameReference) && ((variableReference = (SingleNameReference) operation.left).binding == this.binding)) { - // i = i + value, then use the variable on the right hand side, since it has the correct implicit conversion - variableReference.generateCompoundAssignment(currentScope, codeStream, this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE], operation.right, operator, operation.implicitConversion, valueRequired); - if (valueRequired) { - codeStream.generateImplicitConversion(assignment.implicitConversion); - } - return; - } - if ((operation.right instanceof SingleNameReference) - && ((operator == OperatorIds.PLUS) || (operator == OperatorIds.MULTIPLY)) // only commutative operations - && ((variableReference = (SingleNameReference) operation.right).binding == this.binding) - && (operation.left.constant != Constant.NotAConstant) // exclude non constant expressions, since could have side-effect - && (((operation.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) != TypeIds.T_JavaLangString) // exclude string concatenation which would occur backwards - && (((operation.right.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) != TypeIds.T_JavaLangString)) { // exclude string concatenation which would occur backwards - // i = value + i, then use the variable on the right hand side, since it has the correct implicit conversion - variableReference.generateCompoundAssignment(currentScope, codeStream, this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE], operation.left, operator, operation.implicitConversion, valueRequired); - if (valueRequired) { - codeStream.generateImplicitConversion(assignment.implicitConversion); - } - return; - } - } - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // assigning to a field - int pc = codeStream.position; - FieldBinding codegenBinding = ((FieldBinding) this.binding).original(); - if (!codegenBinding.isStatic()) { // need a receiver? - if ((this.bits & ASTNode.DepthMASK) != 0) { - ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); - Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); - codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); - } else { - generateReceiver(codeStream); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - assignment.expression.generateCode(currentScope, codeStream, true); - fieldStore(currentScope, codeStream, codegenBinding, this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE], this.actualReceiverType, true /*implicit this*/, valueRequired); - if (valueRequired) { - codeStream.generateImplicitConversion(assignment.implicitConversion); - } - // no need for generic cast as value got dupped - return; - case Binding.LOCAL : // assigning to a local variable - LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - if (localBinding.resolvedPosition != -1) { - assignment.expression.generateCode(currentScope, codeStream, true); - } else { - if (assignment.expression.constant != Constant.NotAConstant) { - // assigning an unused local to a constant value = no actual assignment is necessary - if (valueRequired) { - codeStream.generateConstant(assignment.expression.constant, assignment.implicitConversion); - } - } else { - assignment.expression.generateCode(currentScope, codeStream, true); - /* Even though the value may not be required, we force it to be produced, and discard it later - on if it was actually not necessary, so as to provide the same behavior as JDK1.2beta3. */ - if (valueRequired) { - codeStream.generateImplicitConversion(assignment.implicitConversion); // implicit conversion - } else { - switch(localBinding.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - break; - } - } - } - return; - } - // 26903, need extra cast to store null in array local var - if (localBinding.type.isArrayType() - && ((assignment.expression instanceof CastExpression) // arrayLoc = (type[])null - && (((CastExpression)assignment.expression).innermostCastedExpression().resolvedType == TypeBinding.NULL))){ - codeStream.checkcast(localBinding.type); - } - - // normal local assignment (since cannot store in outer local which are final locations) - codeStream.store(localBinding, valueRequired); - if ((this.bits & ASTNode.IsSecretYieldValueUsage) != 0) { - localBinding.recordInitializationStartPC(codeStream.position); - } - if ((this.bits & ASTNode.FirstAssignmentToLocal) != 0) { // for local variable debug attributes - localBinding.recordInitializationStartPC(codeStream.position); - } - // implicit conversion - if (valueRequired) { - codeStream.generateImplicitConversion(assignment.implicitConversion); - } - } -} - -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (this.constant != Constant.NotAConstant) { - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } else { - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - FieldBinding codegenField = ((FieldBinding) this.binding).original(); - Constant fieldConstant = codegenField.constant(); - if (fieldConstant != Constant.NotAConstant) { - // directly use inlined value for constant fields - if (valueRequired) { - codeStream.generateConstant(fieldConstant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - if (codegenField.isStatic()) { - if (!valueRequired - // if no valueRequired, still need possible side-effects of invocation, if field belongs to different class - && TypeBinding.equalsEquals(((FieldBinding)this.binding).original().declaringClass, this.actualReceiverType.erasure()) - && ((this.implicitConversion & TypeIds.UNBOXING) == 0) - && this.genericCast == null) { - // if no valueRequired, optimize out entire gen - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - // managing private access - if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true /* implicit this */); - codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenField, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null /* default declaringClass */); - } - } else { - if (!valueRequired - && (this.implicitConversion & TypeIds.UNBOXING) == 0 - && this.genericCast == null) { - // if no valueRequired, optimize out entire gen - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - // managing enclosing instance access - if ((this.bits & ASTNode.DepthMASK) != 0) { - ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); - Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); - codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); - } else { - generateReceiver(codeStream); - } - // managing private access - if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true /* implicit this */); - codeStream.fieldAccess(Opcodes.OPC_getfield, codegenField, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null /* default declaringClass */); - } - } - break; - case Binding.LOCAL : // reading a local - LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - if (localBinding.resolvedPosition == -1) { - if (valueRequired) { - // restart code gen - localBinding.useFlag = LocalVariableBinding.USED; - throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - if (!valueRequired && (this.implicitConversion & TypeIds.UNBOXING) == 0) { - // if no valueRequired, optimize out entire gen - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - // checkEffectiveFinality() returns if it's outer local - if (checkEffectiveFinality(localBinding, currentScope)) { - // outer local can be reached either through a synthetic arg or a synthetic field - VariableBinding[] path = currentScope.getEmulationPath(localBinding); - codeStream.generateOuterAccess(path, this, localBinding, currentScope); - } else { - // regular local variable read - codeStream.load(localBinding); - } - break; - default: // type - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - } - // required cast must occur even if no value is required - if (this.genericCast != null) codeStream.checkcast(this.genericCast); - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } else { - boolean isUnboxing = (this.implicitConversion & TypeIds.UNBOXING) != 0; - // conversion only generated if unboxing - if (isUnboxing) codeStream.generateImplicitConversion(this.implicitConversion); - switch (isUnboxing ? postConversionType(currentScope).id : this.resolvedType.id) { - case T_long : - case T_double : - codeStream.pop2(); - break; - default : - codeStream.pop(); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -/* - * Regular API for compound assignment, relies on the fact that there is only one reference to the - * variable, which carries both synthetic read/write accessors. - * The APIs with an extra argument is used whenever there are two references to the same variable which - * are optimized in one access: e.g "a = a + 1" optimized into "a++". - */ -@Override -public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682 - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.LOCAL: - LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - // check if compound assignment is the only usage of this local - Reference.reportOnlyUselesslyReadLocal(currentScope, localBinding, valueRequired); - break; - case Binding.FIELD: - // check if compound assignment is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, (FieldBinding)this.binding, valueRequired); - } - this.generateCompoundAssignment( - currentScope, - codeStream, - this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE], - expression, - operator, - assignmentImplicitConversion, - valueRequired); -} - -/* - * The APIs with an extra argument is used whenever there are two references to the same variable which - * are optimized in one access: e.g "a = a + 1" optimized into "a++". - */ -public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // assigning to a field - FieldBinding codegenField = ((FieldBinding) this.binding).original(); - if (codegenField.isStatic()) { - if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true /* implicit this */); - codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenField, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null /* default declaringClass */); - } - } else { - if ((this.bits & ASTNode.DepthMASK) != 0) { - ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); - Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); - codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); - } else { - codeStream.aload_0(); - } - codeStream.dup(); - if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true /* implicit this */); - codeStream.fieldAccess(Opcodes.OPC_getfield, codegenField, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null /* default declaringClass */); - } - } - break; - case Binding.LOCAL : // assigning to a local variable (cannot assign to outer local) - LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - // using incr bytecode if possible - Constant assignConstant; - switch (localBinding.type.id) { - case T_JavaLangString : - codeStream.generateStringConcatenationAppend(currentScope, this, expression); - if (valueRequired) { - codeStream.dup(); - } - codeStream.store(localBinding, false); - return; - case T_int : - assignConstant = expression.constant; - if (localBinding.resolvedPosition == -1) { - if (valueRequired) { - /* - * restart code gen because we either: - * - need the value - * - the constant can have potential side-effect - */ - localBinding.useFlag = LocalVariableBinding.USED; - throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null); - } else if (assignConstant == Constant.NotAConstant) { - // we only need to generate the value of the expression's constant if it is not a constant expression - expression.generateCode(currentScope, codeStream, false); - } - return; - } - if ((assignConstant != Constant.NotAConstant) - && (assignConstant.typeID() != TypeIds.T_float) // only for integral types - && (assignConstant.typeID() != TypeIds.T_double)) { // TODO (philippe) is this test needed ? - switch (operator) { - case PLUS : - int increment = assignConstant.intValue(); - if (increment != (short) increment) break; // not representable as a 16-bits value - codeStream.iinc(localBinding.resolvedPosition, increment); - if (valueRequired) { - codeStream.load(localBinding); - } - return; - case MINUS : - increment = -assignConstant.intValue(); - if (increment != (short) increment) break; // not representable as a 16-bits value - codeStream.iinc(localBinding.resolvedPosition, increment); - if (valueRequired) { - codeStream.load(localBinding); - } - return; - } - } - //$FALL-THROUGH$ - default : - if (localBinding.resolvedPosition == -1) { - assignConstant = expression.constant; - if (valueRequired) { - /* - * restart code gen because we either: - * - need the value - * - the constant can have potential side-effect - */ - localBinding.useFlag = LocalVariableBinding.USED; - throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null); - } else if (assignConstant == Constant.NotAConstant) { - // we only need to generate the value of the expression's constant if it is not a constant expression - expression.generateCode(currentScope, codeStream, false); - } - return; - } - codeStream.load(localBinding); - } - } - // perform the actual compound operation - int operationTypeID; - switch(operationTypeID = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { - case T_JavaLangString : - case T_JavaLangObject : - case T_undefined : - // we enter here if the single name reference is a field of type java.lang.String or if the type of the - // operation is java.lang.Object - // For example: o = o + ""; // where the compiled type of o is java.lang.Object. - codeStream.generateStringConcatenationAppend(currentScope, null, expression); - // no need for generic cast on previous #getfield since using Object string buffer methods. - break; - default : - // promote the array reference to the suitable operation type - if (this.genericCast != null) - codeStream.checkcast(this.genericCast); - codeStream.generateImplicitConversion(this.implicitConversion); - // generate the increment value (will by itself be promoted to the operation value) - if (expression == IntLiteral.One){ // prefix operation - codeStream.generateConstant(expression.constant, this.implicitConversion); - } else { - expression.generateCode(currentScope, codeStream, true); - } - // perform the operation - codeStream.sendOperator(operator, operationTypeID); - // cast the value back to the array reference type - codeStream.generateImplicitConversion(assignmentImplicitConversion); - } - // store the result back into the variable - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // assigning to a field - FieldBinding codegenField = ((FieldBinding) this.binding).original(); - fieldStore(currentScope, codeStream, codegenField, writeAccessor, this.actualReceiverType, true /* implicit this*/, valueRequired); - // no need for generic cast as value got dupped - return; - case Binding.LOCAL : // assigning to a local variable - LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - if (valueRequired) { - switch (localBinding.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2(); - break; - default: - codeStream.dup(); - break; - } - } - codeStream.store(localBinding, false); - } -} - -@Override -public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // assigning to a field - FieldBinding fieldBinding = (FieldBinding)this.binding; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682 - // check if postIncrement is the only usage of a private field - reportOnlyUselesslyReadPrivateField(currentScope, fieldBinding, valueRequired); - FieldBinding codegenField = fieldBinding.original(); - if (codegenField.isStatic()) { - if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true /* implicit this */); - codeStream.fieldAccess(Opcodes.OPC_getstatic, codegenField, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null /* default declaringClass */); - } - } else { - if ((this.bits & ASTNode.DepthMASK) != 0) { - ReferenceBinding targetType = currentScope.enclosingSourceType().enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT); - Object[] emulationPath = currentScope.getEmulationPath(targetType, true /*only exact match*/, false/*consider enclosing arg*/); - codeStream.generateOuterAccess(emulationPath, this, targetType, currentScope); - } else { - codeStream.aload_0(); - } - codeStream.dup(); - if ((this.syntheticAccessors == null) || (this.syntheticAccessors[SingleNameReference.READ] == null)) { - TypeBinding constantPoolDeclaringClass = CodeStream.getConstantPoolDeclaringClass(currentScope, codegenField, this.actualReceiverType, true /* implicit this */); - codeStream.fieldAccess(Opcodes.OPC_getfield, codegenField, constantPoolDeclaringClass); - } else { - codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null /* default declaringClass */); - } - } - TypeBinding operandType; - if (this.genericCast != null) { - codeStream.checkcast(this.genericCast); - operandType = this.genericCast; - } else { - operandType = codegenField.type; - } - if (valueRequired) { - if (codegenField.isStatic()) { - switch (operandType.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2(); - break; - default: - codeStream.dup(); - break; - } - } else { // Stack: [owner][old field value] ---> [old field value][owner][old field value] - switch (operandType.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2_x1(); - break; - default: - codeStream.dup_x1(); - break; - } - } - } - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion); - codeStream.sendOperator(postIncrement.operator, this.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion); - fieldStore(currentScope, codeStream, codegenField, this.syntheticAccessors == null ? null : this.syntheticAccessors[SingleNameReference.WRITE], this.actualReceiverType, true /*implicit this*/, false); - // no need for generic cast - return; - case Binding.LOCAL : // assigning to a local variable - LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=185682 - // check if postIncrement is the only usage of this local - Reference.reportOnlyUselesslyReadLocal(currentScope, localBinding, valueRequired); - if (localBinding.resolvedPosition == -1) { - if (valueRequired) { - // restart code gen - localBinding.useFlag = LocalVariableBinding.USED; - throw new AbortMethod(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, null); - } - return; - } - - // using incr bytecode if possible - if (TypeBinding.equalsEquals(localBinding.type, TypeBinding.INT)) { - if (valueRequired) { - codeStream.load(localBinding); - } - if (postIncrement.operator == OperatorIds.PLUS) { - codeStream.iinc(localBinding.resolvedPosition, 1); - } else { - codeStream.iinc(localBinding.resolvedPosition, -1); - } - } else { - codeStream.load(localBinding); - if (valueRequired){ - switch (localBinding.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2(); - break; - default: - codeStream.dup(); - break; - } - } - codeStream.generateImplicitConversion(this.implicitConversion); - codeStream.generateConstant(postIncrement.expression.constant, this.implicitConversion); - codeStream.sendOperator(postIncrement.operator, this.implicitConversion & TypeIds.COMPILE_TYPE_MASK); - codeStream.generateImplicitConversion(postIncrement.preAssignImplicitConversion); - codeStream.store(localBinding, false); - } - } -} - -public void generateReceiver(CodeStream codeStream) { - codeStream.aload_0(); -} - -/** - * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments() - */ -@Override -public TypeBinding[] genericTypeArguments() { - return null; -} - -@Override -public boolean isEquivalent(Reference reference) { - char[] otherToken = null; - if (reference instanceof SingleNameReference) { - otherToken = ((SingleNameReference) reference).token; - } else if (reference instanceof FieldReference) { - // test for comparison "f1" vs. "this.f1": - FieldReference fr = (FieldReference) reference; - if (fr.receiver.isThis() && !(fr.receiver instanceof QualifiedThisReference)) - otherToken = fr.token; - } - return otherToken != null && CharOperation.equals(this.token, otherToken); -} - -/** - * Returns the local variable referenced by this node. Can be a direct reference (SingleNameReference) - * or thru a cast expression etc... - */ -@Override -public LocalVariableBinding localVariableBinding() { - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - break; - case Binding.LOCAL : // reading a local variable - return (LocalVariableBinding) this.binding; - } - return null; -} - -@Override -public VariableBinding nullAnnotatedVariableBinding(boolean supportTypeAnnotations) { - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.FIELD : // reading a field - case Binding.LOCAL : // reading a local variable - if (supportTypeAnnotations - || (((VariableBinding)this.binding).tagBits & TagBits.AnnotationNullMASK) != 0) - return (VariableBinding) this.binding; - } - return null; -} - -@Override -public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - if ((this.implicitConversion & TypeIds.BOXING) != 0) - return FlowInfo.NON_NULL; - LocalVariableBinding local = localVariableBinding(); - if (local != null) { - return flowInfo.nullStatus(local); - } - return super.nullStatus(flowInfo, flowContext); -} - -public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - //If inlinable field, forget the access emulation, the code gen will directly target it - if (((this.bits & ASTNode.DepthMASK) == 0 && (this.bits & ASTNode.IsCapturedOuterLocal) == 0) || (this.constant != Constant.NotAConstant)) { - return; - } - if ((this.bits & ASTNode.RestrictiveFlagMASK) == Binding.LOCAL) { - LocalVariableBinding localVariableBinding = (LocalVariableBinding) this.binding; - if (localVariableBinding != null) { - if (localVariableBinding.isUninitializedIn(currentScope)) { - // local was tagged as uninitialized - return; - } - if ((localVariableBinding.tagBits & TagBits.IsEffectivelyFinal) == 0) { - // local was tagged as not effectively final - return; - } - switch(localVariableBinding.useFlag) { - case LocalVariableBinding.FAKE_USED : - case LocalVariableBinding.USED : - currentScope.emulateOuterAccess(localVariableBinding); - } - } - } -} - -public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return; - - //If inlinable field, forget the access emulation, the code gen will directly target it - if (this.constant != Constant.NotAConstant) - return; - - if ((this.bits & Binding.FIELD) != 0) { - FieldBinding fieldBinding = (FieldBinding) this.binding; - FieldBinding codegenField = fieldBinding.original(); - if (((this.bits & ASTNode.DepthMASK) != 0) - && ((codegenField.isPrivate() // private access - && !currentScope.enclosingSourceType().isNestmateOf(codegenField.declaringClass) ) - || (codegenField.isProtected() // implicit protected access - && codegenField.declaringClass.getPackage() != currentScope.enclosingSourceType().getPackage()))) { - if (this.syntheticAccessors == null) - this.syntheticAccessors = new MethodBinding[2]; - this.syntheticAccessors[isReadAccess ? SingleNameReference.READ : SingleNameReference.WRITE] = - ((SourceTypeBinding)currentScope.enclosingSourceType(). - enclosingTypeAt((this.bits & ASTNode.DepthMASK) >> ASTNode.DepthSHIFT)).addSyntheticMethod(codegenField, isReadAccess, false /*not super access*/); - currentScope.problemReporter().needToEmulateFieldAccess(codegenField, this, isReadAccess); - return; - } - } -} - -/** - * @see org.eclipse.jdt.internal.compiler.ast.Expression#postConversionType(Scope) - */ -@Override -public TypeBinding postConversionType(Scope scope) { - TypeBinding convertedType = this.resolvedType; - if (this.genericCast != null) - convertedType = this.genericCast; - int runtimeType = (this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4; - switch (runtimeType) { - case T_boolean : - convertedType = TypeBinding.BOOLEAN; - break; - case T_byte : - convertedType = TypeBinding.BYTE; - break; - case T_short : - convertedType = TypeBinding.SHORT; - break; - case T_char : - convertedType = TypeBinding.CHAR; - break; - case T_int : - convertedType = TypeBinding.INT; - break; - case T_float : - convertedType = TypeBinding.FLOAT; - break; - case T_long : - convertedType = TypeBinding.LONG; - break; - case T_double : - convertedType = TypeBinding.DOUBLE; - break; - default : - } - if ((this.implicitConversion & TypeIds.BOXING) != 0) { - convertedType = scope.environment().computeBoxingType(convertedType); - } - return convertedType; -} - -@Override -public StringBuilder printExpression(int indent, StringBuilder output){ - return output.append(this.token); -} -public TypeBinding reportError(BlockScope scope) { - //=====error cases======= - this.constant = Constant.NotAConstant; - if (this.binding instanceof ProblemFieldBinding) { - scope.problemReporter().invalidField(this, (FieldBinding) this.binding); - } else if (this.binding instanceof ProblemReferenceBinding || this.binding instanceof MissingTypeBinding) { - scope.problemReporter().invalidType(this, (TypeBinding) this.binding); - } else { - scope.problemReporter().unresolvableReference(this, this.binding); - } - return null; -} - -@Override -public TypeBinding resolveType(BlockScope scope) { - // for code gen, harm the restrictiveFlag - - if (this.actualReceiverType != null) { - this.binding = scope.getField(this.actualReceiverType, this.token, this); - } else { - this.actualReceiverType = scope.enclosingSourceType(); - this.binding = scope.getBinding(this.token, this.bits & ASTNode.RestrictiveFlagMASK, this, true /*resolve*/); - } - if (this.binding.isValidBinding()) { - switch (this.bits & ASTNode.RestrictiveFlagMASK) { - case Binding.VARIABLE : // =========only variable============ - case Binding.VARIABLE | Binding.TYPE : //====both variable and type============ - if (this.binding instanceof VariableBinding) { - VariableBinding variable = (VariableBinding) this.binding; - TypeBinding variableType; - if (this.binding instanceof LocalVariableBinding) { - this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits - this.bits |= Binding.LOCAL; - ((LocalVariableBinding) this.binding).markReferenced(); - if (!variable.isFinal() && (this.bits & ASTNode.IsCapturedOuterLocal) != 0) { - if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) // for 8, defer till effective finality could be ascertained. - scope.problemReporter().cannotReferToNonFinalOuterLocal((LocalVariableBinding)variable, this); - } - checkLocalStaticClassVariables(scope, variable); - variableType = variable.type; - this.constant = (this.bits & ASTNode.IsStrictlyAssigned) == 0 ? variable.constant(scope) : Constant.NotAConstant; - } else { - // a field - variableType = checkFieldAccess(scope); - } - // perform capture conversion if read access - if (variableType != null) { - this.resolvedType = variableType = (((this.bits & ASTNode.IsStrictlyAssigned) == 0) - ? variableType.capture(scope, this.sourceStart, this.sourceEnd) - : variableType); - if ((variableType.tagBits & TagBits.HasMissingType) != 0) { - if ((this.bits & Binding.LOCAL) == 0) { - // only complain if field reference (for local, its type got flagged already) - scope.problemReporter().invalidType(this, variableType); - } - return null; - } - } - return variableType; - } - - // thus it was a type - this.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits - this.bits |= Binding.TYPE; - //$FALL-THROUGH$ - case Binding.TYPE : //========only type============== - this.constant = Constant.NotAConstant; - //deprecated test - TypeBinding type = (TypeBinding)this.binding; - if (isTypeUseDeprecated(type, scope)) - scope.problemReporter().deprecatedType(type, this); - type = scope.environment().convertToRawType(type, false /*do not force conversion of enclosing types*/); - return this.resolvedType = type; - } - } - // error scenario - return this.resolvedType = reportError(scope); -} - -private void checkLocalStaticClassVariables(BlockScope scope, VariableBinding variable) { - if (this.actualReceiverType.isStatic() && this.actualReceiverType.isLocalType()) { - if ((variable.modifiers & ClassFileConstants.AccStatic) == 0 && - (this.bits & ASTNode.IsCapturedOuterLocal) != 0) { - BlockScope declaringScope = ((LocalVariableBinding) this.binding).declaringScope; - MethodScope declaringMethodScope = declaringScope instanceof MethodScope ? (MethodScope)declaringScope : - declaringScope.enclosingMethodScope(); - MethodScope currentMethodScope = scope instanceof MethodScope ? (MethodScope) scope : scope.enclosingMethodScope(); - ClassScope declaringClassScope = declaringMethodScope != null ? declaringMethodScope.classScope() : null; - ClassScope currentClassScope = currentMethodScope != null ? currentMethodScope.classScope() : null; - if (declaringClassScope != currentClassScope) - scope.problemReporter().recordStaticReferenceToOuterLocalVariable((LocalVariableBinding)variable, this); - } - } -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} - -@Override -public void traverse(ASTVisitor visitor, ClassScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} - -@Override -public String unboundReferenceErrorName(){ - return new String(this.token); -} - -@Override -public char[][] getName() { - return new char[][] {this.token}; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java deleted file mode 100644 index f2fe2e7..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SingleTypeReference.java +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; - -public class SingleTypeReference extends TypeReference { - - public char[] token; - - public SingleTypeReference(char[] source, int start, int end) { - this.token = source; - this.sourceStart = start; - this.sourceEnd = end; -} - public SingleTypeReference(char[] source, long pos) { - this.token = source; - this.sourceStart = (int) (pos>>>32); - this.sourceEnd = (int) (pos & 0x00000000FFFFFFFFL); - } - - @Override - public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { - int totalDimensions = this.dimensions() + additionalDimensions; - Annotation [][] allAnnotations = getMergedAnnotationsOnDimensions(additionalDimensions, additionalAnnotations); - ArrayTypeReference arrayTypeReference = new ArrayTypeReference(this.token, totalDimensions, allAnnotations, (((long) this.sourceStart) << 32) + this.sourceEnd); - arrayTypeReference.annotations = this.annotations; - arrayTypeReference.bits |= (this.bits & ASTNode.HasTypeAnnotations); - if (!isVarargs) - arrayTypeReference.extendedDimensions = additionalDimensions; - return arrayTypeReference; - } - - @Override - public char[] getLastToken() { - return this.token; - } - @Override - protected TypeBinding getTypeBinding(Scope scope) { - if (this.resolvedType != null) - return this.resolvedType; - - this.resolvedType = scope.getType(this.token); - - if (this.resolvedType instanceof TypeVariableBinding) { - TypeVariableBinding typeVariable = (TypeVariableBinding) this.resolvedType; - if (typeVariable.declaringElement instanceof SourceTypeBinding) { - scope.tagAsAccessingEnclosingInstanceStateOf((ReferenceBinding) typeVariable.declaringElement, true /* type variable access */); - } - } else if (this.resolvedType instanceof LocalTypeBinding) { - LocalTypeBinding localType = (LocalTypeBinding) this.resolvedType; - MethodScope methodScope = scope.methodScope(); - if (methodScope != null && !methodScope.isStatic) { - methodScope.tagAsAccessingEnclosingInstanceStateOf(localType, false /* ! type variable access */); - } - } - - if (scope.kind == Scope.CLASS_SCOPE && this.resolvedType.isValidBinding()) - if (((ClassScope) scope).detectHierarchyCycle(this.resolvedType, this)) - return null; - return this.resolvedType; - } - - @Override - public char [][] getTypeName() { - return new char[][] { this.token }; - } - - @Override - public boolean isBaseTypeReference() { - return this.token == BYTE || - this.token == SHORT || - this.token == INT || - this.token == LONG || - this.token == FLOAT || - this.token == DOUBLE || - this.token == CHAR || - this.token == BOOLEAN || - this.token == NULL || - this.token == VOID; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output){ - if (this.annotations != null && this.annotations[0] != null) { - printAnnotations(this.annotations[0], output); - output.append(' '); - } - return output.append(this.token); - } - - public TypeBinding resolveTypeEnclosing(BlockScope scope, ReferenceBinding enclosingType) { - this.resolvedType = scope.getMemberType(this.token, enclosingType); - boolean hasError = false; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=391500 - resolveAnnotations(scope, 0); // defaultNullness not relevant, the only caller within the compiler: QAE - TypeBinding memberType = this.resolvedType; // load after possible update in resolveAnnotations() - if (!memberType.isValidBinding()) { - hasError = true; - scope.problemReporter().invalidEnclosingType(this, memberType, enclosingType); - memberType = ((ReferenceBinding)memberType).closestMatch(); - if (memberType == null) { - return null; - } - } - if (isTypeUseDeprecated(memberType, scope)) - reportDeprecatedType(memberType, scope); - memberType = scope.environment().convertToRawType(memberType, false /*do not force conversion of enclosing types*/); - if (memberType.isRawType() - && (this.bits & IgnoreRawTypeCheck) == 0 - && scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore){ - scope.problemReporter().rawTypeReference(this, memberType); - } - if (hasError) { - // do not store the computed type, keep the problem type instead - return memberType; - } - return this.resolvedType = memberType; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - Annotation [] typeAnnotations = this.annotations[0]; - for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) - typeAnnotations[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - Annotation [] typeAnnotations = this.annotations[0]; - for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) - typeAnnotations[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - @Override - public void updateWithAnnotations(Scope scope, int location) { - super.updateWithAnnotations(scope, location); - if (this.resolvedType instanceof TypeVariableBinding && !this.resolvedType.hasNullTypeAnnotations()) { - // refresh this binding in case a decorated binding was created during ClassScope.connectTypeVariables() - TypeVariableBinding tvb = (TypeVariableBinding) this.resolvedType; - Binding declaringElement = tvb.declaringElement; - if (declaringElement instanceof ReferenceBinding) { - TypeVariableBinding[] typeVariables = ((ReferenceBinding) declaringElement).typeVariables(); - if (typeVariables != null && tvb.rank < typeVariables.length) { - TypeVariableBinding refreshed = typeVariables[tvb.rank]; - if (refreshed != null && refreshed.id == this.resolvedType.id) - this.resolvedType = refreshed; - } - } - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Statement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Statement.java deleted file mode 100644 index 754e01f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Statement.java +++ /dev/null @@ -1,537 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * 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 - * bug 186342 - [compiler][null] Using annotations for null checking - * bug 365983 - [compiler][null] AIOOB with null annotation analysis and varargs - * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK - * bug 370930 - NonNull annotation not considered for enhanced for loops - * bug 365859 - [compiler][null] distinguish warnings based on flow analysis vs. null annotations - * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Bug 415291 - [1.8][null] differentiate type incompatibilities due to null annotations - * Bug 392238 - [1.8][compiler][null] Detect semantically invalid null type annotations - * Bug 416307 - [1.8][compiler][null] subclass with type parameter substitution confuses null checking - * Bug 417758 - [1.8][null] Null safety compromise during array creation. - * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) - * Bug 424415 - [1.8][compiler] Eventual resolution of ReferenceExpression is not seen to be happening. - * Bug 418537 - [1.8][null] Fix null type annotation analysis for poly conditional expressions - * Bug 428352 - [1.8][compiler] Resolution errors don't always surface - * Bug 429430 - [1.8] Lambdas and method reference infer wrong exception type with generics (RuntimeException instead of IOException) - * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations - * Bug 453483 - [compiler][null][loop] Improve null analysis for loops - * Bug 455723 - Nonnull argument not correctly inferred in loop - * Andy Clement - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - * Bug 409250 - [1.8][compiler] Various loose ends in 308 code generation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching.CheckMode; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public abstract class Statement extends ASTNode { - - /** - * Answers true if the if is identified as a known coding pattern which - * should be tolerated by dead code analysis. - * e.g. if (DEBUG) print(); // no complaint - * Only invoked when overall condition is known to be optimizeable into false/true. - */ - protected static boolean isKnowDeadCodePattern(Expression expression) { - // if (!DEBUG) print(); - tolerated - if (expression instanceof UnaryExpression) { - expression = ((UnaryExpression) expression).expression; - } - // if (DEBUG) print(); - tolerated - if (expression instanceof Reference) return true; - -// if (expression instanceof BinaryExpression) { -// BinaryExpression binary = (BinaryExpression) expression; -// switch ((binary.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT/* operator */) { -// case OperatorIds.AND_AND : -// case OperatorIds.OR_OR : -// break; -// default: -// // if (DEBUG_LEVEL > 0) print(); - tolerated -// if ((binary.left instanceof Reference) && binary.right.constant != Constant.NotAConstant) -// return true; -// // if (0 < DEBUG_LEVEL) print(); - tolerated -// if ((binary.right instanceof Reference) && binary.left.constant != Constant.NotAConstant) -// return true; -// } -// } - return false; - } -public abstract FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo); -/** Lambda shape analysis: *Assuming* this is reachable, analyze if this completes normally i.e control flow can reach the textually next statement. - For blocks, we don't perform intra-reachability analysis. We assume the lambda body is free of intrinsic control flow errors (if such errors - exist they will not be flagged by this analysis, but are guaranteed to surface later on.) - - @see Block#doesNotCompleteNormally() -*/ -public boolean doesNotCompleteNormally() { - return false; -} - -/** Lambda shape analysis: *Assuming* this is reachable, analyze if this completes by continuing i.e control flow cannot reach the textually next statement. - This is necessitated by the fact that continue claims to not complete normally. So this is necessary to discriminate between do { continue; } while (false); - which completes normally and do { throw new Exception(); } while (false); which does not complete normally. -*/ -public boolean completesByContinue() { - return false; -} - -/** - * Switch Expression analysis: *Assuming* this is reachable, analyze if this completes normally - * i.e control flow can reach the textually next statement, as per JLS 14 Sec 14.22 - * For blocks, we don't perform intra-reachability analysis. - * Note: delinking this from a similar (opposite) {@link #doesNotCompleteNormally()} since that was - * coded for a specific purpose of Lambda Shape Analysis. - */ -public boolean canCompleteNormally() { - return true; -} -/** - * The equivalent function of completesByContinue - implements both the rules concerning continue with - * and without a label. - */ -public boolean continueCompletes() { - return false; -} - public static final int NOT_COMPLAINED = 0; - public static final int COMPLAINED_FAKE_REACHABLE = 1; - public static final int COMPLAINED_UNREACHABLE = 2; - -/** Analysing arguments of MessageSend, ExplicitConstructorCall, AllocationExpression. */ -protected void analyseArguments(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, MethodBinding methodBinding, Expression[] arguments) -{ - // compare actual null-status against parameter annotations of the called method: - if (arguments != null) { - CompilerOptions compilerOptions = currentScope.compilerOptions(); - if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_7 && methodBinding.isPolymorphic()) - return; - boolean considerTypeAnnotations = currentScope.environment().usesNullTypeAnnotations(); - boolean hasJDK15FlowAnnotations = methodBinding.parameterFlowBits != null; - int numParamsToCheck = methodBinding.parameters.length; - int varArgPos = -1; - TypeBinding varArgsType = null; - boolean passThrough = false; - if (considerTypeAnnotations || hasJDK15FlowAnnotations) { - // check if varargs need special treatment: - if (methodBinding.isVarargs()) { - varArgPos = numParamsToCheck-1; - // this if-block essentially copied from generateArguments(..): - varArgsType = methodBinding.parameters[varArgPos]; - if (numParamsToCheck == arguments.length) { - TypeBinding lastType = arguments[varArgPos].resolvedType; - if (lastType == TypeBinding.NULL - || (varArgsType.dimensions() == lastType.dimensions() - && lastType.isCompatibleWith(varArgsType))) - passThrough = true; // pass directly as-is - } - if (!passThrough) - numParamsToCheck--; // with non-passthrough varargs last param is fed from individual args -> don't check - } - } - if (considerTypeAnnotations) { - for (int i=0; i paramLength) { - // right number but not directly compatible or too many arguments - wrap extra into array - // called with (argLength - lastIndex) elements : foo(1, 2) or foo(1, 2, 3, 4) - // need to gen elements into an array, then gen each remaining element into created array - codeStream.generateInlinedValue(argLength - varArgIndex); - codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array - for (int i = varArgIndex; i < argLength; i++) { - codeStream.dup(); - codeStream.generateInlinedValue(i - varArgIndex); - arguments[i].generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(elementsTypeID, false); - } - } else if (argLength == paramLength) { - // right number of arguments - could be inexact - pass argument as is - TypeBinding lastType = arguments[varArgIndex].resolvedType; - if (lastType == TypeBinding.NULL - || (varArgsType.dimensions() == lastType.dimensions() - && lastType.isCompatibleWith(codeGenVarArgsType))) { - // foo(1, new int[]{2, 3}) or foo(1, null) --> last arg is passed as-is - arguments[varArgIndex].generateCode(currentScope, codeStream, true); - } else { - // right number but not directly compatible or too many arguments - wrap extra into array - // need to gen elements into an array, then gen each remaining element into created array - codeStream.generateInlinedValue(1); - codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array - codeStream.dup(); - codeStream.generateInlinedValue(0); - arguments[varArgIndex].generateCode(currentScope, codeStream, true); - codeStream.arrayAtPut(elementsTypeID, false); - } - } else { // not enough arguments - pass extra empty array - // scenario: foo(1) --> foo(1, new int[0]) - // generate code for an empty array of parameterType - codeStream.generateInlinedValue(0); - codeStream.newArray(codeGenVarArgsType); // create a mono-dimensional array - } - } else if (arguments != null) { // standard generation for method arguments - for (int i = 0, max = arguments.length; i < max; i++) - arguments[i].generateCode(currentScope, codeStream, true); - } -} - -public abstract void generateCode(BlockScope currentScope, CodeStream codeStream); - -public boolean isBoxingCompatible(TypeBinding expressionType, TypeBinding targetType, Expression expression, Scope scope) { - if (scope.isBoxingCompatibleWith(expressionType, targetType)) - return true; - - return expressionType.isBaseType() // narrowing then boxing ? Only allowed for some target types see 362279 - && !targetType.isBaseType() - && !targetType.isTypeVariable() - && scope.compilerOptions().sourceLevel >= org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_5 // autoboxing - && (targetType.id == TypeIds.T_JavaLangByte || targetType.id == TypeIds.T_JavaLangShort || targetType.id == TypeIds.T_JavaLangCharacter) - && expression.isConstantValueOfTypeAssignableToType(expressionType, scope.environment().computeBoxingType(targetType)); -} - -public boolean isEmptyBlock() { - return false; -} - -public boolean isValidJavaStatement() { - //the use of this method should be avoid in most cases - //and is here mostly for documentation purpose..... - //while the parser is responsible for creating - //welled formed expression statement, which results - //in the fact that java-non-semantic-expression-used-as-statement - //should not be parsed...thus not being built. - //It sounds like the java grammar as help the compiler job in removing - //-by construction- some statement that would have no effect.... - //(for example all expression that may do side-effects are valid statement - // -this is an approximative idea.....-) - - return true; -} - -@Override -public StringBuilder print(int indent, StringBuilder output) { - return printStatement(indent, output); -} - -public abstract StringBuilder printStatement(int indent, StringBuilder output); - -public abstract void resolve(BlockScope scope); -public LocalVariableBinding[] bindingsWhenTrue() { - return NO_VARIABLES; -} -public LocalVariableBinding[] bindingsWhenFalse() { - return NO_VARIABLES; -} -public LocalVariableBinding[] bindingsWhenComplete() { - return NO_VARIABLES; -} - -public void resolveWithBindings(LocalVariableBinding[] bindings, BlockScope scope) { - scope.include(bindings); - try { - this.resolve(scope); - } finally { - scope.exclude(bindings); - } -} -/** - * Returns the resolved expression if any associated to this statement - used - * parameter statement has to be either a SwitchStatement or a SwitchExpression - */ -public TypeBinding resolveExpressionType(BlockScope scope) { - return null; -} -public boolean containsPatternVariable() { - return false; -} -/** - * Implementation of {@link org.eclipse.jdt.internal.compiler.lookup.InvocationSite#invocationTargetType} - * suitable at this level. Subclasses should override as necessary. - * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#invocationTargetType() - */ -public TypeBinding invocationTargetType() { - return null; -} -/** Simpler notion of expected type, suitable for code assist purposes. */ -public TypeBinding expectedType() { - // for all but FunctionalExpressions, this is the same as invocationTargetType. - return invocationTargetType(); -} -public ExpressionContext getExpressionContext() { - return ExpressionContext.VANILLA_CONTEXT; -} -/** - * For all constructor invocations: find the constructor binding; - * if site.innersNeedUpdate() perform some post processing for those and produce - * any updates as side-effects into 'argumentTypes'. - */ -protected MethodBinding findConstructorBinding(BlockScope scope, Invocation site, ReferenceBinding receiverType, TypeBinding[] argumentTypes) { - MethodBinding ctorBinding = scope.getConstructor(receiverType, argumentTypes, site); - return resolvePolyExpressionArguments(site, ctorBinding, argumentTypes, scope); -} -} - diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java deleted file mode 100644 index 08fa3c8..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/StringLiteral.java +++ /dev/null @@ -1,148 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.impl.StringConstant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class StringLiteral extends Literal { - - /** may be null, prefixes tail **/ - protected StringLiteral optionalHead; - /** StringLiteral or char[] tail **/ - protected Object tail; - /** zero based **/ - private final int lineNumber; - - public StringLiteral(char[] token, int start, int end, int lineNumber1based) { - this(null, token, start, end, lineNumber1based - 1); - } - - protected StringLiteral(StringLiteral optionalHead, Object tail, int start, int end, int lineNumber) { - super(start, end); - this.optionalHead = optionalHead; - this.tail = tail; - this.lineNumber = lineNumber; - } - - public StringLiteral(int s, int e) { - this(null, null, s, e, 0); - } - - @Override - public void computeConstant() { - this.constant = StringConstant.fromValue(String.valueOf(this.source())); - } - - /** - * creates a copy of dedicated Type for optimizeStringLiterals with the given CharLiteral appended - */ - public ExtendedStringLiteral extendWith(CharLiteral lit) { - char[] charTail = new char[] { lit.value }; - return new ExtendedStringLiteral(this, charTail, this.sourceStart, lit.sourceEnd, this.getLineNumber()); - } - - /** - * creates a copy of dedicated Type for optimizeStringLiterals with the given StringLiteral appended - */ - public ExtendedStringLiteral extendWith(StringLiteral lit) { - return new ExtendedStringLiteral(this, lit, this.sourceStart, lit.sourceEnd, this.getLineNumber()); - } - - /** - * creates a copy of dedicated Type for unoptimizeStringLiterals with the given StringLiteral appended - */ - public StringLiteralConcatenation extendsWith(StringLiteral lit) { - return new StringLiteralConcatenation(this, lit); - } - - /** - * Code generation for string literal - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (valueRequired) - codeStream.ldc(this.constant.stringValue()); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public TypeBinding literalType(BlockScope scope) { - return scope.getJavaLangString(); - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - // handle some special char..... - output.append('\"'); - for (char s : source()) { - Util.appendEscapedChar(output, s, true); - } - output.append('\"'); - return output; - } - - @Override - public char[] source() { - if (this.optionalHead == null && this.tail instanceof char[] ch) { - // fast path without copy - return ch; - } - // flatten linked list to char[] - int size = append(null, 0, this); - char[] result = new char[size]; - append(result, 0, this); - flatten(result); - return result; - } - - protected void flatten(char[] result) { - setSource(result); // keep flat version - } - - private static int append(char[] result, int length, StringLiteral o) { - do { - if (o.tail instanceof char[] c) { - if (result != null) { - System.arraycopy(c, 0, result, result.length - c.length - length, c.length); - } - length += c.length; - } else { - length = append(result, length, ((StringLiteral) o.tail)); - } - o = o.optionalHead; - } while (o != null); - return length; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); - } - - public void setSource(char[] source) { - this.tail = source; - this.optionalHead = null; - } - - public int getLineNumber() { - return this.lineNumber; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/StringLiteralConcatenation.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/StringLiteralConcatenation.java deleted file mode 100644 index 0644b89..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/StringLiteralConcatenation.java +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; - -/** - * Flatten string literal - */ -public class StringLiteralConcatenation extends StringLiteral { - - /** - * Build a two-strings literal - */ - public StringLiteralConcatenation(StringLiteral str1, StringLiteral lit) { - super(str1, lit, str1.sourceStart, lit.sourceEnd, str1.getLineNumber()); - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - output.append("StringLiteralConcatenation{"); //$NON-NLS-1$ - for (StringLiteral lit : getLiterals()) { - lit.printExpression(indent, output); - output.append("+\n");//$NON-NLS-1$ - } - return output.append('}'); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - for (StringLiteral lit : getLiterals()) { - lit.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - public StringLiteral[] getLiterals() { - int size = append(null, 0, this); - StringLiteral[] result = new StringLiteral[size]; - append(result, 0, this); - return result; - } - - private static int append(StringLiteral[] result, int length, StringLiteral o) { - do { - if (o.tail instanceof StringLiteral l) { - if (result != null) { - result[result.length - 1 - length] = l; - } - length += 1; - } else { - if (result != null) { - result[result.length - 1 - length] = o; - } - length += 1; - } - o = o.optionalHead; - } while (o != null); - return length; - } - - @Override - protected void flatten(char[] result) { - // don't store flattened representation: getLiterals() still needs the linked list - } - - @Override - public void setSource(char[] source) { - throw new UnsupportedOperationException(); - } - -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/StringTemplate.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/StringTemplate.java deleted file mode 100644 index 53ad072..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/StringTemplate.java +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2023, 2024 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class StringTemplate extends Expression { - private StringLiteral[] fragments; - private Expression[] values; - public boolean isMultiline; - public StringTemplate(StringLiteral[] fragments, Expression[] values, int start, int end, boolean isMultiline) { - this.fragments = fragments; - this.values = values; - this.sourceStart = start; - this.sourceEnd = end; - this.isMultiline = isMultiline; - } - - public StringLiteral[] fragments() { - return this.fragments; - } - public Expression[] values() { - return this.values; - } - @Override - public void resolve(BlockScope scope) { - for (StringLiteral frag : this.fragments) { - frag.resolveType(scope); - } - for (Expression exp : this.values) { - if (exp == null) { - continue; - } - exp.resolveType(scope); - } - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - this.constant = Constant.NotAConstant; - return this.resolvedType = scope.getJavaLangStringTemplate(); - } - - private void generateNewTemplateBootstrap(CodeStream codeStream) { - int index = codeStream.classFile.recordBootstrapMethod(this); - // Kludge, see if this can be moved to CodeStream - codeStream.stackDepth ++; - if (codeStream.stackDepth > codeStream.stackMax) { - codeStream.stackMax = codeStream.stackDepth; - } - StringBuilder signature = new StringBuilder("("); //$NON-NLS-1$ - for (Expression exp : this.values) { - TypeBinding type = exp.resolvedType; - if (type == TypeBinding.NULL) - signature.append(ConstantPool.JavaLangObjectSignature); - else - signature.append(type.signature()); - } - signature.append(")Ljava/lang/StringTemplate;"); //$NON-NLS-1$ - codeStream.invokeDynamic(index, - 1, // - 1, // int - ConstantPool.PROCESS, - signature.toString().toCharArray(), - TypeIds.T_int, - TypeBinding.INT); - } - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - for (Expression exp : this.values) { - flowInfo = exp.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits(); - } - return flowInfo; - } - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - for (Expression exp : this.values) { - exp.generateCode(currentScope, codeStream, valueRequired); - } - - generateNewTemplateBootstrap(codeStream); - int pc = codeStream.position; - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - int length = this.fragments.length; - output.append('\"'); - if (this.isMultiline) - output.append("\"\"\n"); //$NON-NLS-1$ - for (int i = 0; i < length; i++) { - char[] source = this.fragments[i].source(); - for (int j = 0; j < source.length; j++) { - Util.appendEscapedChar(output, source[j], true); - } - if (i + 1 < length) { - output.append("\\{"); //$NON-NLS-1$ - if (this.values[i] != null) { - this.values[i].printExpression(0, output); - } - output.append("}"); //$NON-NLS-1$ - } - } - output.append('\"'); - if (this.isMultiline) - output.append("\"\""); //$NON-NLS-1$ - return output; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java deleted file mode 100644 index 044cfa1..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SubRoutineStatement.java +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.ExceptionLabel; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; - -/** - * Extra behavior for statements which are generating subroutines - */ -public abstract class SubRoutineStatement extends Statement { - - public static void reenterAllExceptionHandlers(SubRoutineStatement[] subroutines, int max, CodeStream codeStream) { - if (subroutines == null) return; - if (max < 0) max = subroutines.length; - for (int i = 0; i < max; i++) { - SubRoutineStatement sub = subroutines[i]; - sub.enterAnyExceptionHandler(codeStream); - sub.enterDeclaredExceptionHandlers(codeStream); - } - } - - ExceptionLabel anyExceptionLabel; - protected SwitchExpression switchExpression = null; - - public ExceptionLabel enterAnyExceptionHandler(CodeStream codeStream) { - - if (this.anyExceptionLabel == null) { - this.anyExceptionLabel = new ExceptionLabel(codeStream, null /*any exception*/); - } - this.anyExceptionLabel.placeStart(); - return this.anyExceptionLabel; - } - - public void enterDeclaredExceptionHandlers(CodeStream codeStream) { - // do nothing by default - } - - public void exitAnyExceptionHandler() { - if (this.anyExceptionLabel != null) { - this.anyExceptionLabel.placeEnd(); - } - } - - public void exitDeclaredExceptionHandlers(CodeStream codeStream) { - // do nothing by default - } - - - /** - * Generate an invocation of a subroutine (e.g. jsr finally) in current context. - * @return boolean, true if the generated code will abrupt completion - */ - public abstract boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal); - - public abstract boolean isSubRoutineEscaping(); - - public void placeAllAnyExceptionHandler() { - this.anyExceptionLabel.place(); - } - - public SwitchExpression getSwitchExpression() { - return this.switchExpression; - } - - public void setSwitchExpression(SwitchExpression switchExpression) { - this.switchExpression = switchExpression; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SuperReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SuperReference.java deleted file mode 100644 index 2c96e44..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SuperReference.java +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Jesper S Moller - Contributions for - * Bug 378674 - "The method can be declared as static" is wrong - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -public class SuperReference extends ThisReference { - - public SuperReference(int sourceStart, int sourceEnd) { - - super(sourceStart, sourceEnd); - } - - public static ExplicitConstructorCall implicitSuperConstructorCall() { - - return new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); - } - - @Override - public boolean isImplicitThis() { - - return false; - } - - @Override - public boolean isSuper() { - - return true; - } - - @Override - public boolean isUnqualifiedSuper() { - return true; - } - - @Override - public boolean isThis() { - - return false ; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output){ - - return output.append("super"); //$NON-NLS-1$ - - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - - this.constant = Constant.NotAConstant; - ReferenceBinding enclosingReceiverType = scope.enclosingReceiverType(); - if (!checkAccess(scope, enclosingReceiverType)) - return null; - if (enclosingReceiverType.id == T_JavaLangObject) { - scope.problemReporter().cannotUseSuperInJavaLangObject(this); - return null; - } - return this.resolvedType = enclosingReceiverType.superclass(); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope blockScope) { - visitor.visit(this, blockScope); - visitor.endVisit(this, blockScope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java deleted file mode 100644 index f599df9..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SwitchExpression.java +++ /dev/null @@ -1,760 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018, 2023 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 - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.ASSIGNMENT_CONTEXT; -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.INVOCATION_CONTEXT; -import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.VANILLA_CONTEXT; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.stream.Collectors; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -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.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.PolyTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -public class SwitchExpression extends SwitchStatement implements IPolyExpression { - - /* package */ TypeBinding expectedType; - private ExpressionContext expressionContext = VANILLA_CONTEXT; - private boolean isPolyExpression = false; - private TypeBinding[] originalValueResultExpressionTypes; - private TypeBinding[] finalValueResultExpressionTypes; - /* package */ Map originalTypeMap = new HashMap<>(); - - - private int nullStatus = FlowInfo.UNKNOWN; - public List resultExpressions; - public boolean resolveAll; - /* package */ List resultExpressionNullStatus; - LocalVariableBinding hiddenYield; - /* package */ int hiddenYieldResolvedPosition = -1; - public boolean containsTry = false; - private static Map type_map; - static final char[] SECRET_YIELD_VALUE_NAME = " yieldValue".toCharArray(); //$NON-NLS-1$ - int yieldResolvedPosition = -1; - List typesOnStack; - - static { - type_map = new HashMap<>(); - type_map.put(TypeBinding.CHAR, new TypeBinding[] {TypeBinding.CHAR, TypeBinding.INT}); - type_map.put(TypeBinding.SHORT, new TypeBinding[] {TypeBinding.SHORT, TypeBinding.BYTE, TypeBinding.INT}); - type_map.put(TypeBinding.BYTE, new TypeBinding[] {TypeBinding.BYTE, TypeBinding.INT}); - } - - @Override - public void setExpressionContext(ExpressionContext context) { - this.expressionContext = context; - } - - @Override - public void setExpectedType(TypeBinding expectedType) { - this.expectedType = expectedType; - } - - @Override - public ExpressionContext getExpressionContext() { - return this.expressionContext; - } - @Override - protected boolean ignoreMissingDefaultCase(CompilerOptions compilerOptions, boolean isEnumSwitch) { - return isEnumSwitch; // mandatory error if not enum in switch expressions - } - @Override - protected void reportMissingEnumConstantCase(BlockScope upperScope, FieldBinding enumConstant) { - upperScope.problemReporter().missingEnumConstantCase(this, enumConstant); - } - @Override - protected int getFallThroughState(Statement stmt, BlockScope blockScope) { - if ((stmt instanceof Expression && ((Expression) stmt).isTrulyExpression())|| stmt instanceof ThrowStatement) - return BREAKING; - if ((this.switchBits & LabeledRules) != 0 // do this check for every block if '->' (Switch Labeled Rules) - && stmt instanceof Block) { - Block block = (Block) stmt; - if (!block.canCompleteNormally()) { - return BREAKING; - } - } - return FALLTHROUGH; - } - @Override - public boolean checkNPE(BlockScope skope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - if ((this.nullStatus & FlowInfo.NULL) != 0) - skope.problemReporter().expressionNullReference(this); - else if ((this.nullStatus & FlowInfo.POTENTIALLY_NULL) != 0) - skope.problemReporter().expressionPotentialNullReference(this); - return true; // all checking done - } - - private void computeNullStatus(FlowInfo flowInfo, FlowContext flowContext) { - boolean precomputed = this.resultExpressionNullStatus.size() > 0; - if (!precomputed) - this.resultExpressionNullStatus.add(this.resultExpressions.get(0).nullStatus(flowInfo, flowContext)); int status = this.resultExpressions.get(0).nullStatus(flowInfo, flowContext); - int combinedStatus = status; - boolean identicalStatus = true; - for (int i = 1, l = this.resultExpressions.size(); i < l; ++i) { - if (!precomputed) - this.resultExpressionNullStatus.add(this.resultExpressions.get(i).nullStatus(flowInfo, flowContext)); - int tmp = this.resultExpressions.get(i).nullStatus(flowInfo, flowContext); - identicalStatus &= status == tmp; - combinedStatus |= tmp; - } - if (identicalStatus) { - this.nullStatus = status; - return; - } - status = Expression.computeNullStatus(0, combinedStatus); - if (status > 0) - this.nullStatus = status; - } - - @Override - protected void completeNormallyCheck(BlockScope blockScope) { - int sz = this.statements != null ? this.statements.length : 0; - if (sz == 0) return; - /* JLS 12 15.28.1 Given a switch expression, if the switch block consists of switch labeled rules - * then it is a compile-time error if any switch labeled block can complete normally. - */ - if ((this.switchBits & LabeledRules) != 0) { - for (Statement stmt : this.statements) { - if (!(stmt instanceof Block)) - continue; - if (stmt.canCompleteNormally()) - blockScope.problemReporter().switchExpressionLastStatementCompletesNormally(stmt); - } - return; - } - /* JLS 12 15.28.1 - * If, on the other hand, the switch block consists of switch labeled statement groups, then it is a - * compile-time error if either the last statement in the switch block can complete normally, or the - * switch block includes one or more switch labels at the end. - */ - Statement lastNonCaseStmt = null; - Statement firstTrailingCaseStmt = null; - for (int i = sz - 1; i >= 0; i--) { - Statement stmt = this.statements[sz - 1]; - if (stmt instanceof CaseStatement) - firstTrailingCaseStmt = stmt; - else { - lastNonCaseStmt = stmt; - break; - } - } - if (lastNonCaseStmt != null) { - if (lastNonCaseStmt.canCompleteNormally()) - blockScope.problemReporter().switchExpressionLastStatementCompletesNormally(lastNonCaseStmt); - else if (lastNonCaseStmt instanceof ContinueStatement || lastNonCaseStmt instanceof ReturnStatement) { - blockScope.problemReporter().switchExpressionIllegalLastStatement(lastNonCaseStmt); - } - } - if (firstTrailingCaseStmt != null) { - blockScope.problemReporter().switchExpressionTrailingSwitchLabels(firstTrailingCaseStmt); - } - } - @Override - protected boolean needToCheckFlowInAbsenceOfDefaultBranch() { // JLS 12 16.1.8 - return (this.switchBits & LabeledRules) == 0; - } - @Override - public Expression[] getPolyExpressions() { - List polys = new ArrayList<>(); - for (Expression e : this.resultExpressions) { - Expression[] ea = e.getPolyExpressions(); - if (ea == null || ea.length ==0) continue; - polys.addAll(Arrays.asList(ea)); - } - return polys.toArray(new Expression[0]); - } - @Override - public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) { - for (Expression e : this.resultExpressions) { - if (!e.isPertinentToApplicability(targetType, method)) - return false; - } - return true; - } - @Override - public boolean isPotentiallyCompatibleWith(TypeBinding targetType, Scope scope1) { - for (Expression e : this.resultExpressions) { - if (!e.isPotentiallyCompatibleWith(targetType, scope1)) - return false; - } - return true; - } - @Override - public boolean isFunctionalType() { - for (Expression e : this.resultExpressions) { - if (e.isFunctionalType()) // return true even for one functional type - return true; - } - return false; - } - @Override - public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - if ((this.implicitConversion & TypeIds.BOXING) != 0) - return FlowInfo.NON_NULL; - return this.nullStatus; - } - @Override - protected void statementGenerateCode(BlockScope currentScope, CodeStream codeStream, Statement statement) { - if (!(statement instanceof Expression && ((Expression) statement).isTrulyExpression()) - || statement instanceof Assignment - || statement instanceof MessageSend - || (statement instanceof SwitchStatement && !(statement instanceof SwitchExpression))) { - super.statementGenerateCode(currentScope, codeStream, statement); - return; - } - Expression expression1 = (Expression) statement; - expression1.generateCode(currentScope, codeStream, true /* valueRequired */); - } - private TypeBinding createType(int typeId) { - TypeBinding type = TypeBinding.wellKnownType(this.scope, typeId); - return type != null ? type : this.scope.getJavaLangObject(); - } - private LocalVariableBinding addTypeStackVariable(CodeStream codeStream, TypeBinding type, int typeId, int index, int resolvedPosition) { - char[] name = CharOperation.concat(SECRET_YIELD_VALUE_NAME, String.valueOf(index).toCharArray()); - type = type != null ? type : createType(typeId); - LocalVariableBinding lvb = - new LocalVariableBinding( - name, - type, - ClassFileConstants.AccDefault, - false); - lvb.setConstant(Constant.NotAConstant); - lvb.useFlag = LocalVariableBinding.USED; - lvb.resolvedPosition = resolvedPosition; -// if (this.offset > 0xFFFF) { // no more than 65535 words of locals // TODO - also the cumulative at MethodScope -// problemReporter().noMoreAvailableSpaceForLocal( -// local, -// local.declaration == null ? (ASTNode)methodScope().referenceContext : local.declaration); -// } - this.scope.addLocalVariable(lvb); - lvb.declaration = new LocalDeclaration(name, 0, 0); - return lvb; - } - private int getNextOffset(LocalVariableBinding local) { - int delta = ((TypeBinding.equalsEquals(local.type, TypeBinding.LONG)) || (TypeBinding.equalsEquals(local.type, TypeBinding.DOUBLE))) ? - 2 : 1; - return local.resolvedPosition + delta; - } - private void processTypesBindingsOnStack(CodeStream codeStream) { - int count = 0; - int nextResolvedPosition = this.scope.offset; - if (!codeStream.switchSaveTypeBindings.empty()) { - this.typesOnStack = new ArrayList<>(); - int index = 0; - Stack typeStack = new Stack<>(); - int sz = codeStream.switchSaveTypeBindings.size(); - for (int i = codeStream.lastSwitchCumulativeSyntheticVars; i < sz; ++i) { - typeStack.add(codeStream.switchSaveTypeBindings.get(i)); - } - while (!typeStack.empty()) { - TypeBinding type = typeStack.pop(); - LocalVariableBinding lvb = addTypeStackVariable(codeStream, type, TypeIds.T_undefined, index++, nextResolvedPosition); - nextResolvedPosition = getNextOffset(lvb); - this.typesOnStack.add(lvb); - codeStream.store(lvb, false); - codeStream.addVariable(lvb); - ++count; - } - } - // now keep a position reserved for yield result value - this.yieldResolvedPosition = nextResolvedPosition; - nextResolvedPosition += ((TypeBinding.equalsEquals(this.resolvedType, TypeBinding.LONG)) || - (TypeBinding.equalsEquals(this.resolvedType, TypeBinding.DOUBLE))) ? - 2 : 1; - - codeStream.lastSwitchCumulativeSyntheticVars += count + 1; // 1 for yield var - int delta = nextResolvedPosition - this.scope.offset; - this.scope.adjustLocalVariablePositions(delta, false); - } - public void loadStoredTypesAndKeep(CodeStream codeStream) { - List tos = this.typesOnStack; - int sz = tos != null ? tos.size() : 0; - codeStream.clearTypeBindingStack(); - int index = sz - 1; - while (index >= 0) { - LocalVariableBinding lvb = tos.get(index--); - codeStream.load(lvb); -// lvb.recordInitializationEndPC(codeStream.position); -// codeStream.removeVariable(lvb); - } - } - private void removeStoredTypes(CodeStream codeStream) { - List tos = this.typesOnStack; - int sz = tos != null ? tos.size() : 0; - int index = sz - 1; - while (index >= 0) { - LocalVariableBinding lvb = tos.get(index--); - codeStream.removeVariable(lvb); - } - } - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int tmp = 0; - if (this.containsTry) { - tmp = codeStream.lastSwitchCumulativeSyntheticVars; - processTypesBindingsOnStack(codeStream); - } - super.generateCode(currentScope, codeStream); - if (this.containsTry) { - removeStoredTypes(codeStream); - codeStream.lastSwitchCumulativeSyntheticVars = tmp; - } - if (!valueRequired) { - // switch expression is saved to a variable that is not used. We need to pop the generated value from the stack - switch(postConversionType(currentScope).id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.pop2(); - break; - case TypeIds.T_void : - break; - default : - codeStream.pop(); - break; - } - } else { - if (!this.isPolyExpression()) // not in invocation or assignment contexts - codeStream.generateImplicitConversion(this.implicitConversion); - } - } - protected boolean computeConversions(BlockScope blockScope, TypeBinding targetType) { - boolean ok = true; - for (int i = 0, l = this.resultExpressions.size(); i < l; ++i) { - ok &= computeConversionsResultExpressions(blockScope, targetType, this.originalValueResultExpressionTypes[i], this.resultExpressions.get(i)); - } - return ok; - } - private boolean computeConversionsResultExpressions(BlockScope blockScope, TypeBinding targetType, TypeBinding resultExpressionType, - Expression resultExpression) { - if (resultExpressionType != null && resultExpressionType.isValidBinding()) { - if (resultExpression.isConstantValueOfTypeAssignableToType(resultExpressionType, targetType) - || resultExpressionType.isCompatibleWith(targetType)) { - - resultExpression.computeConversion(blockScope, targetType, resultExpressionType); - if (resultExpressionType.needsUncheckedConversion(targetType)) { - blockScope.problemReporter().unsafeTypeConversion(resultExpression, resultExpressionType, targetType); - } - if (resultExpression instanceof CastExpression - && (resultExpression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { - CastExpression.checkNeedForAssignedCast(blockScope, targetType, (CastExpression) resultExpression); - } - } else if (isBoxingCompatible(resultExpressionType, targetType, resultExpression, blockScope)) { - resultExpression.computeConversion(blockScope, targetType, resultExpressionType); - if (resultExpression instanceof CastExpression - && (resultExpression.bits & (ASTNode.UnnecessaryCast|ASTNode.DisableUnnecessaryCastCheck)) == 0) { - CastExpression.checkNeedForAssignedCast(blockScope, targetType, (CastExpression) resultExpression); - } - } else { - blockScope.problemReporter().typeMismatchError(resultExpressionType, targetType, resultExpression, null); - return false; - } - } - return true; - } - - @Override - public TypeBinding resolveType(BlockScope upperScope) { - return resolveTypeInternal(upperScope); - } - public TypeBinding resolveTypeInternal(BlockScope upperScope) { - try { - int resultExpressionsCount; - if (this.constant != Constant.NotAConstant) { - this.constant = Constant.NotAConstant; - - // A switch expression is a poly expression if it appears in an assignment context or an invocation context (5.2, 5.3). - // Otherwise, it is a standalone expression. - if (this.expressionContext == ASSIGNMENT_CONTEXT || this.expressionContext == INVOCATION_CONTEXT) { - for (Expression e : this.resultExpressions) { - //Where a poly switch expression appears in a context of a particular kind with target type T, - //its result expressions similarly appear in a context of the same kind with target type T. - e.setExpressionContext(this.expressionContext); - e.setExpectedType(this.expectedType); - } - } - - if (this.originalTypeMap == null) - this.originalTypeMap = new HashMap<>(); - resolve(upperScope); - - if (this.statements == null || this.statements.length == 0) { - // Report Error JLS 13 15.28.1 The switch block must not be empty. - upperScope.problemReporter().switchExpressionEmptySwitchBlock(this); - return null; - } - - resultExpressionsCount = this.resultExpressions != null ? this.resultExpressions.size() : 0; - if (resultExpressionsCount == 0) { - // Report Error JLS 13 15.28.1 - // It is a compile-time error if a switch expression has no result expressions. - upperScope.problemReporter().switchExpressionNoResultExpressions(this); - return null; - } - - if (this.originalValueResultExpressionTypes == null) { - this.originalValueResultExpressionTypes = new TypeBinding[resultExpressionsCount]; - this.finalValueResultExpressionTypes = new TypeBinding[resultExpressionsCount]; - for (int i = 0; i < resultExpressionsCount; ++i) { - this.finalValueResultExpressionTypes[i] = this.originalValueResultExpressionTypes[i] = - this.resultExpressions.get(i).resolvedType; - } - } - if (isPolyExpression()) { //The type of a poly switch expression is the same as its target type. - if (this.expectedType == null || !this.expectedType.isProperType(true)) { - return new PolyTypeBinding(this); - } - return this.resolvedType = computeConversions(this.scope, this.expectedType) ? this.expectedType : null; - } - // fall through - } else { - // re-resolving of poly expression: - resultExpressionsCount = this.resultExpressions != null ? this.resultExpressions.size() : 0; - if (resultExpressionsCount == 0) - return this.resolvedType = null; // error flagging would have been done during the earlier phase. - for (int i = 0; i < resultExpressionsCount; i++) { - Expression resultExpr = this.resultExpressions.get(i); - TypeBinding origType = this.originalTypeMap.get(resultExpr); - // NB: if origType == null we assume that initial resolving failed hard, rendering re-resolving impossible - if (origType != null && origType.kind() == Binding.POLY_TYPE) { - this.finalValueResultExpressionTypes[i] = this.originalValueResultExpressionTypes[i] = - resultExpr.resolveTypeExpecting(upperScope, this.expectedType); - } - // This is a kludge and only way completion can tell this node to resolve all - // resultExpressions. Ideal solution is to remove all other expressions except - // the one that contain the completion node. - if (this.resolveAll) continue; - if (resultExpr.resolvedType == null || !resultExpr.resolvedType.isValidBinding()) - return this.resolvedType = null; - } - this.resolvedType = computeConversions(this.scope, this.expectedType) ? this.expectedType : null; - // fall through - } - - if (resultExpressionsCount == 1) - return this.resolvedType = this.originalValueResultExpressionTypes[0]; - - boolean typeUniformAcrossAllArms = true; - TypeBinding tmp = this.originalValueResultExpressionTypes[0]; - for (int i = 1, l = this.originalValueResultExpressionTypes.length; i < l; ++i) { - TypeBinding originalType = this.originalValueResultExpressionTypes[i]; - if (originalType != null && TypeBinding.notEquals(tmp, originalType)) { - typeUniformAcrossAllArms = false; - break; - } - } - // If the result expressions all have the same type (which may be the null type), - // then that is the type of the switch expression. - if (typeUniformAcrossAllArms) { - tmp = this.originalValueResultExpressionTypes[0]; - for (int i = 1; i < resultExpressionsCount; ++i) { - if (this.originalValueResultExpressionTypes[i] != null) - tmp = NullAnnotationMatching.moreDangerousType(tmp, this.originalValueResultExpressionTypes[i]); - } - return this.resolvedType = tmp; - } - - boolean typeBbolean = true; - for (TypeBinding t : this.originalValueResultExpressionTypes) { - if (t != null) - typeBbolean &= t.id == T_boolean || t.id == T_JavaLangBoolean; - } - LookupEnvironment env = this.scope.environment(); - /* - * Otherwise, if the type of each result expression is boolean or Boolean, - * an unboxing conversion (5.1.8) is applied to each result expression of type Boolean, - * and the switch expression has type boolean. - */ - if (typeBbolean) { - for (int i = 0; i < resultExpressionsCount; ++i) { - if (this.originalValueResultExpressionTypes[i] == null) continue; - if (this.originalValueResultExpressionTypes[i].id == T_boolean) continue; - this.finalValueResultExpressionTypes[i] = env.computeBoxingType(this.originalValueResultExpressionTypes[i]); - this.resultExpressions.get(i).computeConversion(this.scope, this.finalValueResultExpressionTypes[i], this.originalValueResultExpressionTypes[i]); - } - return this.resolvedType = TypeBinding.BOOLEAN; - } - - /* - * Otherwise, if the type of each result expression is convertible to a numeric type (5.1.8), the type - * of the switch expression is given by numeric promotion (5.6.3) applied to the result expressions. - */ - boolean typeNumeric = true; - TypeBinding resultNumeric = null; - HashSet typeSet = new HashSet<>(); - /* JLS 13 5.6 Numeric Contexts - * An expression appears in a numeric context if it is one of:.... - * ...8. a result expression of a standalone switch expression (15.28.1), - * where all the result expressions are convertible to a numeric type - * If any expression is of a reference type, it is subjected to unboxing conversion (5.1.8). - */ - for (int i = 0; i < resultExpressionsCount; ++i) { - TypeBinding originalType = this.originalValueResultExpressionTypes[i]; - if (originalType == null) continue; - tmp = originalType.isNumericType() ? originalType : env.computeBoxingType(originalType); - if (!tmp.isNumericType()) { - typeNumeric = false; - break; - } - typeSet.add(TypeBinding.wellKnownType(this.scope, tmp.id)); - } - if (typeNumeric) { - /* If any result expression is of type double, then other result expressions that are not of type double - * are widened to double. - * Otherwise, if any result expression is of type float, then other result expressions that are not of - * type float are widened to float. - * Otherwise, if any result expression is of type long, then other result expressions that are not of - * type long are widened to long. - */ - TypeBinding[] dfl = new TypeBinding[]{// do not change the order JLS 13 5.6 - TypeBinding.DOUBLE, - TypeBinding.FLOAT, - TypeBinding.LONG}; - for (TypeBinding binding : dfl) { - if (typeSet.contains(binding)) { - resultNumeric = binding; - break; - } - } - - /* Otherwise, if any expression appears in a numeric array context or a numeric arithmetic context, - * rather than a numeric choice context, then the promoted type is int and other expressions that are - * not of type int undergo widening primitive conversion to int. - not applicable since numeric choice context. - * [Note: A numeric choice context is a numeric context that is either a numeric conditional expression or - * a standalone switch expression where all the result expressions are convertible to a numeric type.] - */ - - /* Otherwise, if any result expression is of type int and is not a constant expression, the other - * result expressions that are not of type int are widened to int. - */ - resultNumeric = resultNumeric != null ? resultNumeric : check_nonconstant_int(); - - resultNumeric = resultNumeric != null ? resultNumeric : // one among the first few rules applied. - getResultNumeric(typeSet); // check the rest - typeSet = null; // hey gc! - for (int i = 0; i < resultExpressionsCount; ++i) { - this.resultExpressions.get(i).computeConversion(this.scope, - resultNumeric, this.originalValueResultExpressionTypes[i]); - this.finalValueResultExpressionTypes[i] = resultNumeric; - } - // After the conversion(s), if any, value set conversion (5.1.13) is then applied to each result expression. - return this.resolvedType = resultNumeric; - } - - /* Otherwise, boxing conversion (5.1.7) is applied to each result expression that has a primitive type, - * after which the type of the switch expression is the result of applying capture conversion (5.1.10) - * to the least upper bound (4.10.4) of the types of the result expressions. - */ - for (int i = 0; i < resultExpressionsCount; ++i) { - TypeBinding finalType = this.finalValueResultExpressionTypes[i]; - if (finalType != null && finalType.isBaseType()) - this.finalValueResultExpressionTypes[i] = env.computeBoxingType(finalType); - } - TypeBinding commonType = this.scope.lowerUpperBound(this.finalValueResultExpressionTypes); - if (commonType != null) { - for (int i = 0, l = this.resultExpressions.size(); i < l; ++i) { - if (this.originalValueResultExpressionTypes[i] == null) continue; - this.resultExpressions.get(i).computeConversion(this.scope, commonType, this.originalValueResultExpressionTypes[i]); - this.finalValueResultExpressionTypes[i] = commonType; - } - return this.resolvedType = commonType.capture(this.scope, this.sourceStart, this.sourceEnd); - } - this.scope.problemReporter().switchExpressionIncompatibleResultExpressions(this); - return null; - } finally { - if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block - } - } - private TypeBinding check_nonconstant_int() { - for (int i = 0, l = this.resultExpressions.size(); i < l; ++i) { - Expression e = this.resultExpressions.get(i); - TypeBinding type = this.originalValueResultExpressionTypes[i]; - if (type != null && type.id == T_int && e.constant == Constant.NotAConstant) - return TypeBinding.INT; - } - return null; - } - private boolean areAllIntegerResultExpressionsConvertibleToTargetType(TypeBinding targetType) { - for (int i = 0, l = this.resultExpressions.size(); i < l; ++i) { - Expression e = this.resultExpressions.get(i); - TypeBinding t = this.originalValueResultExpressionTypes[i]; - if (!TypeBinding.equalsEquals(t, TypeBinding.INT)) continue; - if (!e.isConstantValueOfTypeAssignableToType(t, targetType)) - return false; - } - return true; - } - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - flowInfo = super.analyseCode(currentScope, flowContext, flowInfo); - this.resultExpressionNullStatus = new ArrayList<>(0); - final CompilerOptions compilerOptions = currentScope.compilerOptions(); - if (compilerOptions.enableSyntacticNullAnalysisForFields) { - for (Expression re : this.resultExpressions) { - this.resultExpressionNullStatus.add(re.nullStatus(flowInfo, flowContext)); - // wipe information that was meant only for this result expression: - flowContext.expireNullCheckedFieldInfo(); - } - } - computeNullStatus(flowInfo, flowContext); - return flowInfo; - } - @Override - protected void addSecretTryResultVariable() { - if (this.containsTry) { - this.hiddenYield = - new LocalVariableBinding( - SwitchExpression.SECRET_YIELD_VALUE_NAME, - null, - ClassFileConstants.AccDefault, - false); - this.hiddenYield.setConstant(Constant.NotAConstant); - this.hiddenYield.useFlag = LocalVariableBinding.USED; - this.scope.addLocalVariable(this.hiddenYield); - this.hiddenYield.declaration = new LocalDeclaration(SECRET_YIELD_VALUE_NAME, 0, 0); - } - } - private TypeBinding check_csb(Set typeSet, TypeBinding candidate) { - if (!typeSet.contains(candidate)) - return null; - - TypeBinding[] allowedTypes = SwitchExpression.type_map.get(candidate); - Set allowedSet = Arrays.stream(allowedTypes).collect(Collectors.toSet()); - - if (!allowedSet.containsAll(typeSet)) - return null; - - return areAllIntegerResultExpressionsConvertibleToTargetType(candidate) ? - candidate : null; - } - private TypeBinding getResultNumeric(Set typeSet) { - // note: if an expression has a type integer, then it will be a constant - // since non-constant integers are already processed before reaching here. - - /* Otherwise, if any expression is of type short, and every other expression is either of type short, - * or of type byte, or a constant expression of type int with a value that is representable in the - * type short, then T is short, the byte expressions undergo widening primitive conversion to short, - * and the int expressions undergo narrowing primitive conversion to short.\ - * - * Otherwise, if any expression is of type byte, and every other expression is either of type byte or a - * constant expression of type int with a value that is representable in the type byte, then T is byte - * and the int expressions undergo narrowing primitive conversion to byte. - * - * Otherwise, if any expression is of type char, and every other expression is either of type char or a - * constant expression of type int with a value that is representable in the type char, then T is char - * and the int expressions undergo narrowing primitive conversion to char. - * - * Otherwise, T is int and all the expressions that are not of type int undergo widening - * primitive conversion to int. - */ - - // DO NOT Change the order below [as per JLS 13 5.6 ]. - TypeBinding[] csb = new TypeBinding[] {TypeBinding.SHORT, TypeBinding.BYTE, TypeBinding.CHAR}; - for (TypeBinding c : csb) { - TypeBinding result = check_csb(typeSet, c); - if (result != null) - return result; - } - /* Otherwise, all the result expressions that are not of type int are widened to int. */ - return TypeBinding.INT; - } - @Override - public boolean isPolyExpression() { - if (this.isPolyExpression) - return true; - // JLS 13 15.28.1 A switch expression is a poly expression if it appears in an assignment context or - // an invocation context (5.2, 5.3). Otherwise, it is a standalone expression. - return this.isPolyExpression = this.expressionContext == ASSIGNMENT_CONTEXT || - this.expressionContext == INVOCATION_CONTEXT; - } - @Override - public boolean isTrulyExpression() { - return true; - } - @Override - public boolean isCompatibleWith(TypeBinding left, Scope skope) { - if (!isPolyExpression()) - return super.isCompatibleWith(left, skope); - - for (Expression e : this.resultExpressions) { - if (!e.isCompatibleWith(left, skope)) - return false; - } - return true; - } - @Override - public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope skope) { - if (!isPolyExpression()) - return super.isBoxingCompatibleWith(targetType, skope); - - for (Expression e : this.resultExpressions) { - if (!(e.isCompatibleWith(targetType, skope) || e.isBoxingCompatibleWith(targetType, skope))) - return false; - } - return true; - } - @Override - public boolean sIsMoreSpecific(TypeBinding s, TypeBinding t, Scope skope) { - if (super.sIsMoreSpecific(s, t, skope)) - return true; - if (!isPolyExpression()) - return false; - for (Expression e : this.resultExpressions) { - if (!e.sIsMoreSpecific(s, t, skope)) - return false; - } - return true; - } - @Override - public TypeBinding expectedType() { - return this.expectedType; - } - @Override - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.expression.traverse(visitor, blockScope); - if (this.statements != null) { - int statementsLength = this.statements.length; - for (int i = 0; i < statementsLength; i++) - this.statements[i].traverse(visitor, this.scope); - } - } - visitor.endVisit(this, blockScope); - } -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java deleted file mode 100644 index f62efa1..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java +++ /dev/null @@ -1,1734 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * 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 265744 - Enum switch should warn about missing default - * bug 374605 - Unreasonable warning for enum-based switch statements - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.function.IntPredicate; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.CaseStatement.ResolvedCase; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -import org.eclipse.jdt.internal.compiler.codegen.CaseLabel; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; -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.SwitchFlowContext; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.impl.JavaFeature; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.SyntheticMethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; - -@SuppressWarnings("rawtypes") -public class SwitchStatement extends Expression { - - public Expression expression; - public Statement[] statements; - public BlockScope scope; - public int explicitDeclarations; - public BranchLabel breakLabel; - public CaseStatement[] cases; - public CaseStatement defaultCase; - public CaseStatement nullCase; // convenience pointer for pattern switches - public int blockStart; - public int caseCount; - int[] constants; - int[] constMapping; - // Any non int constants - public ResolvedCase[] otherConstants; - public int nConstants; - public int switchBits; - - public boolean containsPatterns; - public boolean containsNull; - private boolean nullProcessed = false; - BranchLabel switchPatternRestartTarget; - /* package */ public Pattern totalPattern; - - // fallthrough - public final static int CASE = 0; - public final static int FALLTHROUGH = 1; - public final static int ESCAPING = 2; - public final static int BREAKING = 3; - - // Other bits - public final static int LabeledRules = ASTNode.Bit1; - public final static int NullCase = ASTNode.Bit2; - public final static int TotalPattern = ASTNode.Bit3; - public final static int Exhaustive = ASTNode.Bit4; - public final static int Enhanced = ASTNode.Bit5; - public final static int QualifiedEnum = ASTNode.Bit6; - - // for switch on strings - private static final char[] SecretStringVariableName = " switchDispatchString".toCharArray(); //$NON-NLS-1$ - - // for patterns in switch - /* package */ static final char[] SecretPatternVariableName = " switchDispatchPattern".toCharArray(); //$NON-NLS-1$ - private static final char[] SecretPatternRestartIndexName = " switchPatternRestartIndex".toCharArray(); //$NON-NLS-1$ - - public SyntheticMethodBinding synthetic; // use for switch on enums types - - // for local variables table attributes - int preSwitchInitStateIndex = -1; - int mergedInitStateIndex = -1; - - Statement[] duplicateCases = null; - int duplicateCaseCounter = 0; - private LocalVariableBinding dispatchStringCopy = null; - private LocalVariableBinding dispatchPatternCopy = null; - private LocalVariableBinding restartIndexLocal = null; - - /* package */ boolean isNonTraditional = false; - /* package */ List caseLabelElements = new ArrayList<>(0);//TODO: can we remove this? - public List caseLabelElementTypes = new ArrayList<>(0); - int constantIndex = 0; - - class Node { - TypeBinding type; - boolean hasError = false; - public void traverse(NodeVisitor visitor) { - visitor.visit(this); - visitor.endVisit(this); - } - } - class RNode extends Node { - TNode firstComponent; - - RNode(TypeBinding rec) { - this.type = rec; - RecordComponentBinding[] comps = rec.components(); - int len = comps != null ? comps.length : 0; - if (len > 0) { - RecordComponentBinding comp = comps[0]; - if (comp != null && comp.type != null) - this.firstComponent = new TNode(comp.type); - } - } - void addPattern(Pattern p) { - if (p instanceof RecordPattern) - addPattern((RecordPattern)p); - } - void addPattern(RecordPattern rp) { - if (!TypeBinding.equalsEquals(this.type, rp.type.resolvedType)) - return; - if (this.firstComponent == null) - return; - this.firstComponent.addPattern(rp, 0); - } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[RNode] {\n"); //$NON-NLS-1$ - sb.append(" type:"); //$NON-NLS-1$ - sb.append(this.type != null ? this.type.toString() : "null"); //$NON-NLS-1$ - sb.append(" firstComponent:"); //$NON-NLS-1$ - sb.append(this.firstComponent != null ? this.firstComponent.toString() : "null"); //$NON-NLS-1$ - sb.append("\n}\n"); //$NON-NLS-1$ - return sb.toString(); - } - @Override - public void traverse(NodeVisitor visitor) { - if (this.firstComponent != null) { - visitor.visit(this.firstComponent); - } - visitor.endVisit(this); - } - } - class TNode extends Node { - List children; - - TNode(TypeBinding type) { - this.type = type; - this.children = new ArrayList<>(); - } - - public void addPattern(RecordPattern rp, int i) { - if (rp.patterns.length <= i) { - this.hasError = true; - return; - } - TypeBinding childType = rp.patterns[i].resolvedType; - PatternNode child = null; - for (PatternNode c : this.children) { - if (TypeBinding.equalsEquals(childType, c.type)) { - child = c; - break; - } - } - if (child == null) { - child = childType.isRecord() ? - new RecordPatternNode(childType) : new PatternNode(childType); - if (this.type.isSubtypeOf(childType, false)) - this.children.add(0, child); - else - this.children.add(child); - } - if ((i+1) < rp.patterns.length) { - child.addPattern(rp, i + 1); - } - } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[TNode] {\n"); //$NON-NLS-1$ - sb.append(" type:"); //$NON-NLS-1$ - sb.append(this.type != null ? this.type.toString() : "null"); //$NON-NLS-1$ - sb.append(" children:"); //$NON-NLS-1$ - if (this.children == null) { - sb.append("null"); //$NON-NLS-1$ - } else { - for (Node child : this.children) { - sb.append(child.toString()); - } - } - sb.append("\n}\n"); //$NON-NLS-1$ - return sb.toString(); - } - @Override - public void traverse(NodeVisitor visitor) { - if (visitor.visit(this)) { - if (this.children != null) { - for (PatternNode child : this.children) { - if (!visitor.visit(child)) { - break; - } - } - } - } - visitor.endVisit(this); - } - } - class PatternNode extends Node { - TNode next; // next component - - PatternNode(TypeBinding type) { - this.type = type; - } - - public void addPattern(RecordPattern rp, int i) { - TypeBinding ref = SwitchStatement.this.expression.resolvedType; - if (!(ref instanceof ReferenceBinding)) - return; - RecordComponentBinding[] comps = ((ReferenceBinding)ref).components(); - if (comps == null || comps.length <= i) // safety-net for incorrect code. - return; - if (this.next == null) - this.next = new TNode(comps[i].type); - this.next.addPattern(rp, i); - } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[Pattern node] {\n"); //$NON-NLS-1$ - sb.append(" type:"); //$NON-NLS-1$ - sb.append(this.type != null ? this.type.toString() : "null"); //$NON-NLS-1$ - sb.append(" next:"); //$NON-NLS-1$ - sb.append(this.next != null ? this.next.toString() : "null"); //$NON-NLS-1$ - sb.append("\n}\n"); //$NON-NLS-1$ - return sb.toString(); - } - @Override - public void traverse(NodeVisitor visitor) { - if (visitor.visit(this)) { - if (this.next != null) { - visitor.visit(this.next); - } - } - visitor.endVisit(this); - } - } - class RecordPatternNode extends PatternNode { - RNode rNode; - RecordPatternNode(TypeBinding type) { - super(type); - } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("[RecordPattern node] {\n"); //$NON-NLS-1$ - sb.append(" type:"); //$NON-NLS-1$ - sb.append(this.type != null ? this.type.toString() : "null"); //$NON-NLS-1$ - sb.append(" next:"); //$NON-NLS-1$ - sb.append(this.next != null ? this.next.toString() : "null"); //$NON-NLS-1$ - sb.append(" rNode:"); //$NON-NLS-1$ - sb.append(this.rNode != null ? this.rNode.toString() : "null"); //$NON-NLS-1$ - sb.append("\n}\n"); //$NON-NLS-1$ - return sb.toString(); - } - @Override - public void traverse(NodeVisitor visitor) { - if (visitor.visit(this)) { - if (visitor.visit(this.rNode)) { - if (this.next != null) { - visitor.visit(this.next); - } - } - } - visitor.endVisit(this); - } - } - - abstract class NodeVisitor { - public void endVisit(Node node) { - // do nothing by default - } - public void endVisit(PatternNode node) { - // do nothing by default - } - public void endVisit(RecordPatternNode node) { - // do nothing by default - } - public void endVisit(RNode node) { - // do nothing by default - } - public void endVisit(TNode node) { - // do nothing by default - } - public boolean visit(Node node) { - return true; - } - public boolean visit(PatternNode node) { - return true; - } - public boolean visit(RecordPatternNode node) { - return true; - } - public boolean visit(RNode node) { - return true; - } - public boolean visit(TNode node) { - return true; - } - } - class CoverageCheckerVisitor extends NodeVisitor { - public boolean covers = true; - @Override - public boolean visit(TNode node) { - if (node.hasError) - return false; - - List availableTypes = new ArrayList<>(); - if (node.children != null) { - for (Node child : node.children) { - if (node.type.isSubtypeOf(child.type, false)) - this.covers = true; - child.traverse(this); - if (node.type.isSubtypeOf(child.type, false) && this.covers) - return false; // no further visit required - covering! - availableTypes.add(child.type); - } - } - if (node.type instanceof ReferenceBinding && ((ReferenceBinding)node.type).isSealed()) { - List allAllowedTypes = getAllPermittedTypes((ReferenceBinding) node.type); - this.covers &= isExhaustiveWithCaseTypes(allAllowedTypes, availableTypes); - return this.covers; - } - this.covers = false; - return false; // no need to visit further. - } - } - protected int getFallThroughState(Statement stmt, BlockScope blockScope) { - if ((this.switchBits & LabeledRules) != 0) { - if ((stmt instanceof Expression && ((Expression) stmt).isTrulyExpression()) || stmt instanceof ThrowStatement) - return BREAKING; - if (!stmt.canCompleteNormally()) - return BREAKING; - - if (stmt instanceof Block) { - Block block = (Block) stmt; - // Note implicit break anyway - Let the flow analysis do the dead code analysis - BreakStatement breakStatement = new BreakStatement(null, block.sourceEnd -1, block.sourceEnd); - breakStatement.isSynthetic = true; // suppress dead code flagging - codegen will not generate dead code anyway - - int l = block.statements == null ? 0 : block.statements.length; - if (l == 0) { - block.statements = new Statement[] {breakStatement}; - block.scope = this.scope; // (upper scope) see Block.resolve() for similar - } else { - Statement[] newArray = new Statement[l + 1]; - System.arraycopy(block.statements, 0, newArray, 0, l); - newArray[l] = breakStatement; - block.statements = newArray; - } - return BREAKING; - } - } - return FALLTHROUGH; - } - protected void completeNormallyCheck(BlockScope blockScope) { - // do nothing - } - protected boolean needToCheckFlowInAbsenceOfDefaultBranch() { - return !this.isExhaustive(); - } - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - try { - flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); - if (isNullHostile()) { - this.expression.checkNPE(currentScope, flowContext, flowInfo, 1); - } - SwitchFlowContext switchContext = - new SwitchFlowContext(flowContext, this, (this.breakLabel = new BranchLabel()), true, true); - switchContext.isExpression = this instanceof SwitchExpression; - - CompilerOptions compilerOptions = currentScope.compilerOptions(); - - // analyse the block by considering specially the case/default statements (need to bind them - // to the entry point) - FlowInfo caseInits = FlowInfo.DEAD_END; - // in case of statements before the first case - this.preSwitchInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); - int caseIndex = 0; - if (this.statements != null) { - int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; - int complaintLevel = initialComplaintLevel; - int fallThroughState = CASE; - int prevCaseStmtIndex = -100; - for (int i = 0, max = this.statements.length; i < max; i++) { - Statement statement = this.statements[i]; - if ((caseIndex < this.caseCount) && (statement == this.cases[caseIndex])) { // statement is a case - this.scope.enclosingCase = this.cases[caseIndex]; // record entering in a switch case block - caseIndex++; - if (prevCaseStmtIndex == i - 1) { - if (((CaseStatement) this.statements[prevCaseStmtIndex]).containsPatternVariable()) - this.scope.problemReporter().illegalFallthroughFromAPattern(this.statements[prevCaseStmtIndex]); - } - prevCaseStmtIndex = i; - if (fallThroughState == FALLTHROUGH && complaintLevel <= NOT_COMPLAINED) { - if (((CaseStatement) statement).containsPatternVariable()) - this.scope.problemReporter().IllegalFallThroughToPattern(this.scope.enclosingCase); - else if ((statement.bits & ASTNode.DocumentedFallthrough) == 0) { // the case is not fall-through protected by a line comment - this.scope.problemReporter().possibleFallThroughCase(this.scope.enclosingCase); - } - } - caseInits = caseInits.mergedWith(flowInfo.unconditionalInits()); - complaintLevel = initialComplaintLevel; // reset complaint - fallThroughState = this.containsPatterns ? FALLTHROUGH : CASE; - } else if (statement == this.defaultCase) { // statement is the default case - this.scope.enclosingCase = this.defaultCase; // record entering in a switch case block - if (fallThroughState == FALLTHROUGH - && complaintLevel <= NOT_COMPLAINED - && (statement.bits & ASTNode.DocumentedFallthrough) == 0) { - this.scope.problemReporter().possibleFallThroughCase(this.scope.enclosingCase); - } - caseInits = caseInits.mergedWith(flowInfo.unconditionalInits()); - if ((this.switchBits & LabeledRules) != 0 && this.expression.resolvedType instanceof ReferenceBinding) { - if (this.expression instanceof NameReference) { - // default case does not apply to null => mark the variable being switched over as nonnull: - NameReference reference = (NameReference) this.expression; - if (reference.localVariableBinding() != null) { - caseInits.markAsDefinitelyNonNull(reference.localVariableBinding()); - } else if (reference.lastFieldBinding() != null) { - if (this.scope.compilerOptions().enableSyntacticNullAnalysisForFields) - switchContext.recordNullCheckedFieldReference(reference, 2); // survive this case statement and into the next - } - } else if (this.expression instanceof FieldReference) { - if (this.scope.compilerOptions().enableSyntacticNullAnalysisForFields) - switchContext.recordNullCheckedFieldReference((FieldReference) this.expression, 2); // survive this case statement and into the next - } - } - complaintLevel = initialComplaintLevel; // reset complaint - fallThroughState = this.containsPatterns ? FALLTHROUGH : CASE; - } else { - if (!(this instanceof SwitchExpression) && - compilerOptions.complianceLevel >= ClassFileConstants.JDK14 && - statement instanceof YieldStatement && - ((YieldStatement) statement).isImplicit) { - YieldStatement y = (YieldStatement) statement; - Expression e = ((YieldStatement) statement).expression; - /* JLS 13 14.11.2 - Switch labeled rules in switch statements differ from those in switch expressions (15.28). - In switch statements they must be switch labeled statement expressions, ... */ - if (!y.expression.statementExpression()) { - this.scope.problemReporter().invalidExpressionAsStatement(e); - } - } - fallThroughState = getFallThroughState(statement, currentScope); // reset below if needed - } - 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; - } - if (compilerOptions.enableSyntacticNullAnalysisForFields) { - switchContext.expireNullCheckedFieldInfo(); - } - if (compilerOptions.analyseResourceLeaks) { - FakedTrackingVariable.cleanUpUnassigned(this.scope, statement, caseInits, false); - } - } - } - completeNormallyCheck(currentScope); - } - - final TypeBinding resolvedTypeBinding = this.expression.resolvedType; - if (resolvedTypeBinding.isEnum()) { - final SourceTypeBinding sourceTypeBinding = currentScope.classScope().referenceContext.binding; - this.synthetic = sourceTypeBinding.addSyntheticMethodForSwitchEnum(resolvedTypeBinding, this); - } - // if no default case, then record it may jump over the block directly to the end - if (this.defaultCase == null && needToCheckFlowInAbsenceOfDefaultBranch()) { - // only retain the potential initializations - flowInfo.addPotentialInitializationsFrom(caseInits.mergedWith(switchContext.initsOnBreak)); - this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); - return flowInfo; - } - - // merge all branches inits - FlowInfo mergedInfo = caseInits.mergedWith(switchContext.initsOnBreak); - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } finally { - if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block - } - } - private boolean isNullHostile() { - if (this.containsNull) - return false; - if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0) { - return true; - } else if (this.expression.resolvedType != null - && (this.expression.resolvedType.id == T_JavaLangString || this.expression.resolvedType.isEnum())) { - return true; - } else if ((this.switchBits & (LabeledRules|NullCase)) == LabeledRules && this.totalPattern == null) { - return true; - } - return false; - } - - /** - * Switch on String code generation - * This assumes that hashCode() specification for java.lang.String is API - * and is stable. - * - * @see "http://download.oracle.com/javase/6/docs/api/java/lang/String.html" - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ - public void generateCodeForStringSwitch(BlockScope currentScope, CodeStream codeStream) { - - try { - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - - class StringSwitchCase implements Comparable { - int hashCode; - String string; - BranchLabel label; - public StringSwitchCase(int hashCode, String string, BranchLabel label) { - this.hashCode = hashCode; - this.string = string; - this.label = label; - } - @Override - public int compareTo(Object o) { - StringSwitchCase that = (StringSwitchCase) o; - if (this.hashCode == that.hashCode) { - return 0; - } - if (this.hashCode > that.hashCode) { - return 1; - } - return -1; - } - @Override - public String toString() { - return "StringSwitchCase :\n" + //$NON-NLS-1$ - "case " + this.hashCode + ":(" + this.string + ")\n"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - } - } - /* - * With multi constant case statements, the number of case statements (hence branch labels) - * and number of constants (hence hashcode labels) could be different. For e.g: - - switch(s) { - case "FB", "c": - System.out.println("A/C"); - break; - case "Ea": - System.out.println("B"); - break; - - With the above code, we will have - 2 branch labels for FB and c - 3 stringCases for FB, c and Ea - 2 hashCodeCaseLabels one for FB, Ea and one for c - - Should produce something like this: - lookupswitch { // 2 - 99: 32 - 2236: 44 - default: 87 - - "FB" and "Ea" producing the same hashcode values, but still belonging in different case statements. - First, produce the two branch labels pertaining to the case statements - And the three string cases and use the this.constMapping to get the correct branch label. - */ - final boolean hasCases = this.caseCount != 0; - int constSize = hasCases ? this.otherConstants.length : 0; - BranchLabel[] sourceCaseLabels = this.gatherLabels(codeStream, new BranchLabel[this.nConstants], BranchLabel::new); - StringSwitchCase [] stringCases = new StringSwitchCase[constSize]; // may have to shrink later if multiple strings hash to same code. - CaseLabel [] hashCodeCaseLabels = new CaseLabel[constSize]; - this.constants = new int[constSize]; // hashCode() values. - for (int i = 0; i < constSize; i++) { - String literal = this.otherConstants[i].c.stringValue(); - stringCases[i] = new StringSwitchCase(literal.hashCode(), literal, sourceCaseLabels[this.constMapping[i]]); - hashCodeCaseLabels[i] = new CaseLabel(codeStream); - hashCodeCaseLabels[i].tagBits |= BranchLabel.USED; - } - Arrays.sort(stringCases); - - int uniqHashCount = 0; - int lastHashCode = 0; - for (int i = 0, length = constSize; i < length; ++i) { - int hashCode = stringCases[i].hashCode; - if (i == 0 || hashCode != lastHashCode) { - lastHashCode = this.constants[uniqHashCount++] = hashCode; - } - } - - if (uniqHashCount != constSize) { // multiple keys hashed to the same value. - System.arraycopy(this.constants, 0, this.constants = new int[uniqHashCount], 0, uniqHashCount); - System.arraycopy(hashCodeCaseLabels, 0, hashCodeCaseLabels = new CaseLabel[uniqHashCount], 0, uniqHashCount); - } - int[] sortedIndexes = new int[uniqHashCount]; // hash code are sorted already anyways. - for (int i = 0; i < uniqHashCount; i++) { - sortedIndexes[i] = i; - } - - CaseLabel defaultCaseLabel = new CaseLabel(codeStream); - defaultCaseLabel.tagBits |= BranchLabel.USED; - - // prepare the labels and constants - this.breakLabel.initialize(codeStream); - - BranchLabel defaultBranchLabel = new BranchLabel(codeStream); - if (hasCases) defaultBranchLabel.tagBits |= BranchLabel.USED; - if (this.defaultCase != null) { - this.defaultCase.targetLabel = defaultBranchLabel; - } - // generate expression - this.expression.generateCode(currentScope, codeStream, true); - codeStream.store(this.dispatchStringCopy, true); // leaves string on operand stack - codeStream.addVariable(this.dispatchStringCopy); - codeStream.invokeStringHashCode(); - if (hasCases) { - codeStream.lookupswitch(defaultCaseLabel, this.constants, sortedIndexes, hashCodeCaseLabels); - for (int i = 0, j = 0, max = constSize; i < max; i++) { - int hashCode = stringCases[i].hashCode; - if (i == 0 || hashCode != lastHashCode) { - lastHashCode = hashCode; - if (i != 0) { - codeStream.goto_(defaultBranchLabel); - } - hashCodeCaseLabels[j++].place(); - } - codeStream.load(this.dispatchStringCopy); - codeStream.ldc(stringCases[i].string); - codeStream.invokeStringEquals(); - codeStream.ifne(stringCases[i].label); - } - codeStream.goto_(defaultBranchLabel); - } else { - codeStream.pop(); - } - - // generate the switch block statements - int caseIndex = 0; - if (this.statements != null) { - for (int i = 0, maxCases = this.statements.length; i < maxCases; i++) { - Statement statement = this.statements[i]; - if ((caseIndex < this.caseCount) && (statement == this.cases[caseIndex])) { // statements[i] is a case - this.scope.enclosingCase = this.cases[caseIndex]; // record entering in a switch case block - if (this.preSwitchInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSwitchInitStateIndex); - } - if (statement == this.defaultCase) { // statements[i] is a case or a default case - defaultCaseLabel.place(); // branch label gets placed by generateCode below. - } - caseIndex++; - } else { - if (statement == this.defaultCase) { // statements[i] is a case or a default case - defaultCaseLabel.place(); // branch label gets placed by generateCode below. - this.scope.enclosingCase = this.defaultCase; // record entering in a switch case block - if (this.preSwitchInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSwitchInitStateIndex); - } - } - } - statementGenerateCode(currentScope, codeStream, statement); - } - } - - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.removeVariable(this.dispatchStringCopy); - if (this.scope != currentScope) { - codeStream.exitUserScope(this.scope); - } - // place the trailing labels (for break and default case) - this.breakLabel.place(); - if (this.defaultCase == null) { - // we want to force an line number entry to get an end position after the switch statement - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd, true); - defaultCaseLabel.place(); - defaultBranchLabel.place(); - } - if (this.expectedType() != null) { - TypeBinding expectedType = this.expectedType().erasure(); - boolean optimizedGoto = codeStream.lastAbruptCompletion == -1; - // if the last bytecode was an optimized goto (value is already on the stack) or an enum switch without default case, then we need to adjust the - // stack depth to reflect the fact that there is an value on the stack (return type of the switch expression) - codeStream.recordExpressionType(expectedType, optimizedGoto ? 0 : 1, optimizedGoto); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } finally { - if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block - } - } - private T[] gatherLabels(CodeStream codeStream, T[] caseLabels, - Function newLabel) - { - for (int i = 0, j = 0, max = this.caseCount; i < max; i++) { - CaseStatement stmt = this.cases[i]; - int l = stmt.constantExpressions.length; - BranchLabel[] targetLabels = new BranchLabel[l]; - int count = 0; - for (int k = 0; k < l; ++k) { - Expression e = stmt.constantExpressions[k]; - if (e instanceof FakeDefaultLiteral) continue; - targetLabels[count++] = (caseLabels[j] = newLabel.apply(codeStream)); - if (e == this.totalPattern) - this.defaultCase = stmt; - caseLabels[j++].tagBits |= BranchLabel.USED; - } - System.arraycopy(targetLabels, 0, stmt.targetLabels = new BranchLabel[count], 0, count); - } - return caseLabels; - } - /** - * Switch code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if (this.expression.resolvedType.id == TypeIds.T_JavaLangString && !this.isNonTraditional) { - generateCodeForStringSwitch(currentScope, codeStream); - return; - } - try { - if ((this.bits & IsReachable) == 0) { - return; - } - int pc = codeStream.position; - - // prepare the labels and constants - this.breakLabel.initialize(codeStream); - int constantCount = this.otherConstants == null ? 0 : this.otherConstants.length; - CaseLabel[] caseLabels = this.gatherLabels(codeStream, new CaseLabel[this.nConstants], CaseLabel::new); - - CaseLabel defaultLabel = new CaseLabel(codeStream); - final boolean hasCases = this.caseCount != 0; - if (hasCases) defaultLabel.tagBits |= BranchLabel.USED; - if (this.defaultCase != null) { - this.defaultCase.targetLabel = defaultLabel; - } - - final TypeBinding resolvedType1 = this.expression.resolvedType; - boolean valueRequired = false; - if (needPatternDispatchCopy()) { - generateCodeSwitchPatternPrologue(currentScope, codeStream); - valueRequired = true; - transformConstants(); - } else if (resolvedType1.isEnum()) { - // go through the translation table - codeStream.invoke(Opcodes.OPC_invokestatic, this.synthetic, null /* default declaringClass */); - this.expression.generateCode(currentScope, codeStream, true); - // get enum constant ordinal() - codeStream.invokeEnumOrdinal(resolvedType1.constantPoolName()); - codeStream.iaload(); - if (!hasCases) { - // we can get rid of the generated ordinal value - codeStream.pop(); - } - valueRequired = hasCases; - } else { - valueRequired = this.expression.constant == Constant.NotAConstant || hasCases; - // generate expression - this.expression.generateCode(currentScope, codeStream, valueRequired); - } - // generate the appropriate switch table/lookup bytecode - if (hasCases) { - int[] sortedIndexes = new int[constantCount]; - // we sort the keys to be able to generate the code for tableswitch or lookupswitch - for (int i = 0; i < constantCount; i++) { - sortedIndexes[i] = i; - } - int[] localKeysCopy; - System.arraycopy(this.constants, 0, (localKeysCopy = new int[constantCount]), 0, constantCount); - CodeStream.sort(localKeysCopy, 0, constantCount - 1, sortedIndexes); - - int max = localKeysCopy[constantCount - 1]; - int min = localKeysCopy[0]; - if ((long) (constantCount * 2.5) > ((long) max - (long) min)) { - - // work-around 1.3 VM bug, if max>0x7FFF0000, must use lookup bytecode - // see http://dev.eclipse.org/bugs/show_bug.cgi?id=21557 - if (max > 0x7FFF0000 && currentScope.compilerOptions().complianceLevel < ClassFileConstants.JDK1_4) { - codeStream.lookupswitch(defaultLabel, this.constants, sortedIndexes, caseLabels); - - } else { - codeStream.tableswitch( - defaultLabel, - min, - max, - this.constants, - sortedIndexes, - this.constMapping, - caseLabels); - } - } else { - codeStream.lookupswitch(defaultLabel, this.constants, sortedIndexes, caseLabels); - } - codeStream.recordPositionsFrom(codeStream.position, this.expression.sourceEnd); - } else if (valueRequired) { - codeStream.pop(); - } - - // generate the switch block statements - int caseIndex = 0; - int typeSwitchIndex = 0; - if (this.statements != null) { - for (int i = 0, maxCases = this.statements.length; i < maxCases; i++) { - Statement statement = this.statements[i]; - CaseStatement caseStatement = null; - if ((caseIndex < constantCount) && (statement == this.cases[caseIndex])) { // statements[i] is a case - this.scope.enclosingCase = this.cases[caseIndex]; // record entering in a switch case block - if (this.preSwitchInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSwitchInitStateIndex); - } - caseStatement = (CaseStatement) statement; - patternCaseExitPreviousCaseScope(codeStream, caseIndex); - caseIndex++; - typeSwitchIndex += caseStatement.constantExpressions.length; - } else { - if (statement == this.defaultCase) { // statements[i] is a case or a default case - this.scope.enclosingCase = this.defaultCase; // record entering in a switch case block - if (this.preSwitchInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSwitchInitStateIndex); - } - } else if (statement instanceof CaseStatement) { - caseStatement = (CaseStatement) statement; - typeSwitchIndex += caseStatement.constantExpressions.length; - } - } - statementGenerateCode(currentScope, codeStream, statement); - generateCodePatternCaseEpilogue(codeStream, typeSwitchIndex, caseStatement); - } - } - - boolean isEnumSwitchWithoutDefaultCase = this.defaultCase == null && resolvedType1.isEnum() && (this instanceof SwitchExpression || this.containsNull); - CompilerOptions compilerOptions = this.scope != null ? this.scope.compilerOptions() : null; - boolean isPatternSwitchSealedWithoutDefaultCase = this.defaultCase == null - && compilerOptions != null - && this.containsPatterns - && JavaFeature.SEALED_CLASSES.isSupported(compilerOptions) - && JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions) - && this.expression.resolvedType instanceof ReferenceBinding - && ((ReferenceBinding) this.expression.resolvedType).isSealed(); - - boolean isRecordPatternSwitchWithoutDefault = this.defaultCase == null - && compilerOptions != null - && this.containsPatterns - && JavaFeature.RECORD_PATTERNS.isSupported(compilerOptions) - && JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions) - && this.expression.resolvedType instanceof ReferenceBinding - && this.expression.resolvedType.isRecord(); - if (isEnumSwitchWithoutDefaultCase - || isPatternSwitchSealedWithoutDefaultCase - || isRecordPatternSwitchWithoutDefault) { - // we want to force an line number entry to get an end position after the switch statement - if (this.preSwitchInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSwitchInitStateIndex); - } - defaultLabel.place(); - /* a default case is not needed for enum if all enum values are used in the switch expression - * we need to handle the default case to throw an error (IncompatibleClassChangeError) in order - * to make the stack map consistent. All cases will return a value on the stack except the missing default - * case. - * There is no returned value for the default case so we handle it with an exception thrown. An - * IllegalClassChangeError seems legitimate as this would mean the enum type has been recompiled with more - * enum constants and the class that is using the switch on the enum has not been recompiled - */ - if (compilerOptions.complianceLevel >= ClassFileConstants.JDK19) { - codeStream.newJavaLangMatchException(); - codeStream.dup(); - codeStream.aconst_null(); - codeStream.aconst_null(); - codeStream.invokeJavaLangMatchExceptionConstructor(); - codeStream.athrow(); - } else { - codeStream.newJavaLangIncompatibleClassChangeError(); - codeStream.dup(); - codeStream.invokeJavaLangIncompatibleClassChangeErrorDefaultConstructor(); - codeStream.athrow(); - } - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - generateCodeSwitchPatternEpilogue(codeStream); - if (this.scope != currentScope) { - codeStream.exitUserScope(this.scope); - } - // place the trailing labels (for break and default case) - this.breakLabel.place(); - if (this.defaultCase == null && !(isEnumSwitchWithoutDefaultCase - || isPatternSwitchSealedWithoutDefaultCase - || isRecordPatternSwitchWithoutDefault)) { - // we want to force an line number entry to get an end position after the switch statement - codeStream.recordPositionsFrom(codeStream.position, this.sourceEnd, true); - defaultLabel.place(); - } - if (this instanceof SwitchExpression) { - TypeBinding switchResolveType = this.resolvedType; - if (this.expectedType() != null) { - switchResolveType = this.expectedType().erasure(); - } - boolean optimizedGoto = codeStream.lastAbruptCompletion == -1; - // if the last bytecode was an optimized goto (value is already on the stack) or an enum switch without default case, then we need to adjust the - // stack depth to reflect the fact that there is an value on the stack (return type of the switch expression) - codeStream.recordExpressionType(switchResolveType, optimizedGoto ? 0 : 1, optimizedGoto || (isEnumSwitchWithoutDefaultCase && this instanceof SwitchExpression)); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } finally { - if (this.scope != null) this.scope.enclosingCase = null; // no longer inside switch case block - } - } - private void transformConstants() { - if (this.nullCase == null) { - for (int i = 0,l = this.otherConstants.length; i < l; ++i) { - if (this.otherConstants[i].e == this.totalPattern) { - this.otherConstants[i].index = -1; - break; - } - } - } - for (int i = 0; i < this.constants.length; i++) { - this.constants[i] = this.otherConstants[i].index; - } - } - private void generateCodeSwitchPatternEpilogue(CodeStream codeStream) { - if (needPatternDispatchCopy()) { - codeStream.removeVariable(this.dispatchPatternCopy); - codeStream.removeVariable(this.restartIndexLocal); - } - } - private void patternCaseExitPreviousCaseScope(CodeStream codeStream, int caseIndex) { - if (caseIndex > 0) { - CaseStatement caseStatement = this.cases[caseIndex]; - if (caseStatement.containsPatternVariable()) { - caseStatement.patternCaseRemovePatternLocals(codeStream); - } - } - } - private void generateCodePatternCaseEpilogue(CodeStream codeStream, int caseIndex, CaseStatement caseStatement) { - if (this.switchPatternRestartTarget != null && caseStatement != null - && caseStatement.patternIndex != -1 // for null - ) { - Pattern pattern = (Pattern) caseStatement.constantExpressions[caseStatement.patternIndex]; - pattern.elseTarget.place(); - pattern.suspendVariables(codeStream, this.scope); - caseIndex = this.nullProcessed ? caseIndex - 1 : caseIndex; - if (!pattern.isAlwaysTrue()) { - codeStream.loadInt(caseIndex); - codeStream.store(this.restartIndexLocal, false); - codeStream.goto_(this.switchPatternRestartTarget); - } - pattern.thenTarget.place(); - pattern.resumeVariables(codeStream, this.scope); - } else if (this.containsNull && caseStatement != null) { - this.nullProcessed |= caseStatement.patternIndex == -1; - } - } - private void generateCodeSwitchPatternPrologue(BlockScope currentScope, CodeStream codeStream) { - this.expression.generateCode(currentScope, codeStream, true); - if ((this.switchBits & NullCase) == 0) { - codeStream.dup(); - codeStream.invokeJavaUtilObjectsrequireNonNull(); - codeStream.pop(); - } - - codeStream.store(this.dispatchPatternCopy, false); - codeStream.addVariable(this.dispatchPatternCopy); - - codeStream.loadInt(0); // restartIndex - codeStream.store(this.restartIndexLocal, false); - codeStream.addVariable(this.restartIndexLocal); - - this.switchPatternRestartTarget = new BranchLabel(codeStream); - this.switchPatternRestartTarget.place(); - - codeStream.load(this.dispatchPatternCopy); - codeStream.load(this.restartIndexLocal); - int invokeDynamicNumber = codeStream.classFile.recordBootstrapMethod(this); - if (this.expression.resolvedType.isEnum()) { - generateEnumSwitchPatternPrologue(codeStream, invokeDynamicNumber); - } else { - generateTypeSwitchPatternPrologue(codeStream, invokeDynamicNumber); - } - boolean hasQualifiedEnums = (this.switchBits & QualifiedEnum) != 0; - for (int i = 0; i < this.otherConstants.length; i++) { - ResolvedCase c = this.otherConstants[i]; - if (hasQualifiedEnums) { - c.index = i; - } - if (!c.isQualifiedEnum()) - continue; - int classdescIdx = codeStream.classFile.recordBootstrapMethod(c.t); - invokeDynamicNumber = codeStream.classFile.recordBootstrapMethod(c); - c.enumDescIdx = invokeDynamicNumber; - c.classDescIdx = classdescIdx; - } - } - private void generateTypeSwitchPatternPrologue(CodeStream codeStream, int invokeDynamicNumber) { - codeStream.invokeDynamic(invokeDynamicNumber, - 2, // Object, restartIndex - 1, // int - ConstantPool.TYPESWITCH, - "(Ljava/lang/Object;I)I".toCharArray(), //$NON-NLS-1$ - TypeIds.T_int, - TypeBinding.INT); - } - private void generateEnumSwitchPatternPrologue(CodeStream codeStream, int invokeDynamicNumber) { - String genericTypeSignature = new String(this.expression.resolvedType.genericTypeSignature()); - String callingParams = "(" + genericTypeSignature + "I)I"; //$NON-NLS-1$ //$NON-NLS-2$ - codeStream.invokeDynamic(invokeDynamicNumber, - 2, // Object, restartIndex - 1, // int - "enumSwitch".toCharArray(), //$NON-NLS-1$ - callingParams.toCharArray(), - TypeIds.T_int, - TypeBinding.INT); - } - protected void statementGenerateCode(BlockScope currentScope, CodeStream codeStream, Statement statement) { - statement.generateCode(this.scope, codeStream); - } - - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - generateCode(currentScope, codeStream); // redirecting to statement part - } - @Override - public StringBuilder printStatement(int indent, StringBuilder output) { - - printIndent(indent, output).append("switch ("); //$NON-NLS-1$ - this.expression.printExpression(0, output).append(") {"); //$NON-NLS-1$ - if (this.statements != null) { - for (int i = 0; i < this.statements.length; i++) { - output.append('\n'); - if (this.statements[i] instanceof CaseStatement) { - this.statements[i].printStatement(indent, output); - } else { - this.statements[i].printStatement(indent+2, output); - } - } - } - output.append("\n"); //$NON-NLS-1$ - return printIndent(indent, output).append('}'); - } - - private int getNConstants() { - int n = 0; - for (int i = 0, l = this.statements.length; i < l; ++i) { - final Statement statement = this.statements[i]; - if (statement instanceof CaseStatement) { - Expression[] exprs = ((CaseStatement) statement).constantExpressions; - int count = 0; - if (exprs != null) { - for (Expression e : exprs) { - if (e instanceof FakeDefaultLiteral) continue; - ++count; - } - } - n += count; - } - } - return n; - } - protected void addSecretTryResultVariable() { - // do nothing - } - /* package */ boolean isAllowedType(TypeBinding type) { - if (type == null) - return false; - switch (type.id) { - case TypeIds.T_char: - case TypeIds.T_byte: - case TypeIds.T_short: - case TypeIds.T_int: - case TypeIds.T_JavaLangCharacter : - case TypeIds.T_JavaLangByte : - case TypeIds.T_JavaLangShort : - case TypeIds.T_JavaLangInteger : - return true; - default: break; - } - return false; - } - @Override - public void resolve(BlockScope upperScope) { - try { - boolean isEnumSwitch = false; - boolean isStringSwitch = false; - TypeBinding expressionType = this.expression.resolveType(upperScope); - CompilerOptions compilerOptions = upperScope.compilerOptions(); - boolean isEnhanced = checkAndSetEnhanced(upperScope, expressionType); - if (expressionType != null) { - this.expression.computeConversion(upperScope, expressionType, expressionType); - checkType: { - if (!expressionType.isValidBinding()) { - expressionType = null; // fault-tolerance: ignore type mismatch from constants from hereon - break checkType; - } else if (expressionType.isBaseType()) { - if (this.expression.isConstantValueOfTypeAssignableToType(expressionType, TypeBinding.INT)) - break checkType; - if (expressionType.isCompatibleWith(TypeBinding.INT)) - break checkType; - } else if (expressionType.isEnum()) { - isEnumSwitch = true; - if (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 (!this.containsPatterns && !this.containsNull && upperScope.isBoxingCompatibleWith(expressionType, TypeBinding.INT)) { - this.expression.computeConversion(upperScope, TypeBinding.INT, expressionType); - break checkType; - } else if (compilerOptions.complianceLevel >= ClassFileConstants.JDK1_7 && expressionType.id == TypeIds.T_JavaLangString) { - if (this.containsPatterns || this.containsNull) { - isStringSwitch = !JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions); - this.isNonTraditional = true; - break checkType; - } - isStringSwitch = true; - break checkType; - } - if (!JavaFeature.PATTERN_MATCHING_IN_SWITCH.isSupported(compilerOptions)) { - upperScope.problemReporter().incorrectSwitchType(this.expression, expressionType); - expressionType = null; // fault-tolerance: ignore type mismatch from constants from hereon - } else { - this.isNonTraditional = true; - } - } - } - if (isStringSwitch) { - // the secret variable should be created before iterating over the switch's statements that could - // create more locals. This must be done to prevent overlapping of locals - // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=356002 - this.dispatchStringCopy = new LocalVariableBinding(SecretStringVariableName, upperScope.getJavaLangString(), ClassFileConstants.AccDefault, false); - upperScope.addLocalVariable(this.dispatchStringCopy); - this.dispatchStringCopy.setConstant(Constant.NotAConstant); - this.dispatchStringCopy.useFlag = LocalVariableBinding.USED; - } - addSecretPatternSwitchVariables(upperScope); - if (this.statements != null) { - if (this.scope == null) - this.scope = new BlockScope(upperScope); - int length; - // collection of cases is too big but we will only iterate until caseCount - this.cases = new CaseStatement[length = this.statements.length]; - this.nConstants = getNConstants(); - this.constants = new int[this.nConstants]; - this.otherConstants = new ResolvedCase[this.nConstants]; - this.constMapping = new int[this.nConstants]; - int counter = 0; - int caseCounter = 0; - Pattern[] patterns = new Pattern[this.nConstants]; - int[] caseIndex = new int[this.nConstants]; - LocalVariableBinding[] patternVariables = NO_VARIABLES; - boolean caseNullDefaultFound = false; - boolean defaultFound = false; - for (int i = 0; i < length; i++) { - ResolvedCase[] constantsList; - final Statement statement = this.statements[i]; - if (statement instanceof CaseStatement caseStmt) { - caseNullDefaultFound = caseNullDefaultFound ? caseNullDefaultFound - : isCaseStmtNullDefault(caseStmt); - defaultFound |= caseStmt.constantExpressions == null; - constantsList = caseStmt.resolveCase(this.scope, expressionType, this); - patternVariables = statement.bindingsWhenTrue(); - if (constantsList != ResolvedCase.UnresolvedCase) { - for (ResolvedCase c : constantsList) { - Constant con = c.c; - if (con == Constant.NotAConstant) - continue; - this.otherConstants[counter] = c; - final int c1 = this.containsPatterns ? (c.intValue() == -1 ? -1 : counter) : c.intValue(); - this.constants[counter] = c1; - if (counter == 0 && defaultFound) { - if (c.isPattern() || isCaseStmtNullOnly(caseStmt)) - this.scope.problemReporter().patternDominatedByAnother(c.e); - } - for (int j = 0; j < counter; j++) { - IntPredicate check = idx -> { - Constant c2 = this.otherConstants[idx].c; - if (con.typeID() == TypeIds.T_JavaLangString) { - return c2.stringValue().equals(con.stringValue()); - } else { - if (c2.typeID() == TypeIds.T_JavaLangString) - return false; - if (con.intValue() == c2.intValue()) - return true; - return this.constants[idx] == c1; - } - }; - TypeBinding type = c.e.resolvedType; - if (!type.isValidBinding()) - continue; - if ((caseNullDefaultFound || defaultFound) && (c.isPattern() || isCaseStmtNullOnly(caseStmt))) { - this.scope.problemReporter().patternDominatedByAnother(c.e); - break; - } - Pattern p1 = patterns[j]; - if (p1 != null) { - if (c.isPattern()) { - if (p1.dominates((Pattern) c.e)) { - this.scope.problemReporter().patternDominatedByAnother(c.e); - } - } else { - if (type.id != TypeIds.T_null) { - if (type.isBaseType()) { - type = this.scope.environment().computeBoxingType(type); - } - if (p1.coversType(type)) - this.scope.problemReporter().patternDominatedByAnother(c.e); - } - } - } else { - if (!c.isPattern() && check.test(j)) { - if (this.isNonTraditional) { - if (c.e instanceof NullLiteral && this.otherConstants[j].e instanceof NullLiteral) { - reportDuplicateCase(c.e, this.otherConstants[j].e, length); - } - } else { - reportDuplicateCase(caseStmt, this.cases[caseIndex[j]], length); - } - } - } - } - this.constMapping[counter] = counter; - caseIndex[counter] = caseCounter; - // Only the pattern expressions count for dominance check - if (c.e instanceof Pattern) { - patterns[counter] = (Pattern) c.e; - } - counter++; - } - } - caseCounter++; - } else { - statement.resolveWithBindings(patternVariables, this.scope); - patternVariables = LocalVariableBinding.merge(patternVariables, statement.bindingsWhenComplete()); - } - } - if (length != counter) { // resize constants array - System.arraycopy(this.otherConstants, 0, this.otherConstants = new ResolvedCase[counter], 0, counter); - System.arraycopy(this.constants, 0, this.constants = new int[counter], 0, counter); - System.arraycopy(this.constMapping, 0, this.constMapping = new int[counter], 0, counter); - } - } else { - if ((this.bits & UndocumentedEmptyBlock) != 0) { - upperScope.problemReporter().undocumentedEmptyBlock(this.blockStart, this.sourceEnd); - } - } - // Try it again in case we found any qualified enums. - if (this.dispatchPatternCopy == null) { - addSecretPatternSwitchVariables(upperScope); - } - reportMixingCaseTypes(); - - // check default case for all kinds of switch: - boolean flagged = checkAndFlagDefaultSealed(upperScope, compilerOptions); - if (!flagged && this.defaultCase == null) { - if (ignoreMissingDefaultCase(compilerOptions, isEnumSwitch) && isEnumSwitch) { - upperScope.methodScope().hasMissingSwitchDefault = true; - } else { - if (!isExhaustive()) { - if (isEnhanced) - upperScope.problemReporter().enhancedSwitchMissingDefaultCase(this.expression); - else - upperScope.problemReporter().missingDefaultCase(this, isEnumSwitch, expressionType); - } - } - } - // for enum switch, check if all constants are accounted for (perhaps depending on existence of a default case) - if (isEnumSwitch && compilerOptions.complianceLevel >= ClassFileConstants.JDK1_5) { - if (this.defaultCase == null || compilerOptions.reportMissingEnumCaseDespiteDefault) { - int constantCount = this.otherConstants == null ? 0 : this.otherConstants.length; // could be null if no case statement - // The previous computation of exhaustiveness by comparing the size of cases to the enum fields - // no longer holds true when we throw in a pattern expression to the mix. - // And if there is a total pattern, then we don't have to check further. - if (!((this.switchBits & TotalPattern) != 0) && - (this.containsPatterns || - (constantCount >= this.caseCount && - constantCount != ((ReferenceBinding)expressionType).enumConstantCount()))) { - FieldBinding[] enumFields = ((ReferenceBinding)expressionType.erasure()).fields(); - for (int i = 0, max = enumFields.length; i getAllPermittedTypes(ReferenceBinding ref) { - if (!ref.isSealed()) - return new ArrayList<>(0); - - Set permSet = new HashSet<>(Arrays.asList(ref.permittedTypes())); - if (ref.isClass() && (!ref.isAbstract())) - permSet.add(ref); - Set oldSet = new HashSet<>(permSet); - do { - for (ReferenceBinding type : permSet) { - oldSet.addAll(Arrays.asList(type.permittedTypes())); - } - Set tmp = oldSet; - oldSet = permSet; - permSet = tmp; - } while (oldSet.size() != permSet.size()); - return Arrays.asList(permSet.toArray(new ReferenceBinding[0])); - } - - private boolean checkAndFlagDefaultRecord(BlockScope skope, CompilerOptions compilerOptions, ReferenceBinding ref) { - RecordComponentBinding[] comps = ref.components(); - List allallowedTypes = new ArrayList<>(); - allallowedTypes.add(ref); - if (comps == null || comps.length == 0) { - if (!isExhaustiveWithCaseTypes(allallowedTypes, this.caseLabelElementTypes)) { - skope.problemReporter().enhancedSwitchMissingDefaultCase(this.expression); - return true; - } - return false; - } - // non-zero components - RNode head = new RNode(ref); - for (int i = 0; i < this.caseLabelElements.size(); ++i) { - head.addPattern(this.caseLabelElements.get(i)); - } - CoverageCheckerVisitor ccv = new CoverageCheckerVisitor(); - head.traverse(ccv); - if (!ccv.covers) { - skope.problemReporter().enhancedSwitchMissingDefaultCase(this.expression); - return true; // not exhaustive, error flagged - } - this.switchBits |= SwitchStatement.Exhaustive; - return false; - } - private boolean isExhaustiveWithCaseTypes(List allAllowedTypes, List listedTypes) { - // first KISS (Keep It Simple Stupid) - int pendingTypes = allAllowedTypes.size(); - for (ReferenceBinding pt : allAllowedTypes) { - /* Per JLS 14.11.1.1: A type T that names an abstract sealed class or sealed interface is covered - if every permitted direct subclass or subinterface of it is covered. These subtypes are already - added to allAllowedTypes and subject to cover test. - */ - if (pt.isAbstract() && pt.isSealed()) { - --pendingTypes; - continue; - } - for (TypeBinding type : listedTypes) { - if (pt.isCompatibleWith(type)) { - --pendingTypes; - break; - } - } - } - if (pendingTypes == 0) - return true; - // else - #KICKME (Keep It Complicated Keep Me Employed)" - List coveredTypes = new ArrayList<>(listedTypes); - List remainingTypes = new ArrayList<>(allAllowedTypes); - remainingTypes.removeAll(coveredTypes); - - Map> impliedTypes = new HashMap<>(); - - for (ReferenceBinding type : remainingTypes) { - impliedTypes.put(type, new ArrayList<>()); - List typesToAdd = new ArrayList<>(); - for (ReferenceBinding impliedType : allAllowedTypes) { - if (impliedType.equals(type)) continue; - if (type.isClass()) { - if (impliedType.isAbstract() && type.superclass().equals(impliedType)) { - typesToAdd.add(impliedType); - } - if (Arrays.asList(type.superInterfaces()).contains(impliedType)) - typesToAdd.add(impliedType); - } else if (type.isInterface()) { - if (Arrays.asList(impliedType.superInterfaces()).contains(type)) - typesToAdd.add(impliedType); - } - } - if (!typesToAdd.isEmpty()) { - impliedTypes.get(type).addAll(typesToAdd); - } - } - boolean delta = true; - while (delta) { - delta = false; - List typesToAdd = new ArrayList<>(); - for (ReferenceBinding type : remainingTypes) { - boolean add = false; - if (type.isClass()) { - for (TypeBinding tb : impliedTypes.get(type)) { - if (coveredTypes.contains(tb)) { - add = true; - break; - } - } - } else if (type.isInterface()) { - add = coveredTypes.containsAll(impliedTypes.get(type)); - } - if (add) { - typesToAdd.add(type); - } - } - if (!typesToAdd.isEmpty()) { - remainingTypes.removeAll(typesToAdd); - coveredTypes.addAll(typesToAdd); - typesToAdd.clear(); - delta = true; - } - } - return remainingTypes.isEmpty(); - } - private boolean needPatternDispatchCopy() { - if (this.containsPatterns || (this.switchBits & QualifiedEnum) != 0) - return true; - if (this.containsNull) - return true; - TypeBinding eType = this.expression != null ? this.expression.resolvedType : null; - if (eType == null) - return false; - return !(eType.isPrimitiveOrBoxedPrimitiveType() || eType.isEnum() || eType.id == TypeIds.T_JavaLangString); // classic selectors - } - private void addSecretPatternSwitchVariables(BlockScope upperScope) { - if (needPatternDispatchCopy()) { - this.scope = new BlockScope(upperScope); - this.dispatchPatternCopy = new LocalVariableBinding(SecretPatternVariableName, this.expression.resolvedType, ClassFileConstants.AccDefault, false); - this.scope.addLocalVariable(this.dispatchPatternCopy); - this.dispatchPatternCopy.setConstant(Constant.NotAConstant); - this.dispatchPatternCopy.useFlag = LocalVariableBinding.USED; - this.restartIndexLocal = new LocalVariableBinding(SecretPatternRestartIndexName, TypeBinding.INT, ClassFileConstants.AccDefault, false); - this.scope.addLocalVariable(this.restartIndexLocal); - this.restartIndexLocal.setConstant(Constant.NotAConstant); - this.restartIndexLocal.useFlag = LocalVariableBinding.USED; - } - } - protected void reportMissingEnumConstantCase(BlockScope upperScope, FieldBinding enumConstant) { - upperScope.problemReporter().missingEnumConstantCase(this, enumConstant); - } - protected boolean ignoreMissingDefaultCase(CompilerOptions compilerOptions, boolean isEnumSwitch) { - return compilerOptions.getSeverity(CompilerOptions.MissingDefaultCase) == ProblemSeverities.Ignore; - } - @Override - public boolean isTrulyExpression() { - return false; - } - private void reportMixingCaseTypes() { - if (this.caseCount == 0) { - if (this.defaultCase != null && this.defaultCase.isExpr) - this.switchBits |= LabeledRules; - return; - } - if (this.cases[0] == null) - return; - boolean isExpr = this.cases[0].isExpr; - if (isExpr) this.switchBits |= LabeledRules; - for (int i = 1, l = this.caseCount; i < l; ++i) { - if (this.cases[i].isExpr != isExpr) { - this.scope.problemReporter().switchExpressionMixedCase(this.cases[i]); - return; - } - } - if (this.defaultCase != null && this.defaultCase.isExpr != isExpr) { - this.scope.problemReporter().switchExpressionMixedCase(this.defaultCase); - } - } - private void reportDuplicateCase(final Statement duplicate, - final Statement original, - int length) { - if (this.duplicateCases == null) { - this.scope.problemReporter().duplicateCase(original); - if (duplicate != original) - this.scope.problemReporter().duplicateCase(duplicate); - this.duplicateCases = new Statement[length]; - this.duplicateCases[this.duplicateCaseCounter++] = original; - if (duplicate != original) - this.duplicateCases[this.duplicateCaseCounter++] = duplicate; - } else { - boolean found = false; - searchReportedDuplicate: for (int k = 2; k < this.duplicateCaseCounter; k++) { - if (this.duplicateCases[k] == duplicate) { - found = true; - break searchReportedDuplicate; - } - } - if (!found) { - this.scope.problemReporter().duplicateCase(duplicate); - this.duplicateCases[this.duplicateCaseCounter++] = duplicate; - } - } - } - - @Override - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.expression.traverse(visitor, blockScope); - if (this.statements != null) { - int statementsLength = this.statements.length; - for (int i = 0; i < statementsLength; i++) - this.statements[i].traverse(visitor, this.scope); - } - } - visitor.endVisit(this, blockScope); - } - - /** - * Dispatch the call on its last statement. - */ - @Override - public void branchChainTo(BranchLabel label) { - - // in order to improve debug attributes for stepping (11431) - // we want to inline the jumps to #breakLabel which already got - // generated (if any), and have them directly branch to a better - // location (the argument label). - // we know at this point that the breakLabel already got placed - if (this.breakLabel.forwardReferenceCount() > 0) { - label.becomeDelegateFor(this.breakLabel); - } - } - - @Override - public boolean doesNotCompleteNormally() { - if (this.statements == null || this.statements.length == 0) - return false; - for (int i = 0, length = this.statements.length; i < length; i++) { - if (this.statements[i].breaksOut(null)) - return false; - } - return this.statements[this.statements.length - 1].doesNotCompleteNormally(); - } - - @Override - public boolean completesByContinue() { - if (this.statements == null || this.statements.length == 0) - return false; - for (int i = 0, length = this.statements.length; i < length; i++) { - if (this.statements[i].completesByContinue()) - return true; - } - return false; - } - - @Override - public boolean canCompleteNormally() { - if (this.statements == null || this.statements.length == 0) - return true; - if ((this.switchBits & LabeledRules) == 0) { // switch labeled statement group - if (this.statements[this.statements.length - 1].canCompleteNormally()) - return true; // last statement as well as last switch label after blocks if exists. - if (this.totalPattern == null && this.defaultCase == null) - return true; - for (int i = 0, length = this.statements.length; i < length; i++) { - if (this.statements[i].breaksOut(null)) - return true; - } - } else { - // switch block consists of switch rules - for (Statement stmt : this.statements) { - if (stmt instanceof CaseStatement) - continue; // skip case - if (this.totalPattern == null && this.defaultCase == null) - return true; - if (stmt instanceof Expression) - return true; - if (stmt.canCompleteNormally()) - return true; - if (stmt instanceof YieldStatement && ((YieldStatement) stmt).isImplicit) // note: artificially introduced - return true; - if (stmt instanceof Block) { - Block block = (Block) stmt; - if (block.canCompleteNormally()) - return true; - if (block.breaksOut(null)) - return true; - } - } - } - return false; - } - - @Override - public boolean continueCompletes() { - if (this.statements == null || this.statements.length == 0) - return false; - for (int i = 0, length = this.statements.length; i < length; i++) { - if (this.statements[i].continueCompletes()) - return true; - } - return false; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - return printStatement(indent, output); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java deleted file mode 100644 index 863d676..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java +++ /dev/null @@ -1,255 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Carmi Grushko - Bug 465048 - Binding is null for class literals in synchronized blocks - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class SynchronizedStatement extends SubRoutineStatement { - - public Expression expression; - public Block block; - public BlockScope scope; - public LocalVariableBinding synchroVariable; - static final char[] SecretLocalDeclarationName = " syncValue".toCharArray(); //$NON-NLS-1$ - - // for local variables table attributes - int preSynchronizedInitStateIndex = -1; - int mergedSynchronizedInitStateIndex = -1; - -public SynchronizedStatement( - Expression expression, - Block statement, - int s, - int e) { - - this.expression = expression; - this.block = statement; - this.sourceEnd = e; - this.sourceStart = s; -} - -@Override -public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - - this.preSynchronizedInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); - // TODO (philippe) shouldn't it be protected by a check whether reachable statement ? - - // mark the synthetic variable as being used - this.synchroVariable.useFlag = LocalVariableBinding.USED; - - // simple propagation to subnodes - FlowInfo expressionFlowInfo = this.expression.analyseCode(this.scope, flowContext, flowInfo); - - this.expression.checkNPE(currentScope, flowContext, expressionFlowInfo, 1); - - flowInfo = - this.block.analyseCode( - this.scope, - new InsideSubRoutineFlowContext(flowContext, this), - expressionFlowInfo); - - this.mergedSynchronizedInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); - - // optimizing code gen - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) { - this.bits |= ASTNode.BlockExit; - } - - return flowInfo; -} - -@Override -public boolean isSubRoutineEscaping() { - return false; -} - -/** - * Synchronized statement code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & IsReachable) == 0) { - return; - } - // in case the labels needs to be reinitialized - // when the code generation is restarted in wide mode - this.anyExceptionLabel = null; - - int pc = codeStream.position; - - // generate the synchronization expression - this.expression.generateCode(this.scope, codeStream, true); - if (this.block.isEmptyBlock()) { - switch(this.synchroVariable.type.id) { - case TypeIds.T_long : - case TypeIds.T_double : - codeStream.dup2(); - break; - default : - codeStream.dup(); - break; - } - // only take the lock - codeStream.monitorenter(); - codeStream.monitorexit(); - if (this.scope != currentScope) { - codeStream.exitUserScope(this.scope); - } - } else { - // enter the monitor - codeStream.store(this.synchroVariable, true); - codeStream.addVariable(this.synchroVariable); - codeStream.monitorenter(); - - // generate the body of the synchronized block - enterAnyExceptionHandler(codeStream); - this.block.generateCode(this.scope, codeStream); - if (this.scope != currentScope) { - // close all locals defined in the synchronized block except the secret local - codeStream.exitUserScope(this.scope, lvb -> lvb != this.synchroVariable); - } - - BranchLabel endLabel = new BranchLabel(codeStream); - if ((this.bits & ASTNode.BlockExit) == 0) { - codeStream.load(this.synchroVariable); - codeStream.monitorexit(); - exitAnyExceptionHandler(); - codeStream.goto_(endLabel); - enterAnyExceptionHandler(codeStream); - } - // generate the body of the exception handler - codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable()); - if (this.preSynchronizedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preSynchronizedInitStateIndex); - } - placeAllAnyExceptionHandler(); - codeStream.load(this.synchroVariable); - codeStream.monitorexit(); - exitAnyExceptionHandler(); - codeStream.athrow(); - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedSynchronizedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedSynchronizedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedSynchronizedInitStateIndex); - } - if (this.scope != currentScope) { - codeStream.removeVariable(this.synchroVariable); - } - if ((this.bits & ASTNode.BlockExit) == 0) { - endLabel.place(); - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -/** - * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, LocalVariableBinding) - */ -@Override -public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { - codeStream.load(this.synchroVariable); - codeStream.monitorexit(); - exitAnyExceptionHandler(); - return false; -} - -@Override -public void resolve(BlockScope upperScope) { - // special scope for secret locals optimization. - this.scope = new BlockScope(upperScope); - TypeBinding type = this.expression.resolveType(this.scope); - if (type != null) { - switch (type.id) { - case T_boolean : - case T_char : - case T_float : - case T_double : - case T_byte : - case T_short : - case T_int : - case T_long : - this.scope.problemReporter().invalidTypeToSynchronize(this.expression, type); - break; - case T_void : - this.scope.problemReporter().illegalVoidExpression(this.expression); - break; - case T_null : - this.scope.problemReporter().invalidNullToSynchronize(this.expression); - break; - default : - if (type.hasValueBasedTypeAnnotation()) { - this.scope.problemReporter().discouragedValueBasedTypeToSynchronize(this.expression, type); - } - } - //continue even on errors in order to have the TC done into the statements - this.synchroVariable = new LocalVariableBinding(SecretLocalDeclarationName, type, ClassFileConstants.AccDefault, false); - this.scope.addLocalVariable(this.synchroVariable); - this.synchroVariable.setConstant(Constant.NotAConstant); // not inlinable - this.expression.computeConversion(this.scope, type, type); - } - this.block.resolveUsing(this.scope); -} - -@Override -public StringBuilder printStatement(int indent, StringBuilder output) { - printIndent(indent, output); - output.append("synchronized ("); //$NON-NLS-1$ - this.expression.printExpression(0, output).append(')'); - output.append('\n'); - return this.block.printStatement(indent + 1, output); -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) { - this.expression.traverse(visitor, this.scope); - this.block.traverse(visitor, this.scope); - } - visitor.endVisit(this, blockScope); -} - -@Override -public boolean doesNotCompleteNormally() { - return this.block.doesNotCompleteNormally(); -} -@Override - -public boolean completesByContinue() { - return this.block.completesByContinue(); -} - -@Override -public boolean canCompleteNormally() { - return this.block.canCompleteNormally(); -} - -@Override -public boolean continueCompletes() { - return this.block.continueCompletes(); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TemplateExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TemplateExpression.java deleted file mode 100644 index e564077..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TemplateExpression.java +++ /dev/null @@ -1,80 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -public class TemplateExpression extends Expression { - public Expression processor; - public StringTemplate template; - private MessageSend invocation; - public TemplateExpression(Expression processor, StringTemplate template) { - this.processor = processor; - this.template = template; - this.sourceStart = processor.sourceStart; - this.sourceEnd = template.sourceEnd; - } - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - this.processor.printExpression(0, output); - output.append("."); //$NON-NLS-1$ - this.template.printExpression(0, output); - return output; - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - this.constant = Constant.NotAConstant; - this.template.resolve(scope); - if (this.processor != null) { - this.invocation = new MessageSend(); - this.invocation.receiver = this.processor; - this.invocation.selector = ConstantPool.PROCESS; - this.invocation.arguments = new Expression[] {this.template}; - this.invocation.resolve(scope); - if (this.invocation.binding != null) { - this.resolvedType = this.invocation.binding.returnType; - } - ReferenceBinding processorBinding = scope.getJavaLangStringTemplateProcessor(); - if (this.processor.resolvedType == null) { - // already reported an error. Just return. - return this.resolvedType; - } - if (!this.processor.resolvedType.isCompatibleWith(processorBinding)) { - scope.problemReporter().typeMismatchError(this.processor.resolvedType, processorBinding, this.processor, null); - return this.resolvedType; - } - } - return this.resolvedType; - } - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return this.invocation.analyseCode(currentScope, flowContext, flowInfo); - } - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - this.invocation.generateCode(currentScope, codeStream, true); - codeStream.checkcast(this.invocation.binding.returnType); - if (!valueRequired) { - codeStream.pop(); - } - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TextBlock.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TextBlock.java deleted file mode 100644 index 8675c3c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TextBlock.java +++ /dev/null @@ -1,309 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019, 2023 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 - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.core.compiler.InvalidInputException; -import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class TextBlock extends StringLiteral { - - public int endLineNumber; - - private TextBlock(char[] token, int start, int end, int lineNumber, int endLineNumber) { - super(token, start,end, lineNumber); - this.endLineNumber= endLineNumber - 1; // line number is 1 based - } - public static TextBlock createTextBlock(char[] token, int start, int end, int lineNumber, int endLineNumber) { - return new TextBlock(token, start,end, lineNumber, endLineNumber); - } - public static char[][] convertTextBlockToLines(char[] all) { - // 1. Normalize, i.e. convert all CR CRLF to LF - all = normalize(all); - // 2. Split into lines. Consider both \n and \r as line separators - char[][] lines = CharOperation.splitOn('\n', all); - int size = lines.length; - List list = new ArrayList<>(lines.length); - for(int i = 0; i < lines.length; i++) { - char[] line = lines[i]; - if (i + 1 == size && line.length == 0) { - list.add(line); - break; - } - char[][] sub = CharOperation.splitOn('\r', line); - if (sub.length == 0) { - list.add(line); - } else { - for (char[] cs : sub) { - list.add(cs); - } - } - } - size = list.size(); - lines = list.toArray(new char[size][]); - return lines; - } - public static int getTextBlockIndent(char[][] lines) { - int prefix = -1; - int size = lines.length; - for(int i = 0; i < size; i++) { - char[] line = lines[i]; - boolean blank = true; - int whitespaces = 0; - for (char c : line) { - if (blank) { - if (ScannerHelper.isWhitespace(c)) { - whitespaces++; - } else { - blank = false; - } - } - } - // The last line with closing delimiter is part of the - // determining line list even if empty - if (!blank || (i+1 == size)) { - if (prefix < 0 || whitespaces < prefix) { - prefix = whitespaces; - } - } - } - return prefix == -1 ? 0 : prefix; - } - public static int getIndentForFragments(char[][] fragments) { - int prefix = -1; - for(int index = 0; index < fragments.length; index++) { - char[][] lines = convertTextBlockToLines(fragments[index]); - int size = lines.length; - for(int i = 0; i < size; i++) { - if (index > 0 && i == 0) { - continue; - } - char[] line = lines[i]; - boolean blank = true; - int whitespaces = 0; - for (char c : line) { - if (blank) { - if (ScannerHelper.isWhitespace(c)) { - whitespaces++; - } else { - blank = false; - } - } - } - // The last line with closing delimiter is part of the - // determining line list even if empty - if (!blank || (i+1 == size)) { - if (prefix < 0 || whitespaces < prefix) { - prefix = whitespaces; - } - } - } - } - return prefix == -1 ? 0 : prefix; - } - public static char[] formatTextBlock(char[] all, int indent, boolean followsExp, boolean precedesExp) { - char[][] lines = convertTextBlockToLines(all); - return formatTextBlock(lines, indent, followsExp, precedesExp); - } - public static char[] formatTextBlock(char[][] lines, int indent) { - return formatTextBlock(lines, indent, false, false); - } - public static char[] formatTextBlock(char[][] lines, int indent, boolean followsExp, boolean precedesExp) { - // Handle incidental white space - // Split into lines and identify determining lines - // Remove the common white space prefix - // Handle escape sequences that are not already done in getNextToken0() - int size = lines.length; - StringBuilder result = new StringBuilder(); - boolean newLine = false; - for(int i = 0; i < size; i++) { - if (i > 0) - followsExp = false; - char[] l = lines[i]; - int length = l.length; - int prefix = followsExp ? 0 : indent; - // Remove the common prefix from each line - // And remove all trailing whitespace - // Finally append the \n at the end of the line (except the last line) - int trail = length; - // Only the last line is really prefixed to the embedded - // expression in a string template - if (!precedesExp || i < (size -1)) { - for(;trail > 0;) { - if (!ScannerHelper.isWhitespace(l[trail-1])) { - break; - } - trail--; - } - } - if (i >= (size -1)) { - if (newLine) result.append('\n'); - if (trail < prefix) - continue; - newLine = getLineContent(result, l, prefix, trail-1, false, true); - } else { - if (i > 0 && newLine) - result.append('\n'); - if (trail <= prefix) { - newLine = true; - } else { - boolean merge = length > 0 && l[length - 1] == '\\'; - newLine = getLineContent(result, l, prefix, trail-1, merge, false); - } - } - } - return result.toString().toCharArray(); - } - private static char[] normalize(char[] content) { - StringBuilder result = new StringBuilder(); - boolean isCR = false; - for (char c : content) { - switch (c) { - case '\r': - result.append(c); - isCR = true; - break; - case '\n': - if (!isCR) { - result.append(c); - } - isCR = false; - break; - default: - result.append(c); - isCR = false; - break; - } - } - return result.toString().toCharArray(); - } - // This method is for handling the left over escaped characters during the first - // scanning (scanForStringLiteral). Admittedly this goes over the text block - // content again char by char, but this is required in order to correctly - // treat all the white space and line endings - private static boolean getLineContent(StringBuilder result, char[] line, int start, int end, boolean merge, boolean lastLine) { - int lastPointer = 0; - for(int i = start; i < end;) { - char c = line[i]; - if (c != '\\') { - i++; - continue; - } - if (i < end) { - if (lastPointer + 1 <= i) { - result.append(CharOperation.subarray(line, lastPointer == 0 ? start : lastPointer, i)); - } - char next = line[++i]; - switch (next) { - case '\\' : - result.append('\\'); - if (i == end) - merge = false; - break; - case 's' : - result.append(' '); - break; - case '"': - result.append('"'); - break; - case 'b' : - result.append('\b'); - break; - case 'n' : - result.append('\n'); - break; - case 'r' : - result.append('\r'); - break; - case 't' : - result.append('\t'); - break; - case 'f' : - result.append('\f'); - break; - default : - // Direct copy from Scanner#scanEscapeCharacter - int pos = i + 1; - int number = ScannerHelper.getHexadecimalValue(next); - if (number >= 0 && number <= 7) { - boolean zeroToThreeNot = number > 3; - try { - if (pos <= end && ScannerHelper.isDigit(next = line[pos])) { - pos++; - int digit = ScannerHelper.getHexadecimalValue(next); - if (digit >= 0 && digit <= 7) { - number = (number * 8) + digit; - if (pos <= end && ScannerHelper.isDigit(next = line[pos])) { - pos++; - if (zeroToThreeNot) { - // has read \NotZeroToThree OctalDigit Digit --> ignore last character - } else { - digit = ScannerHelper.getHexadecimalValue(next); - if (digit >= 0 && digit <= 7){ // has read \ZeroToThree OctalDigit OctalDigit - number = (number * 8) + digit; - } else { - // has read \ZeroToThree OctalDigit NonOctalDigit --> ignore last character - } - } - } else { - // has read \OctalDigit NonDigit--> ignore last character - } - } else { - // has read \OctalDigit NonOctalDigit--> ignore last character - } - } else { - // has read \OctalDigit --> ignore last character - } - } catch (InvalidInputException e) { - // Unlikely as this has already been processed in scanForStringLiteral() - } - if (number < 255) { - next = (char) number; - } - result.append(next); - lastPointer = i = pos; - continue; - } else { - // Dealing with just '\' - result.append(c); - lastPointer = i; - continue; - } - } - lastPointer = ++i; - } - } - end = merge ? end : end >= line.length ? end : end + 1; - char[] chars = lastPointer == 0 ? - CharOperation.subarray(line, start, end) : - CharOperation.subarray(line, lastPointer, end); - // The below check is because CharOperation.subarray tend to return null when the - // boundaries produce a zero sized char[] - if (chars != null && chars.length > 0) - result.append(chars); - return (!merge && !lastLine); - } - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - output.append("\"\"\"\n"); //$NON-NLS-1$ - for (char c:this.source()) { - Util.appendEscapedChar(output, c, true); - } - output.append("\"\"\""); //$NON-NLS-1$ - return output; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ThisReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ThisReference.java deleted file mode 100644 index 20e08d0..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ThisReference.java +++ /dev/null @@ -1,161 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2015 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 331649 - [compiler][null] consider null annotations for fields - * bug 383368 - [compiler][null] syntactic null analysis for field references - * Jesper S Moller - Contributions for - * Bug 378674 - "The method can be declared as static" is wrong - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.*; -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.*; - -public class ThisReference extends Reference { - - public static ThisReference implicitThis(){ - - ThisReference implicitThis = new ThisReference(0, 0); - implicitThis.bits |= IsImplicitThis; - return implicitThis; - } - - public ThisReference(int sourceStart, int sourceEnd) { - - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; - } - - @Override - public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Assignment assignment, boolean isCompound) { - - return flowInfo; // this cannot be assigned - } - - public boolean checkAccess(BlockScope scope, ReferenceBinding receiverType) { - - MethodScope methodScope = scope.methodScope(); - // this/super cannot be used in constructor call - if (methodScope.isConstructorCall) { - methodScope.problemReporter().fieldsOrThisBeforeConstructorInvocation(this); - return false; - } - - // static may not refer to this/super - if (methodScope.isStatic) { - methodScope.problemReporter().errorThisSuperInStatic(this); - return false; - } else if (this.isUnqualifiedSuper()) { - TypeDeclaration type = methodScope.referenceType(); - if (type != null && TypeDeclaration.kind(type.modifiers) == TypeDeclaration.INTERFACE_DECL) { - methodScope.problemReporter().errorNoSuperInInterface(this); - return false; - } - } - if (receiverType != null) - scope.tagAsAccessingEnclosingInstanceStateOf(receiverType, false /* type variable access */); - return true; - } - - @Override - public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) { - return true; // never problematic - } - - @Override - public void generateAssignment(BlockScope currentScope, CodeStream codeStream, Assignment assignment, boolean valueRequired) { - - // this cannot be assigned - } - - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - - int pc = codeStream.position; - if (valueRequired) - codeStream.aload_0(); - if ((this.bits & IsImplicitThis) == 0) codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public void generateCompoundAssignment(BlockScope currentScope, CodeStream codeStream, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { - - // this cannot be assigned - } - - @Override - public void generatePostIncrement(BlockScope currentScope, CodeStream codeStream, CompoundAssignment postIncrement, boolean valueRequired) { - - // this cannot be assigned - } - - @Override - public boolean isImplicitThis() { - - return (this.bits & IsImplicitThis) != 0; - } - - @Override - public boolean isThis() { - - return true ; - } - - @Override - public int nullStatus(FlowInfo flowInfo, FlowContext flowContext) { - return FlowInfo.NON_NULL; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output){ - - if (isImplicitThis()) return output; - return output.append("this"); //$NON-NLS-1$ - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - - this.constant = Constant.NotAConstant; - - ReferenceBinding enclosingReceiverType = scope.enclosingReceiverType(); - if (!isImplicitThis() &&!checkAccess(scope, enclosingReceiverType)) { - return null; - } - this.resolvedType = enclosingReceiverType; - MethodScope methodScope = scope.namedMethodScope(); - if (methodScope != null) { - MethodBinding method = methodScope.referenceMethodBinding(); - if (method != null && method.receiver != null && TypeBinding.equalsEquals(method.receiver, this.resolvedType)) - this.resolvedType = method.receiver; - } - return this.resolvedType; - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope blockScope) { - - visitor.visit(this, blockScope); - visitor.endVisit(this, blockScope); - } - @Override - public void traverse(ASTVisitor visitor, ClassScope blockScope) { - - visitor.visit(this, blockScope); - visitor.endVisit(this, blockScope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java deleted file mode 100644 index bfa0da9..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/ThrowStatement.java +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2014 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 359334 - Analysis for resource leak warnings does not consider exceptions as method exit points - * bug 368546 - [compiler][resource] Avoid remaining false positives found when compiling the Eclipse SDK - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * Bug 429430 - [1.8] Lambdas and method reference infer wrong exception type with generics (RuntimeException instead of IOException) - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -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.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -public class ThrowStatement extends Statement { - - public Expression exception; - public TypeBinding exceptionType; - -public ThrowStatement(Expression exception, int sourceStart, int sourceEnd) { - this.exception = exception; - this.sourceStart = sourceStart; - this.sourceEnd = sourceEnd; -} - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - this.exception.analyseCode(currentScope, flowContext, flowInfo); - 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, flowContext, this, currentScope); - flowContext.recordAbruptExit(); - return FlowInfo.DEAD_END; -} - -/** - * Throw code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) - return; - int pc = codeStream.position; - this.exception.generateCode(currentScope, codeStream, true); - codeStream.athrow(); - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -@Override -public StringBuilder printStatement(int indent, StringBuilder output) { - printIndent(indent, output).append("throw "); //$NON-NLS-1$ - this.exception.printExpression(0, output); - return output.append(';'); -} - -@Override -public void resolve(BlockScope scope) { - this.exceptionType = this.exception.resolveType(scope); - if (this.exceptionType != null && this.exceptionType.isValidBinding()) { - if (this.exceptionType == TypeBinding.NULL) { - if (scope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3){ - // if compliant with 1.4, this problem will not be reported - scope.problemReporter().cannotThrowNull(this.exception); - } - } else if (this.exceptionType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) == null) { - scope.problemReporter().cannotThrowType(this.exception, this.exceptionType); - } - this.exception.computeConversion(scope, this.exceptionType, this.exceptionType); - } -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) - this.exception.traverse(visitor, blockScope); - visitor.endVisit(this, blockScope); -} - -@Override -public boolean doesNotCompleteNormally() { - return true; -} - -@Override -public boolean canCompleteNormally() { - return false; -} - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java deleted file mode 100644 index 86c395f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TrueLiteral.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2009 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -import org.eclipse.jdt.internal.compiler.impl.BooleanConstant; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; - -public class TrueLiteral extends MagicLiteral { - - static final char[] source = {'t' , 'r' , 'u' , 'e'}; - -public TrueLiteral(int s , int e) { - super(s,e); -} -@Override -public void computeConstant() { - this.constant = BooleanConstant.fromValue(true); -} -/** - * Code generation for the true literal - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) { - int pc = codeStream.position; - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} -@Override -public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) { - - // trueLabel being not nil means that we will not fall through into the TRUE case - - int pc = codeStream.position; - // constant == true - if (valueRequired) { - if (falseLabel == null) { - // implicit falling through the FALSE case - if (trueLabel != null) { - codeStream.goto_(trueLabel); - } - } - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} -@Override -public TypeBinding literalType(BlockScope scope) { - return TypeBinding.BOOLEAN; -} -@Override -public char[] source() { - return source; -} -@Override -public void traverse(ASTVisitor visitor, BlockScope scope) { - visitor.visit(this, scope); - visitor.endVisit(this, scope); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TryStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TryStatement.java deleted file mode 100644 index 3ae6aca..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TryStatement.java +++ /dev/null @@ -1,1417 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * 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 - * bug 358903 - Filter practically unimportant resource leak warnings - * bug 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 388996 - [compiler][resource] Incorrect 'potential resource leak' - * bug 401088 - [compiler][null] Wrong warning "Redundant null check" inside nested try statement - * bug 401092 - [compiler][null] Wrong warning "Redundant null check" in outer catch of nested try - * bug 402993 - [null] Follow up of bug 401088: Missing warning about redundant null check - * bug 384380 - False positive on a ?? Potential null pointer access ?? after a continue - * Bug 415790 - [compiler][resource]Incorrect potential resource leak warning in for loop with close in try/catch - * Bug 371614 - [compiler][resource] Wrong "resource leak" problem on return/throw inside while loop - * Bug 444964 - [1.7+][resource] False resource leak warning (try-with-resources for ByteArrayOutputStream - return inside for loop) - * Jesper Steen Moller - Contributions for - * bug 404146 - [1.7][compiler] nested try-catch-finally-blocks leads to unrunnable Java byte code - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class TryStatement extends SubRoutineStatement { - - static final char[] SECRET_RETURN_ADDRESS_NAME = " returnAddress".toCharArray(); //$NON-NLS-1$ - static final char[] SECRET_ANY_HANDLER_NAME = " anyExceptionHandler".toCharArray(); //$NON-NLS-1$ - static final char[] SECRET_PRIMARY_EXCEPTION_VARIABLE_NAME = " primaryException".toCharArray(); //$NON-NLS-1$ - static final char[] SECRET_CAUGHT_THROWABLE_VARIABLE_NAME = " caughtThrowable".toCharArray(); //$NON-NLS-1$; - static final char[] SECRET_RETURN_VALUE_NAME = " returnValue".toCharArray(); //$NON-NLS-1$ - - public Statement[] resources = new Statement[0]; - public Block tryBlock; - public Block[] catchBlocks; - - public Argument[] catchArguments; - - public Block finallyBlock; - BlockScope scope; - - public UnconditionalFlowInfo subRoutineInits; - ReferenceBinding[] caughtExceptionTypes; - boolean[] catchExits; - - BranchLabel subRoutineStartLabel; - public LocalVariableBinding anyExceptionVariable, - returnAddressVariable, - secretReturnValue; - - ExceptionLabel[] declaredExceptionLabels; // only set while generating code - - // for inlining/optimizing JSR instructions - private Object[] reusableJSRTargets; - private BranchLabel[] reusableJSRSequenceStartLabels; - private int[] reusableJSRStateIndexes; - private int reusableJSRTargetsCount = 0; - - private static final int NO_FINALLY = 0; // no finally block - private static final int FINALLY_SUBROUTINE = 1; // finally is generated as a subroutine (using jsr/ret bytecodes) - private static final int FINALLY_DOES_NOT_COMPLETE = 2; // non returning finally is optimized with only one instance of finally block - private static final int FINALLY_INLINE = 3; // finally block must be inlined since cannot use jsr/ret bytecodes >1.5 - - // for local variables table attributes - int mergedInitStateIndex = -1; - int preTryInitStateIndex = -1; - int postTryInitStateIndex = -1; - int[] postResourcesInitStateIndexes; - int naturalExitMergeInitStateIndex = -1; - int[] catchExitInitStateIndexes; - private LocalVariableBinding primaryExceptionVariable; - private LocalVariableBinding caughtThrowableVariable; - private ExceptionLabel[] resourceExceptionLabels; - private int[] caughtExceptionsCatchBlocks; - - public SwitchExpression enclosingSwitchExpression = null; - -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - - // Consider the try block and catch block so as to compute the intersection of initializations and - // the minimum exit relative depth amongst all of them. Then consider the subroutine, and append its - // initialization to the try/catch ones, if the subroutine completes normally. If the subroutine does not - // complete, then only keep this result for the rest of the analysis - - // process the finally block (subroutine) - create a context for the subroutine - - this.preTryInitStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); - - if (this.anyExceptionVariable != null) { - this.anyExceptionVariable.useFlag = LocalVariableBinding.USED; - } - if (this.primaryExceptionVariable != null) { - this.primaryExceptionVariable.useFlag = LocalVariableBinding.USED; - } - if (this.caughtThrowableVariable != null) { - this.caughtThrowableVariable.useFlag = LocalVariableBinding.USED; - } - if (this.returnAddressVariable != null) { // TODO (philippe) if subroutine is escaping, unused - this.returnAddressVariable.useFlag = LocalVariableBinding.USED; - } - int resourcesLength = this.resources.length; - if (resourcesLength > 0) { - this.postResourcesInitStateIndexes = new int[resourcesLength]; - } - - - if (this.subRoutineStartLabel == null) { - // no finally block -- this is a simplified copy of the else part - if (flowContext instanceof FinallyFlowContext) { - // if this TryStatement sits inside another TryStatement, establish the wiring so that - // FlowContext.markFinallyNullStatus can report into initsOnFinally of the outer try context: - FinallyFlowContext finallyContext = (FinallyFlowContext) flowContext; - finallyContext.outerTryContext = finallyContext.tryContext; - } - // process the try block in a context handling the local exceptions. - ExceptionHandlingFlowContext handlingContext = - new ExceptionHandlingFlowContext( - flowContext, - this, - this.caughtExceptionTypes, - this.caughtExceptionsCatchBlocks, - null, - this.scope, - flowInfo); - handlingContext.conditionalLevel = 0; // start collection initsOnFinally - // only try blocks initialize that member - may consider creating a - // separate class if needed - - FlowInfo tryInfo = flowInfo.copy(); - for (int i = 0; i < resourcesLength; i++) { - final Statement resource = this.resources[i]; - tryInfo = resource.analyseCode(currentScope, handlingContext, tryInfo); - this.postResourcesInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(tryInfo); - TypeBinding resolvedType = null; - LocalVariableBinding localVariableBinding = null; - if (resource instanceof LocalDeclaration) { - localVariableBinding = ((LocalDeclaration) resource).binding; - resolvedType = localVariableBinding.type; - if (localVariableBinding.closeTracker != null) { - // this was false alarm, we don't need to track the resource - localVariableBinding.closeTracker.withdraw(); - localVariableBinding.closeTracker = null; - } - } else { //expression - if (resource instanceof NameReference && ((NameReference) resource).binding instanceof LocalVariableBinding) { - localVariableBinding = (LocalVariableBinding) ((NameReference) resource).binding; - } - resolvedType = ((Expression) resource).resolvedType; - if (currentScope.compilerOptions().analyseResourceLeaks) { - recordCallingClose(currentScope, handlingContext, tryInfo, (Expression)resource); - } - } - if (localVariableBinding != null) { - localVariableBinding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways. - } - MethodBinding closeMethod = findCloseMethod(resource, resolvedType); - if (closeMethod != null && closeMethod.isValidBinding() && 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[i], tryInfo, currentScope, true); - } - } - } - if (!this.tryBlock.isEmptyBlock()) { - tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, tryInfo); - if ((tryInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) - this.bits |= ASTNode.IsTryBlockExiting; - } - if (resourcesLength > 0) { - this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); - // the resources are not in scope after the try block, so remove their assignment info - // to avoid polluting the state indices. However, do this after the postTryInitStateIndex is calculated since - // it is used to add or remove assigned resources during code gen - for (int i = 0; i < resourcesLength; i++) { - if (this.resources[i] instanceof LocalDeclaration) - tryInfo.resetAssignmentInfo(((LocalDeclaration) this.resources[i]).binding); - } - } - // check unreachable catch blocks - handlingContext.complainIfUnusedExceptionHandlers(this.scope, this); - - // process the catch blocks - computing the minimal exit depth amongst try/catch - if (this.catchArguments != null) { - int catchCount; - this.catchExits = new boolean[catchCount = this.catchBlocks.length]; - this.catchExitInitStateIndexes = new int[catchCount]; - for (int i = 0; i < catchCount; i++) { - // keep track of the inits that could potentially have led to this exception handler (for final assignments diagnosis) - FlowInfo catchInfo = prepareCatchInfo(flowInfo, handlingContext, tryInfo, i); - flowContext.conditionalLevel++; - catchInfo = - this.catchBlocks[i].analyseCode( - currentScope, - flowContext, - catchInfo); - flowContext.conditionalLevel--; - this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo); - this.catchExits[i] = - (catchInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0; - tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits()); - } - } - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(tryInfo); - - // chain up null info registry - flowContext.mergeFinallyNullInfo(handlingContext.initsOnFinally); - - return tryInfo; - } else { - InsideSubRoutineFlowContext insideSubContext; - FinallyFlowContext finallyContext; - UnconditionalFlowInfo subInfo; - // analyse finally block first - insideSubContext = new InsideSubRoutineFlowContext(flowContext, this); - if (flowContext instanceof FinallyFlowContext) { - // if this TryStatement sits inside another TryStatement, establish the wiring so that - // FlowContext.markFinallyNullStatus can report into initsOnFinally of the outer try context: - insideSubContext.outerTryContext = ((FinallyFlowContext)flowContext).tryContext; - } - - // process the try block in a context handling the local exceptions. - // (advance instantiation so we can wire this into the FinallyFlowContext) - ExceptionHandlingFlowContext handlingContext = - new ExceptionHandlingFlowContext( - insideSubContext, - this, - this.caughtExceptionTypes, - this.caughtExceptionsCatchBlocks, - null, - this.scope, - flowInfo); - insideSubContext.initsOnFinally = handlingContext.initsOnFinally; - - subInfo = - this.finallyBlock - .analyseCode( - currentScope, - finallyContext = new FinallyFlowContext(flowContext, this.finallyBlock, handlingContext), - flowInfo.nullInfoLessUnconditionalCopy()) - .unconditionalInits(); - handlingContext.conditionalLevel = 0; // start collection initsOnFinally only after analysing the finally block - 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; - // only try blocks initialize that member - may consider creating a - // separate class if needed - - FlowInfo tryInfo = flowInfo.copy(); - for (int i = 0; i < resourcesLength; i++) { - final Statement resource = this.resources[i]; - tryInfo = resource.analyseCode(currentScope, handlingContext, tryInfo); - this.postResourcesInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(tryInfo); - TypeBinding resolvedType = null; - LocalVariableBinding localVariableBinding = null; - if (resource instanceof LocalDeclaration) { - localVariableBinding = ((LocalDeclaration) this.resources[i]).binding; - resolvedType = localVariableBinding.type; - if (localVariableBinding.closeTracker != null) { - // this was false alarm, we don't need to track the resource - localVariableBinding.closeTracker.withdraw(); - // keep the tracking variable in the resourceBinding in order to prevent creating a new one while analyzing the try block - } - } else { // Expression - if (resource instanceof NameReference && ((NameReference) resource).binding instanceof LocalVariableBinding) { - localVariableBinding = (LocalVariableBinding)((NameReference) resource).binding; - } - recordCallingClose(currentScope, flowContext, tryInfo, (Expression)resource); - resolvedType = ((Expression) resource).resolvedType; - } - if (localVariableBinding != null) { - localVariableBinding.useFlag = LocalVariableBinding.USED; // Is implicitly used anyways. - } - MethodBinding closeMethod = findCloseMethod(resource, resolvedType); - if (closeMethod != null && closeMethod.isValidBinding() && 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[i], tryInfo, currentScope, true); - } - } - } - if (!this.tryBlock.isEmptyBlock()) { - tryInfo = this.tryBlock.analyseCode(currentScope, handlingContext, tryInfo); - if ((tryInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) - this.bits |= ASTNode.IsTryBlockExiting; - } - if (resourcesLength > 0) { - this.postTryInitStateIndex = currentScope.methodScope().recordInitializationStates(tryInfo); - // the resources are not in scope after the try block, so remove their assignment info - // to avoid polluting the state indices. However, do this after the postTryInitStateIndex is calculated since - // it is used to add or remove assigned resources during code gen - for (int i = 0; i < resourcesLength; i++) { - if (this.resources[i] instanceof LocalDeclaration) - tryInfo.resetAssignmentInfo(((LocalDeclaration)this.resources[i]).binding); - } - } - // check unreachable catch blocks - handlingContext.complainIfUnusedExceptionHandlers(this.scope, this); - - // process the catch blocks - computing the minimal exit depth amongst try/catch - if (this.catchArguments != null) { - int catchCount; - this.catchExits = new boolean[catchCount = this.catchBlocks.length]; - this.catchExitInitStateIndexes = new int[catchCount]; - for (int i = 0; i < catchCount; i++) { - // keep track of the inits that could potentially have led to this exception handler (for final assignments diagnosis) - FlowInfo catchInfo = prepareCatchInfo(flowInfo, handlingContext, tryInfo, i); - insideSubContext.conditionalLevel = 1; - catchInfo = - this.catchBlocks[i].analyseCode( - currentScope, - insideSubContext, - catchInfo); - this.catchExitInitStateIndexes[i] = currentScope.methodScope().recordInitializationStates(catchInfo); - this.catchExits[i] = - (catchInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0; - tryInfo = tryInfo.mergedWith(catchInfo.unconditionalInits()); - } - } - // we also need to check potential multiple assignments of final variables inside the finally block - // need to include potential inits from returns inside the try/catch parts - 1GK2AOF - finallyContext.complainOnDeferredChecks( - ((tryInfo.tagBits & FlowInfo.UNREACHABLE) == 0 ? - flowInfo.unconditionalCopy(). - addPotentialInitializationsFrom(tryInfo). - // lighten the influence of the try block, which may have - // exited at any point - addPotentialInitializationsFrom(insideSubContext.initsOnReturn) : - insideSubContext.initsOnReturn). - addNullInfoFrom( - handlingContext.initsOnFinally), - currentScope); - - // chain up null info registry - flowContext.mergeFinallyNullInfo(handlingContext.initsOnFinally); - - this.naturalExitMergeInitStateIndex = - currentScope.methodScope().recordInitializationStates(tryInfo); - if (subInfo == FlowInfo.DEAD_END) { - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(subInfo); - return subInfo; - } else { - FlowInfo mergedInfo = tryInfo.addInitializationsFrom(subInfo); - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } - } -} -private void recordCallingClose(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo, Expression closeTarget) { - FakedTrackingVariable trackingVariable = FakedTrackingVariable.getCloseTrackingVariable(closeTarget, flowInfo, flowContext, - currentScope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled); - if (trackingVariable != null) { // null happens if target is not a local variable or not an AutoCloseable - if (trackingVariable.methodScope == currentScope.methodScope()) { - trackingVariable.markClose(flowInfo, flowContext); - } else { - trackingVariable.markClosedInNestedMethod(); - } - trackingVariable.markClosedEffectivelyFinal(); - } -} -private MethodBinding findCloseMethod(final ASTNode resource, TypeBinding type) { - MethodBinding closeMethod = null; - if (type != null && type.isValidBinding() && type instanceof ReferenceBinding) { - ReferenceBinding binding = (ReferenceBinding) type; - closeMethod = binding.getExactMethod(ConstantPool.Close, new TypeBinding [0], this.scope.compilationUnitScope()); // scope needs to be tighter - if(closeMethod == null) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=380112 - // closeMethod could be null if the binding is from an interface - // extending from multiple interfaces. - InvocationSite site = new InvocationSite.EmptyWithAstNode(resource); - closeMethod = this.scope.compilationUnitScope().findMethod(binding, ConstantPool.Close, new TypeBinding[0], site, false); - } - } - return closeMethod; -} -private FlowInfo prepareCatchInfo(FlowInfo flowInfo, ExceptionHandlingFlowContext handlingContext, FlowInfo tryInfo, int i) { - FlowInfo catchInfo; - if (isUncheckedCatchBlock(i)) { - catchInfo = - flowInfo.unconditionalCopy(). - addPotentialInitializationsFrom( - handlingContext.initsOnException(i)). - addPotentialInitializationsFrom(tryInfo). - addPotentialInitializationsFrom( - handlingContext.initsOnReturn). - addNullInfoFrom(handlingContext.initsOnFinally); - } else { - FlowInfo initsOnException = handlingContext.initsOnException(i); - catchInfo = - flowInfo.nullInfoLessUnconditionalCopy() - .addPotentialInitializationsFrom(initsOnException) - .addNullInfoFrom(initsOnException) // <<== Null info only from here! - .addPotentialInitializationsFrom( - tryInfo.nullInfoLessUnconditionalCopy()) - .addPotentialInitializationsFrom( - handlingContext.initsOnReturn.nullInfoLessUnconditionalCopy()); - } - - // catch var is always set - LocalVariableBinding catchArg = this.catchArguments[i].binding; - catchInfo.markAsDefinitelyAssigned(catchArg); - catchInfo.markAsDefinitelyNonNull(catchArg); - /* - "If we are about to consider an unchecked exception handler, potential inits may have occured inside - the try block that need to be detected , e.g. - try { x = 1; throwSomething();} catch(Exception e){ x = 2} " - "(uncheckedExceptionTypes notNil and: [uncheckedExceptionTypes at: index]) - ifTrue: [catchInits addPotentialInitializationsFrom: tryInits]." - */ - if (this.tryBlock.statements == null && this.resources == null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=350579 - catchInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - return catchInfo; -} -// Return true if the catch block corresponds to an unchecked exception making allowance for multi-catch blocks. -private boolean isUncheckedCatchBlock(int catchBlock) { - if (this.caughtExceptionsCatchBlocks == null) { - return this.caughtExceptionTypes[catchBlock].isUncheckedException(true); - } - for (int i = 0, length = this.caughtExceptionsCatchBlocks.length; i < length; i++) { - if (this.caughtExceptionsCatchBlocks[i] == catchBlock) { - if (this.caughtExceptionTypes[i].isUncheckedException(true)) { - return true; - } - } - } - return false; -} - -@Override -public ExceptionLabel enterAnyExceptionHandler(CodeStream codeStream) { - if (this.subRoutineStartLabel == null) - return null; - return super.enterAnyExceptionHandler(codeStream); -} - -@Override -public void enterDeclaredExceptionHandlers(CodeStream codeStream) { - for (int i = 0, length = this.declaredExceptionLabels == null ? 0 : this.declaredExceptionLabels.length; i < length; i++) { - this.declaredExceptionLabels[i].placeStart(); - } - int resourceCount = this.resources.length; - if (resourceCount > 0 && this.resourceExceptionLabels != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=375248 - // Reinstall handlers - for (int i = resourceCount; i >= 0; --i) { - this.resourceExceptionLabels[i].placeStart(); - } - } -} - -@Override -public void exitAnyExceptionHandler() { - if (this.subRoutineStartLabel == null) - return; - super.exitAnyExceptionHandler(); -} - -@Override -public void exitDeclaredExceptionHandlers(CodeStream codeStream) { - for (int i = 0, length = this.declaredExceptionLabels == null ? 0 : this.declaredExceptionLabels.length; i < length; i++) { - this.declaredExceptionLabels[i].placeEnd(); - } -} - -private int finallyMode() { - if (this.subRoutineStartLabel == null) { - return NO_FINALLY; - } else if (isSubRoutineEscaping()) { - return FINALLY_DOES_NOT_COMPLETE; - } else if (this.scope.compilerOptions().inlineJsrBytecode) { - return FINALLY_INLINE; - } else { - return FINALLY_SUBROUTINE; - } -} -/** - * Try statement code generation with or without jsr bytecode use - * post 1.5 target level, cannot use jsr bytecode, must instead inline finally block - * returnAddress is only allocated if jsr is allowed - */ -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) { - return; - } - boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; - // in case the labels needs to be reinitialized - // when the code generation is restarted in wide mode - this.anyExceptionLabel = null; - this.reusableJSRTargets = null; - this.reusableJSRSequenceStartLabels = null; - this.reusableJSRTargetsCount = 0; - - int pc = codeStream.position; - int finallyMode = finallyMode(); - - boolean requiresNaturalExit = false; - // preparing exception labels - int maxCatches = this.catchArguments == null ? 0 : this.catchArguments.length; - ExceptionLabel[] exceptionLabels; - if (maxCatches > 0) { - exceptionLabels = new ExceptionLabel[maxCatches]; - for (int i = 0; i < maxCatches; i++) { - Argument argument = this.catchArguments[i]; - ExceptionLabel exceptionLabel = null; - if ((argument.binding.tagBits & TagBits.MultiCatchParameter) != 0) { - MultiCatchExceptionLabel multiCatchExceptionLabel = new MultiCatchExceptionLabel(codeStream, argument.binding.type); - multiCatchExceptionLabel.initialize((UnionTypeReference) argument.type, argument.annotations); - exceptionLabel = multiCatchExceptionLabel; - } else { - exceptionLabel = new ExceptionLabel(codeStream, argument.binding.type, argument.type, argument.annotations); - } - exceptionLabel.placeStart(); - exceptionLabels[i] = exceptionLabel; - } - } else { - exceptionLabels = null; - } - if (this.subRoutineStartLabel != null) { - this.subRoutineStartLabel.initialize(codeStream); - enterAnyExceptionHandler(codeStream); - } - // generate the try block - try { - codeStream.pushPatternAccessTrapScope(this.tryBlock.scope); - this.declaredExceptionLabels = exceptionLabels; - int resourceCount = this.resources.length; - if (resourceCount > 0) { - // Please see https://bugs.eclipse.org/bugs/show_bug.cgi?id=338402#c16 - this.resourceExceptionLabels = new ExceptionLabel[resourceCount + 1]; - codeStream.aconst_null(); - codeStream.store(this.primaryExceptionVariable, false /* value not required */); - codeStream.addVariable(this.primaryExceptionVariable); - codeStream.aconst_null(); - codeStream.store(this.caughtThrowableVariable, false /* value not required */); - codeStream.addVariable(this.caughtThrowableVariable); - for (int i = 0; i <= resourceCount; i++) { - // put null for the exception type to treat them as any exception handlers (equivalent to a try/finally) - this.resourceExceptionLabels[i] = new ExceptionLabel(codeStream, null); - this.resourceExceptionLabels[i].placeStart(); - if (i < resourceCount) { - Statement stmt = this.resources[i]; - if (stmt instanceof NameReference) { - NameReference ref = (NameReference) stmt; - ref.bits |= ASTNode.IsCapturedOuterLocal; // TODO: selective flagging if ref.binding is not one of earlier inlined LVBs. - VariableBinding binding = (VariableBinding) ref.binding; // Only LVB expected here. - ref.checkEffectiveFinality(binding, this.scope); - } else if (stmt instanceof FieldReference) { - FieldReference fieldReference = (FieldReference) stmt; - if (!fieldReference.binding.isFinal()) - this.scope.problemReporter().cannotReferToNonFinalField(fieldReference.binding, fieldReference); - } - stmt.generateCode(this.scope, codeStream); // Initialize resources ... - } - } - } - - this.tryBlock.generateCode(this.scope, codeStream); - - if (resourceCount > 0) { - for (int i = resourceCount; i >= 0; i--) { - BranchLabel exitLabel = new BranchLabel(codeStream); - if (this.resourceExceptionLabels[i].getCount() % 2 != 0) { - this.resourceExceptionLabels[i].placeEnd(); // outer handler if any is the one that should catch exceptions out of close() - } - - Statement stmt = i > 0 ? this.resources[i - 1] : null; - if ((this.bits & ASTNode.IsTryBlockExiting) == 0) { - // inline resource closure - if (i > 0) { - int invokeCloseStartPc = codeStream.position; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=343785 - if (this.postTryInitStateIndex != -1) { - /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=361053, we are just past a synthetic instance of try-catch-finally. - Our initialization type state is the same as it was at the end of the just concluded try (catch rethrows) - */ - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.postTryInitStateIndex); - } - generateCodeSnippet(stmt, codeStream, exitLabel, false /* record */); - codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd); - } - codeStream.goto_(exitLabel); // skip over the catch block. - } - - if (i > 0) { - // i is off by one - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.postResourcesInitStateIndexes[i - 1]); - codeStream.addDefinitelyAssignedVariables(currentScope, this.postResourcesInitStateIndexes[i - 1]); - } else { - // For the first resource, its preset state is the preTryInitStateIndex - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); - } - - codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable()); - this.resourceExceptionLabels[i].place(); - if (i == resourceCount) { - // inner most try's catch/finally can be a lot simpler. - codeStream.store(this.primaryExceptionVariable, false); - // fall through, invoke close() and re-throw. - } else { - BranchLabel elseLabel = new BranchLabel(codeStream), postElseLabel = new BranchLabel(codeStream); - codeStream.store(this.caughtThrowableVariable, false); - codeStream.load(this.primaryExceptionVariable); - codeStream.ifnonnull(elseLabel); - codeStream.load(this.caughtThrowableVariable); - codeStream.store(this.primaryExceptionVariable, false); - codeStream.goto_(postElseLabel); - elseLabel.place(); - codeStream.load(this.primaryExceptionVariable); - codeStream.load(this.caughtThrowableVariable); - codeStream.if_acmpeq(postElseLabel); - codeStream.load(this.primaryExceptionVariable); - codeStream.load(this.caughtThrowableVariable); - codeStream.invokeThrowableAddSuppressed(); - postElseLabel.place(); - } - if (i > 0) { - // inline resource close here rather than bracketing the current catch block with a try region. - BranchLabel postCloseLabel = new BranchLabel(codeStream); - generateCodeSnippet(stmt, codeStream, postCloseLabel, true /* record */, i, codeStream.position); - postCloseLabel.place(); - } - codeStream.load(this.primaryExceptionVariable); - codeStream.athrow(); - exitLabel.place(); - } - codeStream.removeVariable(this.primaryExceptionVariable); - codeStream.removeVariable(this.caughtThrowableVariable); - } - } finally { - this.declaredExceptionLabels = null; - this.resourceExceptionLabels = null; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=375248 - } - boolean tryBlockHasSomeCode = codeStream.position != pc; - // flag telling if some bytecodes were issued inside the try block - - // place end positions of user-defined exception labels - if (tryBlockHasSomeCode) { - // natural exit may require subroutine invocation (if finally != null) - BranchLabel naturalExitLabel = new BranchLabel(codeStream); - BranchLabel postCatchesFinallyLabel = null; - boolean patternAccessorsMayThrow = codeStream.patternAccessorsMayThrow(this.tryBlock.scope); - if (!patternAccessorsMayThrow) { - for (int i = 0; i < maxCatches; i++) { - exceptionLabels[i].placeEnd(); - } - } - if ((this.bits & ASTNode.IsTryBlockExiting) == 0) { - int position = codeStream.position; - switch(finallyMode) { - case FINALLY_SUBROUTINE : - case FINALLY_INLINE : - requiresNaturalExit = true; - if (this.naturalExitMergeInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); - } - codeStream.goto_(naturalExitLabel); - break; - case NO_FINALLY : - if (this.naturalExitMergeInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); - } - codeStream.goto_(naturalExitLabel); - break; - case FINALLY_DOES_NOT_COMPLETE : - codeStream.goto_(this.subRoutineStartLabel); - break; - } - - codeStream.recordPositionsFrom(position, this.tryBlock.sourceEnd); - //goto is tagged as part of the try block - } - codeStream.handleRecordAccessorExceptions(this.tryBlock.scope); - if (patternAccessorsMayThrow) { - for (int i = 0; i < maxCatches; i++) { - exceptionLabels[i].placeEnd(); - } - } - /* generate sequence of handler, all starting by storing the TOS (exception - thrown) into their own catch variables, the one specified in the source - that must denote the handled exception. - */ - exitAnyExceptionHandler(); - if (this.catchArguments != null) { - postCatchesFinallyLabel = new BranchLabel(codeStream); - - for (int i = 0; i < maxCatches; i++) { - /* - * This should not happen. For consistency purpose, if the exception label is never used - * we also don't generate the corresponding catch block, otherwise we have some - * unreachable bytecodes - */ - if (exceptionLabels[i].getCount() == 0) continue; - enterAnyExceptionHandler(codeStream); - // May loose some local variable initializations : affecting the local variable attributes - if (this.preTryInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); - } - codeStream.pushExceptionOnStack(exceptionLabels[i].exceptionType); - exceptionLabels[i].place(); - // optimizing the case where the exception variable is not actually used - LocalVariableBinding catchVar; - int varPC = codeStream.position; - if ((catchVar = this.catchArguments[i].binding).resolvedPosition != -1) { - codeStream.store(catchVar, false); - catchVar.recordInitializationStartPC(codeStream.position); - codeStream.addVisibleLocalVariable(catchVar); - } else { - codeStream.pop(); - } - codeStream.recordPositionsFrom(varPC, this.catchArguments[i].sourceStart); - // Keep track of the pcs at diverging point for computing the local attribute - // since not passing the catchScope, the block generation will exitUserScope(catchScope) - this.catchBlocks[i].generateCode(this.scope, codeStream); - exitAnyExceptionHandler(); - if (!this.catchExits[i]) { - switch(finallyMode) { - case FINALLY_INLINE : - // inlined finally here can see all merged variables - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex); - } - if (this.catchExitInitStateIndexes[i] != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.catchExitInitStateIndexes[i]); - codeStream.addDefinitelyAssignedVariables(currentScope, this.catchExitInitStateIndexes[i]); - } - // entire sequence for finally is associated to finally block - this.finallyBlock.generateCode(this.scope, codeStream); - codeStream.goto_(postCatchesFinallyLabel); - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).popStateIndex(); - } - break; - case FINALLY_SUBROUTINE : - requiresNaturalExit = true; - //$FALL-THROUGH$ - case NO_FINALLY : - if (this.naturalExitMergeInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); - } - codeStream.goto_(naturalExitLabel); - break; - case FINALLY_DOES_NOT_COMPLETE : - codeStream.goto_(this.subRoutineStartLabel); - break; - } - } - } - } - // extra handler for trailing natural exit (will be fixed up later on when natural exit is generated below) - ExceptionLabel naturalExitExceptionHandler = requiresNaturalExit && (finallyMode == FINALLY_SUBROUTINE) - ? new ExceptionLabel(codeStream, null) - : null; - - // addition of a special handler so as to ensure that any uncaught exception (or exception thrown - // inside catch blocks) will run the finally block - int finallySequenceStartPC = codeStream.position; - if (this.subRoutineStartLabel != null && this.anyExceptionLabel.getCount() != 0) { - codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable()); - if (this.preTryInitStateIndex != -1) { - // reset initialization state, as for a normal catch block - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); - } - placeAllAnyExceptionHandler(); - if (naturalExitExceptionHandler != null) naturalExitExceptionHandler.place(); - - switch(finallyMode) { - case FINALLY_SUBROUTINE : - // any exception handler - codeStream.store(this.anyExceptionVariable, false); - codeStream.jsr(this.subRoutineStartLabel); - codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart); - int position = codeStream.position; - codeStream.throwAnyException(this.anyExceptionVariable); - codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd); - // subroutine - this.subRoutineStartLabel.place(); - codeStream.pushExceptionOnStack(this.scope.getJavaLangThrowable()); - position = codeStream.position; - codeStream.store(this.returnAddressVariable, false); - codeStream.recordPositionsFrom(position, this.finallyBlock.sourceStart); - this.finallyBlock.generateCode(this.scope, codeStream); - position = codeStream.position; - codeStream.ret(this.returnAddressVariable.resolvedPosition); - codeStream.recordPositionsFrom( - position, - this.finallyBlock.sourceEnd); - // the ret bytecode is part of the subroutine - break; - case FINALLY_INLINE : - // any exception handler - codeStream.store(this.anyExceptionVariable, false); - codeStream.addVariable(this.anyExceptionVariable); - codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart); - // subroutine - this.finallyBlock.generateCode(currentScope, codeStream); - position = codeStream.position; - codeStream.throwAnyException(this.anyExceptionVariable); - codeStream.removeVariable(this.anyExceptionVariable); - if (this.preTryInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preTryInitStateIndex); - } - this.subRoutineStartLabel.place(); - codeStream.recordPositionsFrom(position, this.finallyBlock.sourceEnd); - break; - case FINALLY_DOES_NOT_COMPLETE : - // any exception handler - codeStream.pop(); - this.subRoutineStartLabel.place(); - codeStream.recordPositionsFrom(finallySequenceStartPC, this.finallyBlock.sourceStart); - // subroutine - this.finallyBlock.generateCode(this.scope, codeStream); - break; - } - - // will naturally fall into subsequent code after subroutine invocation - if (requiresNaturalExit) { - switch(finallyMode) { - case FINALLY_SUBROUTINE : - naturalExitLabel.place(); - int position = codeStream.position; - naturalExitExceptionHandler.placeStart(); - codeStream.jsr(this.subRoutineStartLabel); - naturalExitExceptionHandler.placeEnd(); - codeStream.recordPositionsFrom( - position, - this.finallyBlock.sourceEnd); - break; - case FINALLY_INLINE : - // inlined finally here can see all merged variables - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).pushStateIndex(this.naturalExitMergeInitStateIndex); - } - if (this.naturalExitMergeInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.naturalExitMergeInitStateIndex); - } - naturalExitLabel.place(); - // entire sequence for finally is associated to finally block - this.finallyBlock.generateCode(this.scope, codeStream); - if (postCatchesFinallyLabel != null) { - position = codeStream.position; - // entire sequence for finally is associated to finally block - codeStream.goto_(postCatchesFinallyLabel); - codeStream.recordPositionsFrom( - position, - this.finallyBlock.sourceEnd); - } - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).popStateIndex(); - } - break; - case FINALLY_DOES_NOT_COMPLETE : - break; - default : - naturalExitLabel.place(); - break; - } - } - if (postCatchesFinallyLabel != null) { - postCatchesFinallyLabel.place(); - } - } else { - // no subroutine, simply position end label (natural exit == end) - naturalExitLabel.place(); - } - } else { - // try block had no effect, only generate the body of the finally block if any - if (this.subRoutineStartLabel != null) { - this.finallyBlock.generateCode(this.scope, codeStream); - } - } - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); -} -private void generateCodeSnippet(Statement statement, CodeStream codeStream, BranchLabel postCloseLabel, boolean record, int... values) { - - int i = -1; - int invokeCloseStartPc = -1; - if (record) { - i = values[0]; - invokeCloseStartPc = values[1]; - } - if (statement instanceof LocalDeclaration) - generateCodeSnippet((LocalDeclaration)statement, codeStream, postCloseLabel, record, i, invokeCloseStartPc); - else if (statement instanceof Reference) - generateCodeSnippet((Reference)statement, codeStream, postCloseLabel, record, i, invokeCloseStartPc); - // else abort -} - -private void generateCodeSnippet(Reference reference, CodeStream codeStream, BranchLabel postCloseLabel, boolean record, int i, int invokeCloseStartPc) { - reference.generateCode(this.scope, codeStream, true); - codeStream.ifnull(postCloseLabel); - reference.generateCode(this.scope, codeStream, true); - codeStream.invokeAutoCloseableClose(reference.resolvedType); - if (!record) return; - codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd); - isDuplicateResourceReference(i); -} -private void generateCodeSnippet(LocalDeclaration localDeclaration, CodeStream codeStream, BranchLabel postCloseLabel, boolean record, int i, int invokeCloseStartPc) { - LocalVariableBinding variableBinding = localDeclaration.binding; - codeStream.load(variableBinding); - codeStream.ifnull(postCloseLabel); - codeStream.load(variableBinding); - codeStream.invokeAutoCloseableClose(variableBinding.type); - if (!record) return; - codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd); - if (!isDuplicateResourceReference(i)) // do not remove duplicate variable now - codeStream.removeVariable(variableBinding); -} - -private boolean isDuplicateResourceReference(int index) { - int len = this.resources.length; - if (index < len && this.resources[index] instanceof Reference) { - Reference ref = (Reference) this.resources[index]; - Binding refBinding = ref instanceof NameReference ? ((NameReference) ref).binding : - ref instanceof FieldReference ? ((FieldReference) ref).binding : null; - if (refBinding == null) return false; - - //TODO: For field accesses in the form of a.b.c and b.c - could there be a non-trivial dup - to check? - for (int i = 0; i < index; i++) { - Statement stmt = this.resources[i]; - Binding b = stmt instanceof LocalDeclaration ? ((LocalDeclaration) stmt).binding : - stmt instanceof NameReference ? ((NameReference) stmt).binding : - stmt instanceof FieldReference ? ((FieldReference) stmt).binding : null; - if (b == refBinding) { - this.scope.problemReporter().duplicateResourceReference(ref); - return true; - } - } - } - return false; -} - -/** - * @see SubRoutineStatement#generateSubRoutineInvocation(BlockScope, CodeStream, Object, int, LocalVariableBinding) - */ -@Override -public boolean generateSubRoutineInvocation(BlockScope currentScope, CodeStream codeStream, Object targetLocation, int stateIndex, LocalVariableBinding secretLocal) { - - int resourceCount = this.resources.length; - if (resourceCount > 0 && this.resourceExceptionLabels != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=375248 - for (int i = resourceCount; i > 0; --i) { - // Disarm the handlers and take care of resource closure. - this.resourceExceptionLabels[i].placeEnd(); - BranchLabel exitLabel = new BranchLabel(codeStream); - int invokeCloseStartPc = codeStream.position; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=343785 - generateCodeSnippet(this.resources[i - 1], codeStream, exitLabel, false); - codeStream.recordPositionsFrom(invokeCloseStartPc, this.tryBlock.sourceEnd); - exitLabel.place(); - } - this.resourceExceptionLabels[0].placeEnd(); // outermost should end here as well, will start again on enter - } - - boolean isStackMapFrameCodeStream = codeStream instanceof StackMapFrameCodeStream; - int finallyMode = finallyMode(); - switch(finallyMode) { - case FINALLY_DOES_NOT_COMPLETE : - if (this.switchExpression != null) { - exitAnyExceptionHandler(); - exitDeclaredExceptionHandlers(codeStream); - this.finallyBlock.generateCode(currentScope, codeStream); - return true; - } - codeStream.goto_(this.subRoutineStartLabel); - return true; - - case NO_FINALLY : - exitDeclaredExceptionHandlers(codeStream); - return false; - } - // optimize subroutine invocation sequences, using the targetLocation (if any) - CompilerOptions options = this.scope.compilerOptions(); - if (options.shareCommonFinallyBlocks && targetLocation != null) { - boolean reuseTargetLocation = true; - if (this.reusableJSRTargetsCount > 0) { - nextReusableTarget: for (int i = 0, count = this.reusableJSRTargetsCount; i < count; i++) { - Object reusableJSRTarget = this.reusableJSRTargets[i]; - differentTarget: { - if (targetLocation == reusableJSRTarget) - break differentTarget; - if (targetLocation instanceof Constant - && reusableJSRTarget instanceof Constant - && ((Constant)targetLocation).hasSameValue((Constant) reusableJSRTarget)) { - break differentTarget; - } - // cannot reuse current target - continue nextReusableTarget; - } - // current target has been used in the past, simply branch to its label - if ((this.reusableJSRStateIndexes[i] != stateIndex) && finallyMode == FINALLY_INLINE) { - reuseTargetLocation = false; - break nextReusableTarget; - } else { - codeStream.goto_(this.reusableJSRSequenceStartLabels[i]); - return true; - } - } - } else { - this.reusableJSRTargets = new Object[3]; - this.reusableJSRSequenceStartLabels = new BranchLabel[3]; - this.reusableJSRStateIndexes = new int[3]; - } - if (reuseTargetLocation) { - if (this.reusableJSRTargetsCount == this.reusableJSRTargets.length) { - System.arraycopy(this.reusableJSRTargets, 0, this.reusableJSRTargets = new Object[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); - System.arraycopy(this.reusableJSRSequenceStartLabels, 0, this.reusableJSRSequenceStartLabels = new BranchLabel[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); - System.arraycopy(this.reusableJSRStateIndexes, 0, this.reusableJSRStateIndexes = new int[2*this.reusableJSRTargetsCount], 0, this.reusableJSRTargetsCount); - } - this.reusableJSRTargets[this.reusableJSRTargetsCount] = targetLocation; - BranchLabel reusableJSRSequenceStartLabel = new BranchLabel(codeStream); - reusableJSRSequenceStartLabel.place(); - this.reusableJSRStateIndexes[this.reusableJSRTargetsCount] = stateIndex; - this.reusableJSRSequenceStartLabels[this.reusableJSRTargetsCount++] = reusableJSRSequenceStartLabel; - } - } - if (finallyMode == FINALLY_INLINE) { - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).pushStateIndex(stateIndex); - } - // cannot use jsr bytecode, then simply inline the subroutine - // inside try block, ensure to deactivate all catch block exception handlers while inlining finally block - exitAnyExceptionHandler(); - exitDeclaredExceptionHandlers(codeStream); - this.finallyBlock.generateCode(currentScope, codeStream); - if (isStackMapFrameCodeStream) { - ((StackMapFrameCodeStream) codeStream).popStateIndex(); - } - } else { - // classic subroutine invocation, distinguish case of non-returning subroutine - codeStream.jsr(this.subRoutineStartLabel); - exitAnyExceptionHandler(); - exitDeclaredExceptionHandlers(codeStream); - } - return false; -} -@Override -public boolean isSubRoutineEscaping() { - return (this.bits & ASTNode.IsSubRoutineEscaping) != 0; -} - -@Override -public StringBuilder printStatement(int indent, StringBuilder output) { - int length = this.resources.length; - printIndent(indent, output).append("try" + (length == 0 ? "\n" : " (")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - for (int i = 0; i < length; i++) { - Statement stmt = this.resources[i]; - if (stmt instanceof LocalDeclaration) { - ((LocalDeclaration) stmt).printAsExpression(0, output); - } else if (stmt instanceof Reference) { - ((Reference) stmt).printExpression(0, output); - } else continue; - if (i != length - 1) { - output.append(";\n"); //$NON-NLS-1$ - printIndent(indent + 2, output); - } - } - if (length > 0) { - output.append(")\n"); //$NON-NLS-1$ - } - this.tryBlock.printStatement(indent + 1, output); - - //catches - if (this.catchBlocks != null) - for (int i = 0; i < this.catchBlocks.length; i++) { - output.append('\n'); - printIndent(indent, output).append("catch ("); //$NON-NLS-1$ - this.catchArguments[i].print(0, output).append(")\n"); //$NON-NLS-1$ - this.catchBlocks[i].printStatement(indent + 1, output); - } - //finally - if (this.finallyBlock != null) { - output.append('\n'); - printIndent(indent, output).append("finally\n"); //$NON-NLS-1$ - this.finallyBlock.printStatement(indent + 1, output); - } - return output; -} - -@Override -public void resolve(BlockScope upperScope) { - // special scope for secret locals optimization. - this.scope = new BlockScope(upperScope); - - BlockScope finallyScope = null; - BlockScope resourceManagementScope = null; // Single scope to hold all resources and additional secret variables. - int resourceCount = this.resources.length; - if (resourceCount > 0) { - resourceManagementScope = new BlockScope(this.scope); - this.primaryExceptionVariable = - new LocalVariableBinding(TryStatement.SECRET_PRIMARY_EXCEPTION_VARIABLE_NAME, this.scope.getJavaLangThrowable(), ClassFileConstants.AccDefault, false); - resourceManagementScope.addLocalVariable(this.primaryExceptionVariable); - this.primaryExceptionVariable.setConstant(Constant.NotAConstant); // not inlinable - this.caughtThrowableVariable = - new LocalVariableBinding(TryStatement.SECRET_CAUGHT_THROWABLE_VARIABLE_NAME, this.scope.getJavaLangThrowable(), ClassFileConstants.AccDefault, false); - resourceManagementScope.addLocalVariable(this.caughtThrowableVariable); - this.caughtThrowableVariable.setConstant(Constant.NotAConstant); // not inlinable - } - for (int i = 0; i < resourceCount; i++) { - this.resources[i].resolve(resourceManagementScope); - if (this.resources[i] instanceof LocalDeclaration) { - LocalDeclaration node = (LocalDeclaration)this.resources[i]; - LocalVariableBinding localVariableBinding = node.binding; - if (localVariableBinding != null && localVariableBinding.isValidBinding()) { - localVariableBinding.modifiers |= ClassFileConstants.AccFinal; - localVariableBinding.tagBits |= TagBits.IsResource; - TypeBinding resourceType = localVariableBinding.type; - if (resourceType instanceof ReferenceBinding) { - if (resourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangAutoCloseable, false /*AutoCloseable is not a class*/) == null && resourceType.isValidBinding()) { - upperScope.problemReporter().resourceHasToImplementAutoCloseable(resourceType, node.type); - localVariableBinding.type = new ProblemReferenceBinding(CharOperation.splitOn('.', resourceType.shortReadableName()), null, ProblemReasons.InvalidTypeForAutoManagedResource); - } - } else if (resourceType != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=349862, avoid secondary error in problematic null case - upperScope.problemReporter().resourceHasToImplementAutoCloseable(resourceType, node.type); - localVariableBinding.type = new ProblemReferenceBinding(CharOperation.splitOn('.', resourceType.shortReadableName()), null, ProblemReasons.InvalidTypeForAutoManagedResource); - } - } - } else { // expression - Expression node = (Expression) this.resources[i]; - TypeBinding resourceType = node.resolvedType; - if (resourceType instanceof ReferenceBinding) { - if (resourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangAutoCloseable, false /*AutoCloseable is not a class*/) == null && resourceType.isValidBinding()) { - upperScope.problemReporter().resourceHasToImplementAutoCloseable(resourceType, node); - ((Expression) this.resources[i]).resolvedType = new ProblemReferenceBinding(CharOperation.splitOn('.', resourceType.shortReadableName()), null, ProblemReasons.InvalidTypeForAutoManagedResource); - } - } else if (resourceType != null) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=349862, avoid secondary error in problematic null case - upperScope.problemReporter().resourceHasToImplementAutoCloseable(resourceType, node); - ((Expression) this.resources[i]).resolvedType = new ProblemReferenceBinding(CharOperation.splitOn('.', resourceType.shortReadableName()), null, ProblemReasons.InvalidTypeForAutoManagedResource); - } - } - } - BlockScope tryScope = new BlockScope(resourceManagementScope != null ? resourceManagementScope : this.scope); - - if (this.finallyBlock != null) { - if (this.finallyBlock.isEmptyBlock()) { - if ((this.finallyBlock.bits & ASTNode.UndocumentedEmptyBlock) != 0) { - this.scope.problemReporter().undocumentedEmptyBlock(this.finallyBlock.sourceStart, this.finallyBlock.sourceEnd); - } - } else { - finallyScope = new BlockScope(this.scope, false); // don't add it yet to parent scope - - // provision for returning and forcing the finally block to run - MethodScope methodScope = this.scope.methodScope(); - - // the type does not matter as long as it is not a base type - if (!upperScope.compilerOptions().inlineJsrBytecode) { - this.returnAddressVariable = - new LocalVariableBinding(TryStatement.SECRET_RETURN_ADDRESS_NAME, upperScope.getJavaLangObject(), ClassFileConstants.AccDefault, false); - finallyScope.addLocalVariable(this.returnAddressVariable); - this.returnAddressVariable.setConstant(Constant.NotAConstant); // not inlinable - } - this.subRoutineStartLabel = new BranchLabel(); - - this.anyExceptionVariable = - new LocalVariableBinding(TryStatement.SECRET_ANY_HANDLER_NAME, this.scope.getJavaLangThrowable(), ClassFileConstants.AccDefault, false); - finallyScope.addLocalVariable(this.anyExceptionVariable); - this.anyExceptionVariable.setConstant(Constant.NotAConstant); // not inlinable - - if (!methodScope.isInsideInitializer()) { - MethodBinding methodBinding = methodScope.referenceContext instanceof AbstractMethodDeclaration ? - ((AbstractMethodDeclaration) methodScope.referenceContext).binding : (methodScope.referenceContext instanceof LambdaExpression ? - ((LambdaExpression)methodScope.referenceContext).binding : null); - if (methodBinding != null) { - TypeBinding methodReturnType = methodBinding.returnType; - if (methodReturnType.id != TypeIds.T_void) { - this.secretReturnValue = - new LocalVariableBinding( - TryStatement.SECRET_RETURN_VALUE_NAME, - methodReturnType, - ClassFileConstants.AccDefault, - false); - finallyScope.addLocalVariable(this.secretReturnValue); - this.secretReturnValue.setConstant(Constant.NotAConstant); // not inlinable - } - } - } - this.finallyBlock.resolveUsing(finallyScope); - // force the finally scope to have variable positions shifted after its try scope and catch ones - int shiftScopesLength = this.catchArguments == null ? 1 : this.catchArguments.length + 1; - finallyScope.shiftScopes = new BlockScope[shiftScopesLength]; - finallyScope.shiftScopes[0] = tryScope; - } - } - this.tryBlock.resolveUsing(tryScope); - - // arguments type are checked against JavaLangThrowable in resolveForCatch(..) - if (this.catchBlocks != null) { - int length = this.catchArguments.length; - TypeBinding[] argumentTypes = new TypeBinding[length]; - boolean containsUnionTypes = false; - boolean catchHasError = false; - for (int i = 0; i < length; i++) { - BlockScope catchScope = new BlockScope(this.scope); - if (finallyScope != null){ - finallyScope.shiftScopes[i+1] = catchScope; - } - // side effect on catchScope in resolveForCatch(..) - Argument catchArgument = this.catchArguments[i]; - containsUnionTypes |= (catchArgument.type.bits & ASTNode.IsUnionType) != 0; - if ((argumentTypes[i] = catchArgument.resolveForCatch(catchScope)) == null) { - catchHasError = true; - } - this.catchBlocks[i].resolveUsing(catchScope); - } - if (catchHasError) { - return; - } - // Verify that the catch clause are ordered in the right way: - // more specialized first. - verifyDuplicationAndOrder(length, argumentTypes, containsUnionTypes); - } else { - this.caughtExceptionTypes = new ReferenceBinding[0]; - } - - if (finallyScope != null){ - // add finallyScope as last subscope, so it can be shifted behind try/catch subscopes. - // the shifting is necessary to achieve no overlay in between the finally scope and its - // sibling in term of local variable positions. - this.scope.addSubscope(finallyScope); - } -} -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - if (visitor.visit(this, blockScope)) { - Statement[] statements = this.resources; - for (int i = 0, max = statements.length; i < max; i++) { - statements[i].traverse(visitor, this.scope); - } - this.tryBlock.traverse(visitor, this.scope); - if (this.catchArguments != null) { - for (int i = 0, max = this.catchBlocks.length; i < max; i++) { - this.catchArguments[i].traverse(visitor, this.scope); - this.catchBlocks[i].traverse(visitor, this.scope); - } - } - if (this.finallyBlock != null) - this.finallyBlock.traverse(visitor, this.scope); - } - visitor.endVisit(this, blockScope); -} -protected void verifyDuplicationAndOrder(int length, TypeBinding[] argumentTypes, boolean containsUnionTypes) { - // Verify that the catch clause are ordered in the right way: - // more specialized first. - if (containsUnionTypes) { - int totalCount = 0; - ReferenceBinding[][] allExceptionTypes = new ReferenceBinding[length][]; - for (int i = 0; i < length; i++) { - if (argumentTypes[i] instanceof ArrayBinding) - continue; - ReferenceBinding currentExceptionType = (ReferenceBinding) argumentTypes[i]; - TypeReference catchArgumentType = this.catchArguments[i].type; - if ((catchArgumentType.bits & ASTNode.IsUnionType) != 0) { - TypeReference[] typeReferences = ((UnionTypeReference) catchArgumentType).typeReferences; - int typeReferencesLength = typeReferences.length; - ReferenceBinding[] unionExceptionTypes = new ReferenceBinding[typeReferencesLength]; - for (int j = 0; j < typeReferencesLength; j++) { - unionExceptionTypes[j] = (ReferenceBinding) typeReferences[j].resolvedType; - } - totalCount += typeReferencesLength; - allExceptionTypes[i] = unionExceptionTypes; - } else { - allExceptionTypes[i] = new ReferenceBinding[] { currentExceptionType }; - totalCount++; - } - } - this.caughtExceptionTypes = new ReferenceBinding[totalCount]; - this.caughtExceptionsCatchBlocks = new int[totalCount]; - for (int i = 0, l = 0; i < length; i++) { - ReferenceBinding[] currentExceptions = allExceptionTypes[i]; - if (currentExceptions == null) continue; - loop: for (int j = 0, max = currentExceptions.length; j < max; j++) { - ReferenceBinding exception = currentExceptions[j]; - this.caughtExceptionTypes[l] = exception; - this.caughtExceptionsCatchBlocks[l++] = i; - // now iterate over all previous exceptions - for (int k = 0; k < i; k++) { - ReferenceBinding[] exceptions = allExceptionTypes[k]; - if (exceptions == null) continue; - for (int n = 0, max2 = exceptions.length; n < max2; n++) { - ReferenceBinding currentException = exceptions[n]; - if (exception.isCompatibleWith(currentException)) { - TypeReference catchArgumentType = this.catchArguments[i].type; - if ((catchArgumentType.bits & ASTNode.IsUnionType) != 0) { - catchArgumentType = ((UnionTypeReference) catchArgumentType).typeReferences[j]; - } - this.scope.problemReporter().wrongSequenceOfExceptionTypesError( - catchArgumentType, - exception, - currentException); - break loop; - } - } - } - } - } - } else { - this.caughtExceptionTypes = new ReferenceBinding[length]; - for (int i = 0; i < length; i++) { - if (argumentTypes[i] instanceof ArrayBinding) - continue; - this.caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i]; - for (int j = 0; j < i; j++) { - if (this.caughtExceptionTypes[i].isCompatibleWith(argumentTypes[j])) { - this.scope.problemReporter().wrongSequenceOfExceptionTypesError( - this.catchArguments[i].type, - this.caughtExceptionTypes[i], - argumentTypes[j]); - } - } - } - } -} -@Override -public boolean doesNotCompleteNormally() { - if (!this.tryBlock.doesNotCompleteNormally()) { - return (this.finallyBlock != null) ? this.finallyBlock.doesNotCompleteNormally() : false; - } - if (this.catchBlocks != null) { - for (int i = 0; i < this.catchBlocks.length; i++) { - if (!this.catchBlocks[i].doesNotCompleteNormally()) { - return (this.finallyBlock != null) ? this.finallyBlock.doesNotCompleteNormally() : false; - } - } - } - return true; -} -@Override -public boolean completesByContinue() { - if (this.tryBlock.completesByContinue()) { - return (this.finallyBlock == null) ? true : - !this.finallyBlock.doesNotCompleteNormally() || this.finallyBlock.completesByContinue(); - } - if (this.catchBlocks != null) { - for (int i = 0; i < this.catchBlocks.length; i++) { - if (this.catchBlocks[i].completesByContinue()) { - return (this.finallyBlock == null) ? true : - !this.finallyBlock.doesNotCompleteNormally() || this.finallyBlock.completesByContinue(); - } - } - } - return this.finallyBlock != null && this.finallyBlock.completesByContinue(); -} -@Override -public boolean canCompleteNormally() { - if (this.tryBlock.canCompleteNormally()) { - return (this.finallyBlock != null) ? this.finallyBlock.canCompleteNormally() : true; - } - if (this.catchBlocks != null) { - for (int i = 0; i < this.catchBlocks.length; i++) { - if (this.catchBlocks[i].canCompleteNormally()) { - return (this.finallyBlock != null) ? this.finallyBlock.canCompleteNormally() : true; - } - } - } - return false; -} -@Override -public boolean continueCompletes() { - if (this.tryBlock.continueCompletes()) { - return (this.finallyBlock == null) ? true : - this.finallyBlock.canCompleteNormally() || this.finallyBlock.continueCompletes(); - } - if (this.catchBlocks != null) { - for (int i = 0; i < this.catchBlocks.length; i++) { - if (this.catchBlocks[i].continueCompletes()) { - return (this.finallyBlock == null) ? true : - this.finallyBlock.canCompleteNormally() || this.finallyBlock.continueCompletes(); - } - } - } - return this.finallyBlock != null && this.finallyBlock.continueCompletes(); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java deleted file mode 100644 index 255f683..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypeDeclaration.java +++ /dev/null @@ -1,1956 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * Bug 360328 - [compiler][null] detect null problems in nested code (local class inside a loop) - * Bug 388630 - @NonNull diagnostics at line 0 - * Bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * Bug 416176 - [1.8][compiler][null] null type annotations cause grief on type variables - * Bug 424727 - [compiler][null] NullPointerException in nullAnnotationUnsupportedLocation(ProblemReporter.java:5708) - * Bug 457210 - [1.8][compiler][null] Wrong Nullness errors given on full build build but not on incremental build? - * Keigo Imai - Contribution for bug 388903 - Cannot extend inner class as an anonymous class when it extends the outer class - * Pierre-Yves B. - Contributions for - * Bug 542520 - [JUnit 5] Warning The method xxx from the type X is never used locally is shown when using MethodSource - * Bug 546084 - Using Junit 5s MethodSource leads to ClassCastException - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import org.eclipse.jdt.core.compiler.*; -import org.eclipse.jdt.internal.compiler.*; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; -import org.eclipse.jdt.internal.compiler.parser.*; -import org.eclipse.jdt.internal.compiler.problem.*; -import org.eclipse.jdt.internal.compiler.util.SimpleSetOfCharArray; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class TypeDeclaration extends Statement implements ProblemSeverities, ReferenceContext { - // Type decl kinds - public static final int CLASS_DECL = 1; - public static final int INTERFACE_DECL = 2; - public static final int ENUM_DECL = 3; - public static final int ANNOTATION_TYPE_DECL = 4; - /* - * @noreference This field is not intended to be referenced by clients as it is a part of Java preview feature. - */ - public static final int RECORD_DECL = 5; - - public int modifiers = ClassFileConstants.AccDefault; - public int modifiersSourceStart; - public int functionalExpressionsCount = 0; - public Annotation[] annotations; - public char[] name; - public TypeReference superclass; - public TypeReference[] superInterfaces; - public FieldDeclaration[] fields; - public AbstractMethodDeclaration[] methods; - public TypeDeclaration[] memberTypes; - public SourceTypeBinding binding; - public ClassScope scope; - public MethodScope initializerScope; - public MethodScope staticInitializerScope; - public boolean ignoreFurtherInvestigation = false; - public int maxFieldCount; - public int declarationSourceStart; - public int declarationSourceEnd; - public int restrictedIdentifierStart = -1; // used only for record and permits restricted keywords. - public int bodyStart; - public int bodyEnd; // doesn't include the trailing comment if any. - public CompilationResult compilationResult; - public MethodDeclaration[] missingAbstractMethods; - public Javadoc javadoc; - - public QualifiedAllocationExpression allocation; // for anonymous only - public TypeDeclaration enclosingType; // for member types only - - public FieldBinding enumValuesSyntheticfield; // for enum - public int enumConstantsCounter; - - // 1.5 support - public TypeParameter[] typeParameters; - - // 14 Records preview support - public RecordComponent[] recordComponents; - public int nRecordComponents; - public static Set disallowedComponentNames; - - // 15 Sealed Type preview support - public TypeReference[] permittedTypes; - - static { - disallowedComponentNames = new HashSet<>(6); - disallowedComponentNames.add("clone"); //$NON-NLS-1$ - disallowedComponentNames.add("finalize"); //$NON-NLS-1$ - disallowedComponentNames.add("getClass"); //$NON-NLS-1$ - disallowedComponentNames.add("hashCode"); //$NON-NLS-1$ - disallowedComponentNames.add("notify"); //$NON-NLS-1$ - disallowedComponentNames.add("notifyAll");//$NON-NLS-1$ - disallowedComponentNames.add("toString"); //$NON-NLS-1$ - disallowedComponentNames.add("wait"); //$NON-NLS-1$ - } - -public TypeDeclaration(CompilationResult compilationResult){ - this.compilationResult = compilationResult; -} - -/* - * We cause the compilation task to abort to a given extent. - */ -@Override -public void abort(int abortLevel, CategorizedProblem problem) { - switch (abortLevel) { - case AbortCompilation : - throw new AbortCompilation(this.compilationResult, problem); - case AbortCompilationUnit : - throw new AbortCompilationUnit(this.compilationResult, problem); - case AbortMethod : - throw new AbortMethod(this.compilationResult, problem); - default : - throw new AbortType(this.compilationResult, problem); - } -} - -/** - * This method is responsible for adding a {@code } method declaration to the type method collections. - * Note that this implementation is inserting it in first place (as VAJ or javac), and that this - * impacts the behavior of the method ConstantPool.resetForClinit(int. int), in so far as - * the latter will have to reset the constant pool state accordingly (if it was added first, it does - * not need to preserve some of the method specific cached entries since this will be the first method). - * inserts the clinit method declaration in the first position. - * - * @see org.eclipse.jdt.internal.compiler.codegen.ConstantPool#resetForClinit(int, int) - */ -public final void addClinit() { - //see comment on needClassInitMethod - if (needClassInitMethod()) { - int length; - AbstractMethodDeclaration[] methodDeclarations; - if ((methodDeclarations = this.methods) == null) { - length = 0; - methodDeclarations = new AbstractMethodDeclaration[1]; - } else { - length = methodDeclarations.length; - System.arraycopy( - methodDeclarations, - 0, - (methodDeclarations = new AbstractMethodDeclaration[length + 1]), - 1, - length); - } - Clinit clinit = new Clinit(this.compilationResult); - methodDeclarations[0] = clinit; - // clinit is added in first location, so as to minimize the use of ldcw (big consumer of constant inits) - clinit.declarationSourceStart = clinit.sourceStart = this.sourceStart; - clinit.declarationSourceEnd = clinit.sourceEnd = this.sourceEnd; - clinit.bodyEnd = this.sourceEnd; - this.methods = methodDeclarations; - } -} - -/* - * INTERNAL USE ONLY - Creates a fake method declaration for the corresponding binding. - * It is used to report errors for missing abstract methods. - */ -public MethodDeclaration addMissingAbstractMethodFor(MethodBinding methodBinding) { - TypeBinding[] argumentTypes = methodBinding.parameters; - int argumentsLength = argumentTypes.length; - //the constructor - MethodDeclaration methodDeclaration = new MethodDeclaration(this.compilationResult); - methodDeclaration.selector = methodBinding.selector; - methodDeclaration.sourceStart = this.sourceStart; - methodDeclaration.sourceEnd = this.sourceEnd; - methodDeclaration.modifiers = methodBinding.getAccessFlags() & ~ClassFileConstants.AccAbstract; - - if (argumentsLength > 0) { - String baseName = "arg";//$NON-NLS-1$ - Argument[] arguments = (methodDeclaration.arguments = new Argument[argumentsLength]); - for (int i = argumentsLength; --i >= 0;) { - arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, ClassFileConstants.AccDefault); - } - } - - //adding the constructor in the methods list - if (this.missingAbstractMethods == null) { - this.missingAbstractMethods = new MethodDeclaration[] { methodDeclaration }; - } else { - MethodDeclaration[] newMethods; - System.arraycopy( - this.missingAbstractMethods, - 0, - newMethods = new MethodDeclaration[this.missingAbstractMethods.length + 1], - 1, - this.missingAbstractMethods.length); - newMethods[0] = methodDeclaration; - this.missingAbstractMethods = newMethods; - } - - //============BINDING UPDATE========================== - methodDeclaration.binding = new MethodBinding( - methodDeclaration.modifiers | ClassFileConstants.AccSynthetic, //methodDeclaration - methodBinding.selector, - methodBinding.returnType, - argumentsLength == 0 ? Binding.NO_PARAMETERS : argumentTypes, //arguments bindings - methodBinding.thrownExceptions, //exceptions - this.binding); //declaringClass - - methodDeclaration.scope = new MethodScope(this.scope, methodDeclaration, true); - methodDeclaration.bindArguments(); - -/* if (binding.methods == null) { - binding.methods = new MethodBinding[] { methodDeclaration.binding }; - } else { - MethodBinding[] newMethods; - System.arraycopy( - binding.methods, - 0, - newMethods = new MethodBinding[binding.methods.length + 1], - 1, - binding.methods.length); - newMethods[0] = methodDeclaration.binding; - binding.methods = newMethods; - }*/ - //=================================================== - - return methodDeclaration; -} - -/** - * Flow analysis for a local innertype - */ -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - if (this.ignoreFurtherInvestigation) - return flowInfo; - try { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - this.bits |= ASTNode.IsReachable; - LocalTypeBinding localType = (LocalTypeBinding) this.binding; - localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType)); - } - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - updateMaxFieldCount(); // propagate down the max field count - internalAnalyseCode(flowContext, flowInfo); - } catch (AbortType e) { - this.ignoreFurtherInvestigation = true; - } - return flowInfo; -} - -/** - * Flow analysis for a member innertype - */ -public void analyseCode(ClassScope enclosingClassScope) { - if (this.ignoreFurtherInvestigation) - return; - try { - // propagate down the max field count - updateMaxFieldCount(); - internalAnalyseCode(null, FlowInfo.initial(this.maxFieldCount)); - } catch (AbortType e) { - this.ignoreFurtherInvestigation = true; - } -} - -/** - * Flow analysis for a local member innertype - */ -public void analyseCode(ClassScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - if (this.ignoreFurtherInvestigation) - return; - try { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - this.bits |= ASTNode.IsReachable; - LocalTypeBinding localType = (LocalTypeBinding) this.binding; - localType.setConstantPoolName(currentScope.compilationUnitScope().computeConstantPoolName(localType)); - } - manageEnclosingInstanceAccessIfNecessary(currentScope, flowInfo); - updateMaxFieldCount(); // propagate down the max field count - internalAnalyseCode(flowContext, flowInfo); - } catch (AbortType e) { - this.ignoreFurtherInvestigation = true; - } -} - -/** - * Flow analysis for a package member type - */ -public void analyseCode(CompilationUnitScope unitScope) { - if (this.ignoreFurtherInvestigation) - return; - try { - internalAnalyseCode(null, FlowInfo.initial(this.maxFieldCount)); - } catch (AbortType e) { - this.ignoreFurtherInvestigation = true; - } -} - -/** - * Check for constructor vs. method with no return type. - * Answers true if at least one constructor is defined - */ -public boolean checkConstructors(Parser parser) { - //if a constructor has not the name of the type, - //convert it into a method with 'null' as its return type - boolean hasConstructor = false; - if (this.methods != null) { - for (int i = this.methods.length; --i >= 0;) { - AbstractMethodDeclaration am; - if ((am = this.methods[i]).isConstructor()) { - if (!CharOperation.equals(am.selector, this.name)) { - // the constructor was in fact a method with no return type - // unless an explicit constructor call was supplied - ConstructorDeclaration c = (ConstructorDeclaration) am; - if (c.constructorCall == null || c.constructorCall.isImplicitSuper()) { //changed to a method - MethodDeclaration m = parser.convertToMethodDeclaration(c, this.compilationResult); - this.methods[i] = m; - } - } else { - switch (kind(this.modifiers)) { - case TypeDeclaration.INTERFACE_DECL : - // report the problem and continue the parsing - parser.problemReporter().interfaceCannotHaveConstructors((ConstructorDeclaration) am); - break; - case TypeDeclaration.ANNOTATION_TYPE_DECL : - // report the problem and continue the parsing - parser.problemReporter().annotationTypeDeclarationCannotHaveConstructor((ConstructorDeclaration) am); - break; - - } - hasConstructor = true; - } - } - } - } - return hasConstructor; -} - -@Override -public CompilationResult compilationResult() { - return this.compilationResult; -} - - -public ConstructorDeclaration createDefaultConstructorForRecord(boolean needExplicitConstructorCall, boolean needToInsert) { - //Add to method'set, the default constuctor that just recall the - //super constructor with no arguments - //The arguments' type will be positionned by the TC so just use - //the default int instead of just null (consistency purpose) - - ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult); - constructor.bits |= ASTNode.IsCanonicalConstructor | ASTNode.IsImplicit; - constructor.selector = this.name; - constructor.modifiers = this.modifiers & ExtraCompilerModifiers.AccVisibilityMASK; -// constructor.modifiers = this.modifiers & ClassFileConstants.AccPublic; -// constructor.modifiers |= ClassFileConstants.AccPublic; // JLS 14 8.10.5 - constructor.arguments = getArgumentsFromComponents(this.recordComponents); - - for (int i = 0, max = constructor.arguments.length; i < max; i++) { - if ((constructor.arguments[i].bits & ASTNode.HasTypeAnnotations) != 0) { - constructor.bits |= ASTNode.HasTypeAnnotations; - break; - } - } - constructor.declarationSourceStart = constructor.sourceStart = - constructor.bodyStart = this.sourceStart; - constructor.declarationSourceEnd = - constructor.sourceEnd = constructor.bodyEnd = this.sourceStart - 1; - - //the super call inside the constructor - if (needExplicitConstructorCall) { - constructor.constructorCall = SuperReference.implicitSuperConstructorCall(); - constructor.constructorCall.sourceStart = this.sourceStart; - constructor.constructorCall.sourceEnd = this.sourceEnd; - } -/* The body of the implicitly declared canonical constructor initializes each field corresponding - * to a record component with the corresponding formal parameter in the order that they appear - * in the record component list.*/ - List statements = new ArrayList<>(); - int l = this.recordComponents != null ? this.recordComponents.length : 0; - if (l > 0 && this.fields != null) { - List fNames = Arrays.stream(this.fields) - .filter(f -> f.isARecordComponent) - .map(f ->new String(f.name)) - .collect(Collectors.toList()); - for (int i = 0; i < l; ++i) { - RecordComponent component = this.recordComponents[i]; - if (!fNames.contains(new String(component.name))) - continue; - FieldReference lhs = new FieldReference(component.name, 0); - lhs.receiver = ThisReference.implicitThis(); - statements.add(new Assignment(lhs, new SingleNameReference(component.name, 0), 0)); - } - } - constructor.statements = statements.toArray(new Statement[0]); - - //adding the constructor in the methods list: rank is not critical since bindings will be sorted - if (needToInsert) { - if (this.methods == null) { - this.methods = new AbstractMethodDeclaration[] { constructor }; - } else { - AbstractMethodDeclaration[] newMethods; - System.arraycopy( - this.methods, - 0, - newMethods = new AbstractMethodDeclaration[this.methods.length + 1], - 1, - this.methods.length); - newMethods[0] = constructor; - this.methods = newMethods; - } - } - return constructor; -} - - -private Argument[] getArgumentsFromComponents(RecordComponent[] comps) { - Argument[] args2 = comps == null || comps.length == 0 ? ASTNode.NO_ARGUMENTS : - new Argument[comps.length]; - int count = 0; - for (RecordComponent comp : comps) { - Argument argument = new Argument(comp.name, ((long)comp.sourceStart) << 32 | comp.sourceEnd, - comp.type, 0); // no modifiers allowed for record components - enforce - args2[count++] = argument; - } - return args2; -} - -public ConstructorDeclaration createDefaultConstructor( boolean needExplicitConstructorCall, boolean needToInsert) { - if (this.isRecord()) - return createDefaultConstructorForRecord(needExplicitConstructorCall, needToInsert); - //Add to method'set, the default constuctor that just recall the - //super constructor with no arguments - //The arguments' type will be positionned by the TC so just use - //the default int instead of just null (consistency purpose) - - //the constructor - ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult); - constructor.bits |= ASTNode.IsDefaultConstructor; - constructor.selector = this.name; - constructor.modifiers = this.modifiers & ExtraCompilerModifiers.AccVisibilityMASK; - - //if you change this setting, please update the - //SourceIndexer2.buildTypeDeclaration(TypeDeclaration,char[]) method - constructor.declarationSourceStart = constructor.sourceStart = this.sourceStart; - constructor.declarationSourceEnd = - constructor.sourceEnd = constructor.bodyEnd = this.sourceEnd; - - //the super call inside the constructor - if (needExplicitConstructorCall) { - constructor.constructorCall = SuperReference.implicitSuperConstructorCall(); - constructor.constructorCall.sourceStart = this.sourceStart; - constructor.constructorCall.sourceEnd = this.sourceEnd; - } - - //adding the constructor in the methods list: rank is not critical since bindings will be sorted - if (needToInsert) { - if (this.methods == null) { - this.methods = new AbstractMethodDeclaration[] { constructor }; - } else { - AbstractMethodDeclaration[] newMethods; - System.arraycopy( - this.methods, - 0, - newMethods = new AbstractMethodDeclaration[this.methods.length + 1], - 1, - this.methods.length); - newMethods[0] = constructor; - this.methods = newMethods; - } - } - return constructor; -} - -// anonymous type constructor creation: rank is important since bindings already got sorted -public MethodBinding createDefaultConstructorWithBinding(MethodBinding inheritedConstructorBinding, boolean eraseThrownExceptions) { - //Add to method'set, the default constuctor that just recall the - //super constructor with the same arguments - String baseName = "$anonymous"; //$NON-NLS-1$ - TypeBinding[] argumentTypes = inheritedConstructorBinding.parameters; - int argumentsLength = argumentTypes.length; - //the constructor - ConstructorDeclaration constructor = new ConstructorDeclaration(this.compilationResult); - constructor.selector = new char[] { 'x' }; //no maining - constructor.sourceStart = this.sourceStart; - constructor.sourceEnd = this.sourceEnd; - int newModifiers = this.modifiers & ExtraCompilerModifiers.AccVisibilityMASK; - if (inheritedConstructorBinding.isVarargs()) { - newModifiers |= ClassFileConstants.AccVarargs; - } - constructor.modifiers = newModifiers; - constructor.bits |= ASTNode.IsDefaultConstructor; - - if (argumentsLength > 0) { - Argument[] arguments = (constructor.arguments = new Argument[argumentsLength]); - for (int i = argumentsLength; --i >= 0;) { - arguments[i] = new Argument((baseName + i).toCharArray(), 0L, null /*type ref*/, ClassFileConstants.AccDefault); - } - } - //the super call inside the constructor - constructor.constructorCall = SuperReference.implicitSuperConstructorCall(); - constructor.constructorCall.sourceStart = this.sourceStart; - constructor.constructorCall.sourceEnd = this.sourceEnd; - - if (argumentsLength > 0) { - Expression[] args1; - args1 = constructor.constructorCall.arguments = new Expression[argumentsLength]; - for (int i = argumentsLength; --i >= 0;) { - args1[i] = new SingleNameReference((baseName + i).toCharArray(), 0L); - } - } - - //adding the constructor in the methods list - if (this.methods == null) { - this.methods = new AbstractMethodDeclaration[] { constructor }; - } else { - AbstractMethodDeclaration[] newMethods; - System.arraycopy(this.methods, 0, newMethods = new AbstractMethodDeclaration[this.methods.length + 1], 1, this.methods.length); - newMethods[0] = constructor; - this.methods = newMethods; - } - - //============BINDING UPDATE========================== - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=277643, align with javac on JLS 15.12.2.6 - ReferenceBinding[] thrownExceptions = eraseThrownExceptions - ? this.scope.environment().convertToRawTypes(inheritedConstructorBinding.thrownExceptions, true, true) - : inheritedConstructorBinding.thrownExceptions; - - SourceTypeBinding sourceType = this.binding; - constructor.binding = new MethodBinding( - constructor.modifiers, //methodDeclaration - argumentsLength == 0 ? Binding.NO_PARAMETERS : argumentTypes, //arguments bindings - thrownExceptions, //exceptions - sourceType); //declaringClass - constructor.binding.tagBits |= (inheritedConstructorBinding.tagBits & TagBits.HasMissingType); - constructor.binding.modifiers |= ExtraCompilerModifiers.AccIsDefaultConstructor; - if (inheritedConstructorBinding.parameterFlowBits != null // this implies that annotation based null/resource analysis is enabled - && argumentsLength > 0) - { - // copy flowbits from inherited constructor to the new constructor: - int len = inheritedConstructorBinding.parameterFlowBits.length; - System.arraycopy(inheritedConstructorBinding.parameterFlowBits, 0, - constructor.binding.parameterFlowBits = new byte[len], 0, len); - } - // TODO(stephan): do argument types already carry sufficient info about type annotations? - - constructor.scope = new MethodScope(this.scope, constructor, true); - constructor.bindArguments(); - constructor.constructorCall.resolve(constructor.scope); - - MethodBinding[] methodBindings = sourceType.methods(); // trigger sorting - int length; - System.arraycopy(methodBindings, 0, methodBindings = new MethodBinding[(length = methodBindings.length) + 1], 1, length); - methodBindings[0] = constructor.binding; - if (++length > 1) - ReferenceBinding.sortMethods(methodBindings, 0, length); // need to resort, since could be valid methods ahead (140643) - DOM needs eager sorting - sourceType.setMethods(methodBindings); - //=================================================== - - return constructor.binding; -} - -/** - * Find the matching parse node, answers null if nothing found - */ -public FieldDeclaration declarationOf(FieldBinding fieldBinding) { - if (fieldBinding != null && this.fields != null) { - for (int i = 0, max = this.fields.length; i < max; i++) { - FieldDeclaration fieldDecl; - if ((fieldDecl = this.fields[i]).binding == fieldBinding) - return fieldDecl; - } - } - return null; -} - -/** - * Find the matching parse node, answers null if nothing found - */ -public TypeDeclaration declarationOf(MemberTypeBinding memberTypeBinding) { - if (memberTypeBinding != null && this.memberTypes != null) { - for (int i = 0, max = this.memberTypes.length; i < max; i++) { - TypeDeclaration memberTypeDecl; - if (TypeBinding.equalsEquals((memberTypeDecl = this.memberTypes[i]).binding, memberTypeBinding)) - return memberTypeDecl; - } - } - return null; -} - -/** - * Find the matching parse node, answers null if nothing found - */ -public AbstractMethodDeclaration declarationOf(MethodBinding methodBinding) { - if (methodBinding != null && this.methods != null) { - for (int i = 0, max = this.methods.length; i < max; i++) { - AbstractMethodDeclaration methodDecl; - - if ((methodDecl = this.methods[i]).binding == methodBinding) - return methodDecl; - } - } - return null; -} - -/** - * Find the matching parse node, answers null if nothing found - */ -public RecordComponent declarationOf(RecordComponentBinding recordComponentBinding) { - if (recordComponentBinding != null && this.recordComponents != null) { - for (int i = 0, max = this.recordComponents.length; i < max; i++) { - RecordComponent recordComponent; - if ((recordComponent = this.recordComponents[i]).binding == recordComponentBinding) - return recordComponent; - } - } - return null; -} - -/** - * Finds the matching type amoung this type's member types. - * Returns null if no type with this name is found. - * The type name is a compound name relative to this type - * e.g. if this type is X and we're looking for Y.X.A.B - * then a type name would be {X, A, B} - */ -public TypeDeclaration declarationOfType(char[][] typeName) { - int typeNameLength = typeName.length; - if (typeNameLength < 1 || !CharOperation.equals(typeName[0], this.name)) { - return null; - } - if (typeNameLength == 1) { - return this; - } - char[][] subTypeName = new char[typeNameLength - 1][]; - System.arraycopy(typeName, 1, subTypeName, 0, typeNameLength - 1); - for (int i = 0; i < this.memberTypes.length; i++) { - TypeDeclaration typeDecl = this.memberTypes[i].declarationOfType(subTypeName); - if (typeDecl != null) { - return typeDecl; - } - } - return null; -} - -@Override -public CompilationUnitDeclaration getCompilationUnitDeclaration() { - if (this.scope != null) { - return this.scope.compilationUnitScope().referenceContext; - } - return null; -} - -/** - * This is applicable only for records - ideally get the canonical constructor, if not - * get a constructor and at the client side tentatively marked as canonical constructor - * which gets checked at the binding time. If there are no constructors, then null is returned. - **/ -public ConstructorDeclaration getConstructor(Parser parser) { - ConstructorDeclaration cd = null; - if (this.methods != null) { - for (int i = this.methods.length; --i >= 0;) { - AbstractMethodDeclaration am; - if ((am = this.methods[i]).isConstructor()) { - if (!CharOperation.equals(am.selector, this.name)) { - // the constructor was in fact a method with no return type - // unless an explicit constructor call was supplied - ConstructorDeclaration c = (ConstructorDeclaration) am; - if (c.constructorCall == null || c.constructorCall.isImplicitSuper()) { //changed to a method - MethodDeclaration m = parser.convertToMethodDeclaration(c, this.compilationResult); - this.methods[i] = m; - } - } else { - if (am instanceof CompactConstructorDeclaration) { - CompactConstructorDeclaration ccd = (CompactConstructorDeclaration) am; - ccd.recordDeclaration = this; - if (ccd.arguments == null) - ccd.arguments = getArgumentsFromComponents(this.recordComponents); - return ccd; - } - // now we are looking at a "normal" constructor - if ((this.recordComponents == null || this.recordComponents.length == 0) - && am.arguments == null) - return (ConstructorDeclaration) am; - cd = (ConstructorDeclaration) am; // just return the last constructor - } - } - } - } -// /* At this point we can only say that there is high possibility that there is a constructor -// * If it is a CCD, then definitely it is there (except for empty one); else we need to check -// * the bindings to say that there is a canonical constructor. To take care at binding resolution time. -// */ - return cd; // the last constructor -} - -/** - * Generic bytecode generation for type - */ -public void generateCode(ClassFile enclosingClassFile) { - if ((this.bits & ASTNode.HasBeenGenerated) != 0) - return; - this.bits |= ASTNode.HasBeenGenerated; - if (this.ignoreFurtherInvestigation) { - if (this.binding == null) - return; - ClassFile.createProblemType( - this, - this.scope.referenceCompilationUnit().compilationResult); - return; - } - try { - // create the result for a compiled type - ClassFile classFile = ClassFile.getNewInstance(this.binding); - classFile.initialize(this.binding, enclosingClassFile, false); - if (this.binding.isMemberType()) { - classFile.recordInnerClasses(this.binding); - } else if (this.binding.isLocalType()) { - enclosingClassFile.recordInnerClasses(this.binding); - classFile.recordInnerClasses(this.binding); - } - SourceTypeBinding nestHost = this.binding.getNestHost(); - if (nestHost != null && !TypeBinding.equalsEquals(nestHost, this.binding)) { - ClassFile ocf = enclosingClassFile.outerMostEnclosingClassFile(); - if (ocf != null) - ocf.recordNestMember(this.binding); - } - TypeVariableBinding[] typeVariables = this.binding.typeVariables(); - for (int i = 0, max = typeVariables.length; i < max; i++) { - TypeVariableBinding typeVariableBinding = typeVariables[i]; - if ((typeVariableBinding.tagBits & TagBits.ContainsNestedTypeReferences) != 0) { - Util.recordNestedType(classFile, typeVariableBinding); - } - } - - // generate all fiels - classFile.addFieldInfos(); - - if (this.memberTypes != null) { - for (int i = 0, max = this.memberTypes.length; i < max; i++) { - TypeDeclaration memberType = this.memberTypes[i]; - classFile.recordInnerClasses(memberType.binding); - memberType.generateCode(this.scope, classFile); - } - } - // generate all methods - classFile.setForMethodInfos(); - if (this.methods != null) { - for (int i = 0, max = this.methods.length; i < max; i++) { - this.methods[i].generateCode(this.scope, classFile); - } - } - // generate all synthetic and abstract methods - classFile.addSpecialMethods(this); - - if (this.ignoreFurtherInvestigation) { // trigger problem type generation for code gen errors - throw new AbortType(this.scope.referenceCompilationUnit().compilationResult, null); - } - - // finalize the compiled type result - classFile.addAttributes(); - this.scope.referenceCompilationUnit().compilationResult.record( - this.binding.constantPoolName(), - classFile); - } catch (AbortType e) { - if (this.binding == null) - return; - ClassFile.createProblemType( - this, - this.scope.referenceCompilationUnit().compilationResult); - } -} - -/** - * Bytecode generation for a local inner type (API as a normal statement code gen) - */ -@Override -public void generateCode(BlockScope blockScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) { - return; - } - if ((this.bits & ASTNode.HasBeenGenerated) != 0) return; - int pc = codeStream.position; - if (this.binding != null) { - SyntheticArgumentBinding[] enclosingInstances = ((NestedTypeBinding) this.binding).syntheticEnclosingInstances(); - for (int i = 0, slotSize = 0, count = enclosingInstances == null ? 0 : enclosingInstances.length; i < count; i++){ - SyntheticArgumentBinding enclosingInstance = enclosingInstances[i]; - enclosingInstance.resolvedPosition = ++slotSize; // shift by 1 to leave room for aload0==this - if (slotSize > 0xFF) { // no more than 255 words of arguments - blockScope.problemReporter().noMoreAvailableSpaceForArgument(enclosingInstance, blockScope.referenceType()); - } - } - } - generateCode(codeStream.classFile); - codeStream.recordPositionsFrom(pc, this.sourceStart); -} - -/** - * Bytecode generation for a member inner type - */ -public void generateCode(ClassScope classScope, ClassFile enclosingClassFile) { - if ((this.bits & ASTNode.HasBeenGenerated) != 0) return; - if (this.binding != null) { - SyntheticArgumentBinding[] enclosingInstances = ((NestedTypeBinding) this.binding).syntheticEnclosingInstances(); - for (int i = 0, slotSize = 0, count = enclosingInstances == null ? 0 : enclosingInstances.length; i < count; i++){ - SyntheticArgumentBinding enclosingInstance = enclosingInstances[i]; - enclosingInstance.resolvedPosition = ++slotSize; // shift by 1 to leave room for aload0==this - if (slotSize > 0xFF) { // no more than 255 words of arguments - classScope.problemReporter().noMoreAvailableSpaceForArgument(enclosingInstance, classScope.referenceType()); - } - } - } - generateCode(enclosingClassFile); -} - -/** - * Bytecode generation for a package member - */ -public void generateCode(CompilationUnitScope unitScope) { - generateCode((ClassFile) null); -} - -@Override -public boolean hasErrors() { - return this.ignoreFurtherInvestigation; -} - -/** - * Common flow analysis for all types - */ -private void internalAnalyseCode(FlowContext flowContext, FlowInfo flowInfo) { - if (CharOperation.equals(this.name, TypeConstants.YIELD)) { - this.scope.problemReporter().validateRestrictedKeywords(this.name, this); - } - - if (!this.binding.isUsed() && this.binding.isOrEnclosedByPrivateType()) { - if (!this.scope.referenceCompilationUnit().compilationResult.hasSyntaxError) { - this.scope.problemReporter().unusedPrivateType(this); - } - } - - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=385780 - if (this.typeParameters != null && - !this.scope.referenceCompilationUnit().compilationResult.hasSyntaxError) { - for (int i = 0, length = this.typeParameters.length; i < length; ++i) { - TypeParameter typeParameter = this.typeParameters[i]; - if ((typeParameter.binding.modifiers & ExtraCompilerModifiers.AccLocallyUsed) == 0) { - this.scope.problemReporter().unusedTypeParameter(typeParameter); - } - } - } - - boolean useOwningAnnotations = this.scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled; - boolean isCloseable = this.binding.hasTypeBit(TypeIds.BitAutoCloseable|TypeIds.BitCloseable); - FieldDeclaration fieldNeedingClose = null; - - // 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(); - if (this.fields != null) { - for (int i = 0, count = this.fields.length; i < count; i++) { - FieldDeclaration field = this.fields[i]; - if (field.isStatic()) { - if ((staticFieldInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) - field.bits &= ~ASTNode.IsReachable; - - /*if (field.isField()){ - staticInitializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2 - } else {*/ - staticInitializerContext.handledExceptions = Binding.ANY_EXCEPTION; // tolerate them all, and record them - /*}*/ - staticFieldInfo = field.analyseCode(this.staticInitializerScope, staticInitializerContext, staticFieldInfo); - // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable - // branch, since the previous initializer already got the blame. - if (staticFieldInfo == FlowInfo.DEAD_END) { - this.staticInitializerScope.problemReporter().initializerMustCompleteNormally(field); - staticFieldInfo = FlowInfo.initial(this.maxFieldCount).setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - } else { - if ((nonStaticFieldInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) - field.bits &= ~ASTNode.IsReachable; - - /*if (field.isField()){ - initializerContext.handledExceptions = NoExceptions; // no exception is allowed jls8.3.2 - } else {*/ - initializerContext.handledExceptions = Binding.ANY_EXCEPTION; // tolerate them all, and record them - /*}*/ - nonStaticFieldInfo = field.analyseCode(this.initializerScope, initializerContext, nonStaticFieldInfo); - // in case the initializer is not reachable, use a reinitialized flowInfo and enter a fake reachable - // branch, since the previous initializer already got the blame. - if (nonStaticFieldInfo == FlowInfo.DEAD_END) { - this.initializerScope.problemReporter().initializerMustCompleteNormally(field); - nonStaticFieldInfo = FlowInfo.initial(this.maxFieldCount).setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - if (fieldNeedingClose == null && useOwningAnnotations && isCloseable && (field.binding.tagBits & TagBits.AnnotationOwning) != 0) { - fieldNeedingClose = field; - } - } - } - } - if (this.memberTypes != null) { - for (int i = 0, count = this.memberTypes.length; i < count; i++) { - if (flowContext != null){ // local type - this.memberTypes[i].analyseCode(this.scope, flowContext, nonStaticFieldInfo.copy().setReachMode(flowInfo.reachMode())); // reset reach mode in case initializers did abrupt completely - } else { - this.memberTypes[i].analyseCode(this.scope); - } - } - } - if (this.scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK9) { - // synthesize if one is not present. Required to initialize - // synthetic final fields as modifying final fields outside of a - // is disallowed in Java 9 - if (this.methods == null || !this.methods[0].isClinit()) { - Clinit clinit = new Clinit(this.compilationResult); - clinit.declarationSourceStart = clinit.sourceStart = this.sourceStart; - clinit.declarationSourceEnd = clinit.sourceEnd = this.sourceEnd; - clinit.bodyEnd = this.sourceEnd; - int length = this.methods == null ? 0 : this.methods.length; - AbstractMethodDeclaration[] methodDeclarations = new AbstractMethodDeclaration[length + 1]; - methodDeclarations[0] = clinit; - if (this.methods != null) - System.arraycopy(this.methods, 0, methodDeclarations, 1, length); - } - } - if (this.methods != null) { - UnconditionalFlowInfo outerInfo = flowInfo.unconditionalFieldLessCopy(); - FlowInfo constructorInfo = nonStaticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo); - SimpleSetOfCharArray jUnitMethodSourceValues = getJUnitMethodSourceValues(); - for (int i = 0, count = this.methods.length; i < count; i++) { - AbstractMethodDeclaration method = this.methods[i]; - if (method.ignoreFurtherInvestigation) - continue; - if (method.isInitializationMethod()) { - // pass down the appropriate initializerContext: - if (method.isStatic()) { // - ((Clinit)method).analyseCode( - this.scope, - staticInitializerContext, - staticFieldInfo.unconditionalInits().discardNonFieldInitializations().addInitializationsFrom(outerInfo)); - } else { // constructor - ((ConstructorDeclaration)method).analyseCode(this.scope, initializerContext, constructorInfo.copy(), flowInfo.reachMode()); - } - } else { // regular method - // JUnit 5 only accepts methods without arguments for method sources - if (method.arguments == null && jUnitMethodSourceValues.includes(method.selector) && method.binding != null) { - method.binding.modifiers |= ExtraCompilerModifiers.AccLocallyUsed; - } - // pass down the parentContext (NOT an initializer context, see above): - ((MethodDeclaration)method).analyseCode(this.scope, parentContext, flowInfo.copy()); - if (fieldNeedingClose != null && CharOperation.equals(TypeConstants.CLOSE, method.selector) && method.arguments == null) { - fieldNeedingClose = null; - } - } - } - } - if (fieldNeedingClose != null) { - this.scope.problemReporter().missingImplementationOfClose(fieldNeedingClose); - } - // enable enum support ? - if (this.binding.isEnum() && !this.binding.isAnonymousType()) { - this.enumValuesSyntheticfield = this.binding.addSyntheticFieldForEnumValues(); - } -} - -private SimpleSetOfCharArray getJUnitMethodSourceValues() { - SimpleSetOfCharArray junitMethodSourceValues = new SimpleSetOfCharArray(); - for (AbstractMethodDeclaration methodDeclaration : this.methods) { - if (methodDeclaration.annotations != null) { - for (Annotation annotation : methodDeclaration.annotations) { - if (annotation.resolvedType != null && annotation.resolvedType.id == TypeIds.T_OrgJunitJupiterParamsProviderMethodSource) { - addJUnitMethodSourceValues(junitMethodSourceValues, annotation, methodDeclaration.selector); - } - } - } - } - return junitMethodSourceValues; -} - -private void addJUnitMethodSourceValues(SimpleSetOfCharArray junitMethodSourceValues, Annotation annotation, char[] methodName) { - for (MemberValuePair memberValuePair : annotation.memberValuePairs()) { - if (CharOperation.equals(memberValuePair.name, TypeConstants.VALUE)) { - Expression value = memberValuePair.value; - if (value instanceof ArrayInitializer) { // e.g. @MethodSource({ "someMethod" }) - ArrayInitializer arrayInitializer = (ArrayInitializer) value; - for (Expression arrayValue : arrayInitializer.expressions) { - junitMethodSourceValues.add(getValueAsChars(arrayValue)); - } - } else { - junitMethodSourceValues.add(getValueAsChars(value)); - } - return; - } - } - // value member not specified (i.e. marker annotation): JUnit 5 defaults to the test method's name - junitMethodSourceValues.add(methodName); -} - -private char[] getValueAsChars(Expression value) { - if (value instanceof StringLiteral) { // e.g. "someMethod" - return ((StringLiteral) value).source(); - } else if (value.constant instanceof StringConstant) { // e.g. SOME_CONSTANT + "value" - return ((StringConstant) value.constant).stringValue().toCharArray(); - } - return CharOperation.NO_CHAR; -} - -public final static int kind(int flags) { - switch (flags & (ClassFileConstants.AccInterface|ClassFileConstants.AccAnnotation|ClassFileConstants.AccEnum|ExtraCompilerModifiers.AccRecord)) { - case ClassFileConstants.AccInterface : - return TypeDeclaration.INTERFACE_DECL; - case ClassFileConstants.AccInterface|ClassFileConstants.AccAnnotation : - return TypeDeclaration.ANNOTATION_TYPE_DECL; - case ClassFileConstants.AccEnum : - return TypeDeclaration.ENUM_DECL; - case ExtraCompilerModifiers.AccRecord : - return TypeDeclaration.RECORD_DECL; - default : - return TypeDeclaration.CLASS_DECL; - } -} - -public boolean isRecord() { - return (this.modifiers & ExtraCompilerModifiers.AccRecord) != 0; -} - -/* - * Access emulation for a local type - * force to emulation of access to direct enclosing instance. - * By using the initializer scope, we actually only request an argument emulation, the - * field is not added until actually used. However we will force allocations to be qualified - * with an enclosing instance. - * 15.9.2 - */ -public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) return; - NestedTypeBinding nestedType = (NestedTypeBinding) this.binding; - - MethodScope methodScope = currentScope.methodScope(); - if (!methodScope.isStatic && !methodScope.isConstructorCall){ - nestedType.addSyntheticArgumentAndField(nestedType.enclosingType()); - } - // add superclass enclosing instance arg for anonymous types (if necessary) - if (nestedType.isAnonymousType()) { - ReferenceBinding superclassBinding = (ReferenceBinding)nestedType.superclass.erasure(); - if (superclassBinding.enclosingType() != null && !superclassBinding.isStatic()) { - if (!superclassBinding.isLocalType() - || ((NestedTypeBinding)superclassBinding).getSyntheticField(superclassBinding.enclosingType(), true) != null - || superclassBinding.isMemberType()){ - nestedType.addSyntheticArgument(superclassBinding.enclosingType()); - } - } - // From 1.5 on, provide access to enclosing instance synthetic constructor argument when declared inside constructor call - // only for direct anonymous type - //public class X { - // void foo() {} - // class M { - // M(Object o) {} - // M() { this(new Object() { void baz() { foo(); }}); } // access to #foo() indirects through constructor synthetic arg: val$this$0 - // } - //} - if (!methodScope.isStatic && methodScope.isConstructorCall && currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5) { - ReferenceBinding enclosing = nestedType.enclosingType(); - if (enclosing.isNestedType()) { - NestedTypeBinding nestedEnclosing = (NestedTypeBinding)enclosing; -// if (nestedEnclosing.findSuperTypeErasingTo(nestedEnclosing.enclosingType()) == null) { // only if not inheriting - SyntheticArgumentBinding syntheticEnclosingInstanceArgument = nestedEnclosing.getSyntheticArgument(nestedEnclosing.enclosingType(), true, false); - if (syntheticEnclosingInstanceArgument != null) { - nestedType.addSyntheticArgumentAndField(syntheticEnclosingInstanceArgument); - } - } -// } - } - } -} - -/** - * Access emulation for a local member type - * force to emulation of access to direct enclosing instance. - * By using the initializer scope, we actually only request an argument emulation, the - * field is not added until actually used. However we will force allocations to be qualified - * with an enclosing instance. - * - * Local member cannot be static. - */ -public void manageEnclosingInstanceAccessIfNecessary(ClassScope currentScope, FlowInfo flowInfo) { - if ((flowInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) == 0) { - NestedTypeBinding nestedType = (NestedTypeBinding) this.binding; - nestedType.addSyntheticArgumentAndField(this.binding.enclosingType()); - } -} - -/** - * A {@code } will be requested as soon as static fields or assertions are present. It will be eliminated during - * classfile creation if no bytecode was actually produced based on some optimizations/compiler settings. - */ -public final boolean needClassInitMethod() { - // always need a when assertions are present - if ((this.bits & ASTNode.ContainsAssertion) != 0) - return true; - - switch (kind(this.modifiers)) { - case TypeDeclaration.INTERFACE_DECL: - case TypeDeclaration.ANNOTATION_TYPE_DECL: - return this.fields != null; // fields are implicitly statics - case TypeDeclaration.ENUM_DECL: - return true; // even if no enum constants, need to set $VALUES array - } - if (this.fields != null) { - for (int i = this.fields.length; --i >= 0;) { - FieldDeclaration field = this.fields[i]; - //need to test the modifier directly while there is no binding yet - if ((field.modifiers & ClassFileConstants.AccStatic) != 0) - return true; // TODO (philippe) shouldn't it check whether field is initializer or has some initial value ? - } - } - return false; -} - -public void parseMethods(Parser parser, CompilationUnitDeclaration unit) { - //connect method bodies - if (unit.ignoreMethodBodies) - return; - - //members - if (this.memberTypes != null) { - int length = this.memberTypes.length; - for (int i = 0; i < length; i++) { - TypeDeclaration typeDeclaration = this.memberTypes[i]; - typeDeclaration.parseMethods(parser, unit); - this.bits |= (typeDeclaration.bits & ASTNode.HasSyntaxErrors); - } - } - - //methods - if (this.methods != null) { - int length = this.methods.length; - for (int i = 0; i < length; i++) { - AbstractMethodDeclaration abstractMethodDeclaration = this.methods[i]; - abstractMethodDeclaration.parseStatements(parser, unit); - this.bits |= (abstractMethodDeclaration.bits & ASTNode.HasSyntaxErrors); - } - } - - //initializers - if (this.fields != null) { - int length = this.fields.length; - for (int i = 0; i < length; i++) { - final FieldDeclaration fieldDeclaration = this.fields[i]; - switch(fieldDeclaration.getKind()) { - case AbstractVariableDeclaration.INITIALIZER: - ((Initializer) fieldDeclaration).parseStatements(parser, this, unit); - this.bits |= (fieldDeclaration.bits & ASTNode.HasSyntaxErrors); - break; - } - } - } -} - -@Override -public StringBuilder print(int indent, StringBuilder output) { - if (this.javadoc != null) { - this.javadoc.print(indent, output); - } - if ((this.bits & ASTNode.IsAnonymousType) == 0) { - printIndent(indent, output); - printHeader(0, output); - } - return printBody(indent, output); -} - -public StringBuilder printBody(int indent, StringBuilder output) { - output.append(" {"); //$NON-NLS-1$ - if (this.memberTypes != null) { - for (int i = 0; i < this.memberTypes.length; i++) { - if (this.memberTypes[i] != null) { - output.append('\n'); - this.memberTypes[i].print(indent + 1, output); - } - } - } - if (this.fields != null) { - for (int fieldI = 0; fieldI < this.fields.length; fieldI++) { - if (this.fields[fieldI] != null) { - output.append('\n'); - this.fields[fieldI].print(indent + 1, output); - } - } - } - if (this.methods != null) { - for (int i = 0; i < this.methods.length; i++) { - if (this.methods[i] != null) { - output.append('\n'); - this.methods[i].print(indent + 1, output); - } - } - } - output.append('\n'); - return printIndent(indent, output).append('}'); -} - -public StringBuilder printHeader(int indent, StringBuilder output) { - printModifiers(this.modifiers, output); - if (this.annotations != null) { - printAnnotations(this.annotations, output); - output.append(' '); - } - - switch (kind(this.modifiers)) { - case TypeDeclaration.CLASS_DECL : - output.append("class "); //$NON-NLS-1$ - break; - case TypeDeclaration.INTERFACE_DECL : - output.append("interface "); //$NON-NLS-1$ - break; - case TypeDeclaration.ENUM_DECL : - output.append("enum "); //$NON-NLS-1$ - break; - case TypeDeclaration.ANNOTATION_TYPE_DECL : - output.append("@interface "); //$NON-NLS-1$ - break; - case TypeDeclaration.RECORD_DECL : - output.append("record "); //$NON-NLS-1$ - break; - } - output.append(this.name); - if (this.isRecord()) { - output.append('('); - if (this.nRecordComponents > 0 && this.fields != null) { - for (int i = 0; i < this.nRecordComponents; i++) { - if (i > 0) output.append(", "); //$NON-NLS-1$ - output.append(this.fields[i].type.getTypeName()[0]); - output.append(' '); - output.append(this.fields[i].name); - } - } - output.append(')'); - } - if (this.typeParameters != null) { - output.append("<");//$NON-NLS-1$ - for (int i = 0; i < this.typeParameters.length; i++) { - if (i > 0) output.append( ", "); //$NON-NLS-1$ - this.typeParameters[i].print(0, output); - } - output.append(">");//$NON-NLS-1$ - } - - if (!this.isRecord() && this.superclass != null) { - output.append(" extends "); //$NON-NLS-1$ - this.superclass.print(0, output); - } - if (this.superInterfaces != null && this.superInterfaces.length > 0) { - switch (kind(this.modifiers)) { - case TypeDeclaration.CLASS_DECL : - case TypeDeclaration.ENUM_DECL : - case TypeDeclaration.RECORD_DECL : - output.append(" implements "); //$NON-NLS-1$ - break; - case TypeDeclaration.INTERFACE_DECL : - case TypeDeclaration.ANNOTATION_TYPE_DECL : - output.append(" extends "); //$NON-NLS-1$ - break; - } - for (int i = 0; i < this.superInterfaces.length; i++) { - if (i > 0) output.append( ", "); //$NON-NLS-1$ - this.superInterfaces[i].print(0, output); - } - } - if (this.permittedTypes != null && this.permittedTypes.length > 0) { - output.append(" permits "); //$NON-NLS-1$ - for (int i = 0; i < this.permittedTypes.length; i++) { - if (i > 0) output.append( ", "); //$NON-NLS-1$ - this.permittedTypes[i].print(0, output); - } - } - return output; -} - -@Override -public StringBuilder printStatement(int tab, StringBuilder output) { - return print(tab, output); -} - -/* - * Keep track of number of lambda/method reference expressions in this type declaration. - * Return the 0 based "ordinal" in the TypeDeclaration. - */ -public int record(FunctionalExpression expression) { - return this.functionalExpressionsCount++; -} - -public void resolve() { - SourceTypeBinding sourceType = this.binding; - if (sourceType == null) { - this.ignoreFurtherInvestigation = true; - return; - } - try { - if (CharOperation.equals(this.name, TypeConstants.VAR)) { - if (this.scope.compilerOptions().sourceLevel < ClassFileConstants.JDK10) { - this.scope.problemReporter().varIsReservedTypeNameInFuture(this); - } else { - this.scope.problemReporter().varIsReservedTypeName(this); - } - } - this.scope.problemReporter().validateRestrictedKeywords(this.name, this); - // resolve annotations and check @Deprecated annotation - long annotationTagBits = sourceType.getAnnotationTagBits(); - if ((annotationTagBits & TagBits.AnnotationDeprecated) == 0 - && (sourceType.modifiers & ClassFileConstants.AccDeprecated) != 0 - && this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) { - this.scope.problemReporter().missingDeprecatedAnnotationForType(this); - } - if ((annotationTagBits & TagBits.AnnotationFunctionalInterface) != 0) { - if(!this.binding.isFunctionalInterface(this.scope)) { - this.scope.problemReporter().notAFunctionalInterface(this); - } - } - - if ((this.bits & ASTNode.UndocumentedEmptyBlock) != 0 && this.nRecordComponents == 0) { - this.scope.problemReporter().undocumentedEmptyBlock(this.bodyStart-1, this.bodyEnd); - } - boolean needSerialVersion = - this.scope.compilerOptions().getSeverity(CompilerOptions.MissingSerialVersion) != ProblemSeverities.Ignore - && sourceType.isClass() - && !sourceType.isRecord() - && sourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaIoExternalizable, false /*Externalizable is not a class*/) == null - && sourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaIoSerializable, false /*Serializable is not a class*/) != null; - - if (needSerialVersion) { - // if Object writeReplace() throws java.io.ObjectStreamException is present, then no serialVersionUID is needed - // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=101476 - CompilationUnitScope compilationUnitScope = this.scope.compilationUnitScope(); - MethodBinding methodBinding = sourceType.getExactMethod(TypeConstants.WRITEREPLACE, Binding.NO_TYPES, compilationUnitScope); - ReferenceBinding[] throwsExceptions; - needSerialVersion = - methodBinding == null - || !methodBinding.isValidBinding() - || methodBinding.returnType.id != TypeIds.T_JavaLangObject - || (throwsExceptions = methodBinding.thrownExceptions).length != 1 - || throwsExceptions[0].id != TypeIds.T_JavaIoObjectStreamException; - if (needSerialVersion) { - // check the presence of an implementation of the methods - // private void writeObject(java.io.ObjectOutputStream out) throws IOException - // private void readObject(java.io.ObjectInputStream out) throws IOException - boolean hasWriteObjectMethod = false; - boolean hasReadObjectMethod = false; - TypeBinding argumentTypeBinding = this.scope.getType(TypeConstants.JAVA_IO_OBJECTOUTPUTSTREAM, 3); - if (argumentTypeBinding.isValidBinding()) { - methodBinding = sourceType.getExactMethod(TypeConstants.WRITEOBJECT, new TypeBinding[] { argumentTypeBinding }, compilationUnitScope); - hasWriteObjectMethod = methodBinding != null - && methodBinding.isValidBinding() - && methodBinding.modifiers == ClassFileConstants.AccPrivate - && methodBinding.returnType == TypeBinding.VOID - && (throwsExceptions = methodBinding.thrownExceptions).length == 1 - && throwsExceptions[0].id == TypeIds.T_JavaIoException; - } - argumentTypeBinding = this.scope.getType(TypeConstants.JAVA_IO_OBJECTINPUTSTREAM, 3); - if (argumentTypeBinding.isValidBinding()) { - methodBinding = sourceType.getExactMethod(TypeConstants.READOBJECT, new TypeBinding[] { argumentTypeBinding }, compilationUnitScope); - hasReadObjectMethod = methodBinding != null - && methodBinding.isValidBinding() - && methodBinding.modifiers == ClassFileConstants.AccPrivate - && methodBinding.returnType == TypeBinding.VOID - && (throwsExceptions = methodBinding.thrownExceptions).length == 1 - && throwsExceptions[0].id == TypeIds.T_JavaIoException; - } - needSerialVersion = !hasWriteObjectMethod || !hasReadObjectMethod; - } - } - // generics (and non static generic members) cannot extend Throwable - if (sourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) != null) { - ReferenceBinding current = sourceType; - checkEnclosedInGeneric : do { - if (current.isGenericType()) { - this.scope.problemReporter().genericTypeCannotExtendThrowable(this); - break checkEnclosedInGeneric; - } - if (current.isStatic()) break checkEnclosedInGeneric; - if (current.isLocalType()) { - NestedTypeBinding nestedType = (NestedTypeBinding) current.erasure(); - if (nestedType.scope.methodScope().isStatic) break checkEnclosedInGeneric; - } - } while ((current = current.enclosingType()) != null); - } - // this.maxFieldCount might already be set - int localMaxFieldCount = 0; - int lastVisibleFieldID = -1; - boolean hasEnumConstants = false; - FieldDeclaration[] enumConstantsWithoutBody = null; - - if (this.memberTypes != null) { - for (int i = 0, count = this.memberTypes.length; i < count; i++) { - this.memberTypes[i].resolve(this.scope); - } - } - if (this.recordComponents != null) { - for (RecordComponent rc : this.recordComponents) { - rc.resolve(this.initializerScope); - } - } - if (this.fields != null) { - for (int i = 0, count = this.fields.length; i < count; i++) { - FieldDeclaration field = this.fields[i]; - switch(field.getKind()) { - case AbstractVariableDeclaration.ENUM_CONSTANT: - hasEnumConstants = true; - if (!(field.initialization instanceof QualifiedAllocationExpression)) { - if (enumConstantsWithoutBody == null) - enumConstantsWithoutBody = new FieldDeclaration[count]; - enumConstantsWithoutBody[i] = field; - } - //$FALL-THROUGH$ - case AbstractVariableDeclaration.FIELD: - FieldBinding fieldBinding = field.binding; - if (fieldBinding == null) { - // still discover secondary errors - if (field.initialization != null) field.initialization.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope); - this.ignoreFurtherInvestigation = true; - continue; - } - if (needSerialVersion - && ((fieldBinding.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal)) == (ClassFileConstants.AccStatic | ClassFileConstants.AccFinal)) - && CharOperation.equals(TypeConstants.SERIALVERSIONUID, fieldBinding.name) - && TypeBinding.equalsEquals(TypeBinding.LONG, fieldBinding.type)) { - needSerialVersion = false; - } - localMaxFieldCount++; - lastVisibleFieldID = field.binding.id; - break; - - case AbstractVariableDeclaration.INITIALIZER: - ((Initializer) field).lastVisibleFieldID = lastVisibleFieldID + 1; - break; - } - if (this.isRecord()) { - field.javadoc = this.javadoc; - } - field.resolve(field.isStatic() ? this.staticInitializerScope : this.initializerScope); - } - } - if (this.maxFieldCount < localMaxFieldCount) { - this.maxFieldCount = localMaxFieldCount; - } - if (needSerialVersion) { - //check that the current type doesn't extend javax.rmi.CORBA.Stub - TypeBinding javaxRmiCorbaStub = this.scope.getType(TypeConstants.JAVAX_RMI_CORBA_STUB, 4); - if (javaxRmiCorbaStub.isValidBinding()) { - ReferenceBinding superclassBinding = this.binding.superclass; - loop: while (superclassBinding != null) { - if (TypeBinding.equalsEquals(superclassBinding, javaxRmiCorbaStub)) { - needSerialVersion = false; - break loop; - } - superclassBinding = superclassBinding.superclass(); - } - } - if (needSerialVersion) { - this.scope.problemReporter().missingSerialVersion(this); - } - } - - // check extends/implements for annotation type - switch(kind(this.modifiers)) { - case TypeDeclaration.ANNOTATION_TYPE_DECL : - if (this.superclass != null) { - this.scope.problemReporter().annotationTypeDeclarationCannotHaveSuperclass(this); - } - if (this.superInterfaces != null) { - this.scope.problemReporter().annotationTypeDeclarationCannotHaveSuperinterfaces(this); - } - break; - case TypeDeclaration.ENUM_DECL : - // check enum abstract methods - if (this.binding.isAbstract()) { - if (!hasEnumConstants) { - for (int i = 0, count = this.methods.length; i < count; i++) { - final AbstractMethodDeclaration methodDeclaration = this.methods[i]; - if (methodDeclaration.isAbstract() && methodDeclaration.binding != null) - this.scope.problemReporter().enumAbstractMethodMustBeImplemented(methodDeclaration); - } - } else if (enumConstantsWithoutBody != null) { - for (int i = 0, count = this.methods.length; i < count; i++) { - final AbstractMethodDeclaration methodDeclaration = this.methods[i]; - if (methodDeclaration.isAbstract() && methodDeclaration.binding != null) { - for (int f = 0, l = enumConstantsWithoutBody.length; f < l; f++) - if (enumConstantsWithoutBody[f] != null) - this.scope.problemReporter().enumConstantMustImplementAbstractMethod(methodDeclaration, enumConstantsWithoutBody[f]); - } - } - } - } - break; - } - - int missingAbstractMethodslength = this.missingAbstractMethods == null ? 0 : this.missingAbstractMethods.length; - int methodsLength = this.methods == null ? 0 : this.methods.length; - if ((methodsLength + missingAbstractMethodslength) > 0xFFFF) { - this.scope.problemReporter().tooManyMethods(this); - } - if (this.methods != null) { - for (int i = 0, count = this.methods.length; i < count; i++) { - this.methods[i].resolve(this.scope); - } - } - // Resolve javadoc - if (this.javadoc != null) { - if (this.scope != null && (this.name != TypeConstants.PACKAGE_INFO_NAME)) { - // if the type is package-info, the javadoc was resolved as part of the compilation unit javadoc - this.javadoc.resolve(this.scope); - } - } else if (!sourceType.isLocalType()) { - // Set javadoc visibility - int visibility = sourceType.modifiers & ExtraCompilerModifiers.AccVisibilityMASK; - ProblemReporter reporter = this.scope.problemReporter(); - try { - int severity = reporter.computeSeverity(IProblem.JavadocMissing); - if (severity != ProblemSeverities.Ignore) { - if (this.enclosingType != null) { - visibility = Util.computeOuterMostVisibility(this.enclosingType, visibility); - } - int javadocModifiers = (this.binding.modifiers & ~ExtraCompilerModifiers.AccVisibilityMASK) | visibility; - reporter.javadocMissing(this.sourceStart, this.sourceEnd, severity, javadocModifiers); - } - } finally { - reporter.close(); - } - } - updateNestHost(); - FieldDeclaration[] fieldsDecls = this.fields; - if (fieldsDecls != null) { - for (FieldDeclaration fieldDeclaration : fieldsDecls) - fieldDeclaration.resolveJavadoc(this.initializerScope); - } - AbstractMethodDeclaration[] methodDecls = this.methods; - if (methodDecls != null) { - for (AbstractMethodDeclaration methodDeclaration : methodDecls) - methodDeclaration.resolveJavadoc(); - } - } catch (AbortType e) { - this.ignoreFurtherInvestigation = true; - return; - } -} - -/** - * Resolve a local type declaration - */ -@Override -public void resolve(BlockScope blockScope) { - - // need to build its scope first and proceed with binding's creation - if ((this.bits & ASTNode.IsAnonymousType) == 0) { - // check collision scenarii - Binding existing = blockScope.getType(this.name); - if (existing instanceof ReferenceBinding - && existing != this.binding - && existing.isValidBinding()) { - ReferenceBinding existingType = (ReferenceBinding) existing; - if (existingType instanceof TypeVariableBinding) { - blockScope.problemReporter().typeHiding(this, (TypeVariableBinding) existingType); - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=312989, check for collision with enclosing type. - Scope outerScope = blockScope.parent; -checkOuterScope:while (outerScope != null) { - Binding existing2 = outerScope.getType(this.name); - if (existing2 instanceof TypeVariableBinding && existing2.isValidBinding()) { - TypeVariableBinding tvb = (TypeVariableBinding) existingType; - Binding declaringElement = tvb.declaringElement; - if (declaringElement instanceof ReferenceBinding - && CharOperation.equals(((ReferenceBinding) declaringElement).sourceName(), this.name)) { - blockScope.problemReporter().typeCollidesWithEnclosingType(this); - break checkOuterScope; - } - } else if (existing2 instanceof ReferenceBinding - && existing2.isValidBinding() - && outerScope.isDefinedInType((ReferenceBinding) existing2)) { - blockScope.problemReporter().typeCollidesWithEnclosingType(this); - break checkOuterScope; - } else if (existing2 == null) { - break checkOuterScope; - } - outerScope = outerScope.parent; - } - } else if (existingType instanceof LocalTypeBinding - && ((LocalTypeBinding) existingType).scope.methodScope() == blockScope.methodScope()) { - // dup in same method - blockScope.problemReporter().duplicateNestedType(this); - } else if (existingType instanceof LocalTypeBinding && blockScope.isLambdaSubscope() - && blockScope.enclosingLambdaScope().enclosingMethodScope() == ((LocalTypeBinding) existingType).scope.methodScope()) { - blockScope.problemReporter().duplicateNestedType(this); - } else if (blockScope.isDefinedInType(existingType)) { - // collision with enclosing type - blockScope.problemReporter().typeCollidesWithEnclosingType(this); - } else if (blockScope.isDefinedInSameUnit(existingType)){ // only consider hiding inside same unit - // hiding sibling - blockScope.problemReporter().typeHiding(this, existingType); - } - } - blockScope.addLocalType(this); - } - - if (this.binding != null) { - // remember local types binding for innerclass emulation propagation - blockScope.referenceCompilationUnit().record((LocalTypeBinding)this.binding); - - // binding is not set if the receiver could not be created - resolve(); - updateMaxFieldCount(); - } -} - -/** - * Resolve a member type declaration (can be a local member) - */ -public void resolve(ClassScope upperScope) { - // member scopes are already created - // request the construction of a binding if local member type - - if (this.binding != null && this.binding instanceof LocalTypeBinding) { - // remember local types binding for innerclass emulation propagation - upperScope.referenceCompilationUnit().record((LocalTypeBinding)this.binding); - } - resolve(); - updateMaxFieldCount(); -} - -/** - * Resolve a top level type declaration - */ -public void resolve(CompilationUnitScope upperScope) { - // top level : scope are already created - resolve(); - updateMaxFieldCount(); -} - -@Override -public void tagAsHavingErrors() { - this.ignoreFurtherInvestigation = true; -} - -@Override -public void tagAsHavingIgnoredMandatoryErrors(int problemId) { - // Nothing to do for this context; -} - -/** - * Iteration for a package member type - */ -public void traverse(ASTVisitor visitor, CompilationUnitScope unitScope) { - try { - if (visitor.visit(this, unitScope)) { - if (this.javadoc != null) { - this.javadoc.traverse(visitor, this.scope); - } - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, this.staticInitializerScope); - } - if (this.superclass != null) - this.superclass.traverse(visitor, this.scope); - if (this.superInterfaces != null) { - int length = this.superInterfaces.length; - for (int i = 0; i < length; i++) - this.superInterfaces[i].traverse(visitor, this.scope); - } - if (this.permittedTypes != null) { - int length = this.permittedTypes.length; - for (int i = 0; i < length; i++) - this.permittedTypes[i].traverse(visitor, this.scope); - } - if (this.typeParameters != null) { - int length = this.typeParameters.length; - for (int i = 0; i < length; i++) { - this.typeParameters[i].traverse(visitor, this.scope); - } - } - if (this.recordComponents != null) { - int length = this.recordComponents.length; - for (int i = 0; i < length; i++) - this.recordComponents[i].traverse(visitor, this.initializerScope); - } - if (this.memberTypes != null) { - int length = this.memberTypes.length; - for (int i = 0; i < length; i++) - this.memberTypes[i].traverse(visitor, this.scope); - } - if (this.fields != null) { - int length = this.fields.length; - for (int i = 0; i < length; i++) { - FieldDeclaration field; - if ((field = this.fields[i]).isStatic()) { - field.traverse(visitor, this.staticInitializerScope); - } else { - field.traverse(visitor, this.initializerScope); - } - } - } - if (this.methods != null) { - int length = this.methods.length; - for (int i = 0; i < length; i++) - this.methods[i].traverse(visitor, this.scope); - } - } - visitor.endVisit(this, unitScope); - } catch (AbortType e) { - // silent abort - } -} - -/** - * Iteration for a local inner type - */ -@Override -public void traverse(ASTVisitor visitor, BlockScope blockScope) { - try { - if (visitor.visit(this, blockScope)) { - if (this.javadoc != null) { - this.javadoc.traverse(visitor, this.scope); - } - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, this.staticInitializerScope); - } - if (this.superclass != null) - this.superclass.traverse(visitor, this.scope); - if (this.superInterfaces != null) { - int length = this.superInterfaces.length; - for (int i = 0; i < length; i++) - this.superInterfaces[i].traverse(visitor, this.scope); - } - if (this.permittedTypes != null) { - int length = this.permittedTypes.length; - for (int i = 0; i < length; i++) - this.permittedTypes[i].traverse(visitor, this.scope); - } - if (this.typeParameters != null) { - int length = this.typeParameters.length; - for (int i = 0; i < length; i++) { - this.typeParameters[i].traverse(visitor, this.scope); - } - } - if (this.recordComponents != null) { - int length = this.recordComponents.length; - for (int i = 0; i < length; i++) - this.recordComponents[i].traverse(visitor, this.initializerScope); - } - if (this.memberTypes != null) { - int length = this.memberTypes.length; - for (int i = 0; i < length; i++) - this.memberTypes[i].traverse(visitor, this.scope); - } - if (this.fields != null) { - int length = this.fields.length; - for (int i = 0; i < length; i++) { - FieldDeclaration field = this.fields[i]; - if (field.isStatic() && !field.isFinal()) { - // local type cannot have static fields that are not final, https://bugs.eclipse.org/bugs/show_bug.cgi?id=244544 - } else { - field.traverse(visitor, this.initializerScope); - } - } - } - if (this.methods != null) { - int length = this.methods.length; - for (int i = 0; i < length; i++) - this.methods[i].traverse(visitor, this.scope); - } - } - visitor.endVisit(this, blockScope); - } catch (AbortType e) { - // silent abort - } -} - -/** - * Iteration for a member innertype - */ -public void traverse(ASTVisitor visitor, ClassScope classScope) { - try { - if (visitor.visit(this, classScope)) { - if (this.javadoc != null) { - this.javadoc.traverse(visitor, this.scope); - } - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, this.staticInitializerScope); - } - if (this.superclass != null) - this.superclass.traverse(visitor, this.scope); - if (this.superInterfaces != null) { - int length = this.superInterfaces.length; - for (int i = 0; i < length; i++) - this.superInterfaces[i].traverse(visitor, this.scope); - } - if (this.permittedTypes != null) { - int length = this.permittedTypes.length; - for (int i = 0; i < length; i++) - this.permittedTypes[i].traverse(visitor, this.scope); - } - if (this.typeParameters != null) { - int length = this.typeParameters.length; - for (int i = 0; i < length; i++) { - this.typeParameters[i].traverse(visitor, this.scope); - } - } - if (this.recordComponents != null) { - int length = this.recordComponents.length; - for (int i = 0; i < length; i++) - this.recordComponents[i].traverse(visitor, this.initializerScope); - } - if (this.memberTypes != null) { - int length = this.memberTypes.length; - for (int i = 0; i < length; i++) - this.memberTypes[i].traverse(visitor, this.scope); - } - if (this.fields != null) { - int length = this.fields.length; - for (int i = 0; i < length; i++) { - FieldDeclaration field; - if ((field = this.fields[i]).isStatic()) { - field.traverse(visitor, this.staticInitializerScope); - } else { - field.traverse(visitor, this.initializerScope); - } - } - } - if (this.methods != null) { - int length = this.methods.length; - for (int i = 0; i < length; i++) - this.methods[i].traverse(visitor, this.scope); - } - } - visitor.endVisit(this, classScope); - } catch (AbortType e) { - // silent abort - } -} - -/** - * MaxFieldCount's computation is necessary so as to reserve space for - * the flow info field portions. It corresponds to the maximum amount of - * fields this class or one of its innertypes have. - * - * During name resolution, types are traversed, and the max field count is recorded - * on the outermost type. It is then propagated down during the flow analysis. - * - * This method is doing either up/down propagation. - */ -void updateMaxFieldCount() { - if (this.binding == null) - return; // error scenario - TypeDeclaration outerMostType = this.scope.outerMostClassScope().referenceType(); - if (this.maxFieldCount > outerMostType.maxFieldCount) { - outerMostType.maxFieldCount = this.maxFieldCount; // up - } else { - this.maxFieldCount = outerMostType.maxFieldCount; // down - } -} - -private SourceTypeBinding findNestHost() { - ClassScope classScope = this.scope.enclosingTopMostClassScope(); - return classScope != null ? classScope.referenceContext.binding : null; -} - -void updateNestHost() { - if (this.binding == null) - return; - SourceTypeBinding nestHost = findNestHost(); - if (nestHost != null && !this.binding.equals(nestHost)) {// member - this.binding.setNestHost(nestHost); - } -} -public boolean isPackageInfo() { - return CharOperation.equals(this.name, TypeConstants.PACKAGE_INFO_NAME); -} -/** - * Returns whether the type is a secondary one or not. - */ -public boolean isSecondary() { - return (this.bits & ASTNode.IsSecondaryType) != 0; -} -public void updateSupertypesWithAnnotations(Map outerUpdates) { - if (this.binding == null) - return; - this.binding.getAnnotationTagBits(); - if (this.binding instanceof MemberTypeBinding) { - ((MemberTypeBinding) this.binding).updateDeprecationFromEnclosing(); - } - Map updates = new HashMap<>(); - if (this.typeParameters != null) { - for (TypeParameter typeParameter : this.typeParameters) { - typeParameter.updateWithAnnotations(this.scope); // TODO: need to integrate with outerUpdates/updates? - } - } - if (this.superclass != null) { - this.binding.superclass = updateWithAnnotations(this.superclass, this.binding.superclass, outerUpdates, updates); - } - if (this.superInterfaces != null) { - ReferenceBinding[] superIfcBindings = this.binding.superInterfaces; - boolean areBindingsConsistent = superIfcBindings != null && superIfcBindings.length == this.superInterfaces.length; - for (int i = 0; i < this.superInterfaces.length; i++) { - ReferenceBinding previous = areBindingsConsistent ? superIfcBindings[i] : null; - ReferenceBinding updated = updateWithAnnotations(this.superInterfaces[i], previous, outerUpdates, updates); - if (areBindingsConsistent) - superIfcBindings[i] = updated; - } - } - if (this.memberTypes != null) { - for (TypeDeclaration memberTypesDecl : this.memberTypes) { - memberTypesDecl.updateSupertypesWithAnnotations(updates); - } - } - if (this.scope.compilerOptions().isAnnotationBasedResourceAnalysisEnabled) { - this.binding.detectWrapperResource(); // needs field an methods built - } -} - -protected ReferenceBinding updateWithAnnotations(TypeReference typeRef, ReferenceBinding previousType, - Map outerUpdates, Map updates) -{ - typeRef.updateWithAnnotations(this.scope, 0); - ReferenceBinding updatedType = (ReferenceBinding) typeRef.resolvedType; - if (updatedType instanceof ParameterizedTypeBinding) { - ParameterizedTypeBinding ptb = (ParameterizedTypeBinding) updatedType; - if (updatedType.enclosingType() != null && outerUpdates.containsKey(ptb.enclosingType())) { - updatedType = this.scope.environment().createParameterizedType(ptb.genericType(), ptb.typeArguments(), outerUpdates.get(ptb.enclosingType())); - } - } - if (updatedType == null || !updatedType.isValidBinding()) - return previousType; - if (previousType != null) { - if (previousType.id == TypeIds.T_JavaLangObject && ((this.binding.tagBits & TagBits.HierarchyHasProblems) != 0)) - return previousType; // keep this cycle breaker - if (previousType != updatedType) //$IDENTITY-COMPARISON$ - updates.put(previousType, updatedType); - } - return updatedType; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java deleted file mode 100644 index 09b37f5..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypeParameter.java +++ /dev/null @@ -1,283 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contributions for - * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 415543 - [1.8][compiler] Incorrect bound index in RuntimeInvisibleTypeAnnotations attribute - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.List; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.AnnotationContext; -import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; -import org.eclipse.jdt.internal.compiler.lookup.MethodScope; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -public class TypeParameter extends AbstractVariableDeclaration { - - public TypeVariableBinding binding; - public TypeReference[] bounds; - - /** - * @see org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration#getKind() - */ - @Override - public int getKind() { - return TYPE_PARAMETER; - } - - public void checkBounds(Scope scope) { - - if (this.type != null) { - this.type.checkBounds(scope); - } - if (this.bounds != null) { - for (int i = 0, length = this.bounds.length; i < length; i++) { - this.bounds[i].checkBounds(scope); - } - } - } - - public void getAllAnnotationContexts(int targetType, int typeParameterIndex, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, typeParameterIndex, allAnnotationContexts); - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(collector, (BlockScope) null); - } - switch(collector.targetType) { - case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER : - collector.targetType = AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER_BOUND; - break; - case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER : - collector.targetType = AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER_BOUND; - } - int boundIndex = 0; - if (this.type != null) { - // boundIndex 0 is always a class - if (this.type.resolvedType.isInterface()) - boundIndex = 1; - if ((this.type.bits & ASTNode.HasTypeAnnotations) != 0) { - collector.info2 = boundIndex; - this.type.traverse(collector, (BlockScope) null); - } - } - if (this.bounds != null) { - int boundsLength = this.bounds.length; - for (int i = 0; i < boundsLength; i++) { - TypeReference bound = this.bounds[i]; - if ((bound.bits & ASTNode.HasTypeAnnotations) == 0) { - continue; - } - collector.info2 = ++boundIndex; - bound.traverse(collector, (BlockScope) null); - } - } - } - private void internalResolve(Scope scope, boolean staticContext) { - // detect variable/type name collisions - if (this.binding != null) { - Binding existingType = scope.parent.getBinding(this.name, Binding.TYPE, this, false/*do not resolve hidden field*/); - if (existingType != null - && this.binding != existingType - && existingType.isValidBinding() - && (existingType.kind() != Binding.TYPE_PARAMETER || !staticContext)) { - scope.problemReporter().typeHiding(this, existingType); - } - } - if (this.annotations != null || scope.environment().usesNullTypeAnnotations()) { - resolveAnnotations(scope); - } - if (CharOperation.equals(this.name, TypeConstants.VAR)) { - if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK10) { - scope.problemReporter().varIsReservedTypeNameInFuture(this); - } else { - scope.problemReporter().varIsNotAllowedHere(this); - } - } - scope.problemReporter().validateRestrictedKeywords(this.name, this); - } - - @Override - public void resolve(BlockScope scope) { - internalResolve(scope, scope.methodScope().isStatic); - } - - public void resolve(ClassScope scope) { - internalResolve(scope, scope.enclosingSourceType().isStatic()); - } - - public void resolveAnnotations(Scope scope) { - if (!TypeReference.hasCompletedHierarchyCheckWithMembers(scope.enclosingReceiverType())) - return; - BlockScope resolutionScope = Scope.typeAnnotationsResolutionScope(scope); - if (resolutionScope != null) { - AnnotationBinding [] annotationBindings = resolveAnnotations(resolutionScope, this.annotations, this.binding, false); - LookupEnvironment environment = scope.environment(); - boolean isAnnotationBasedNullAnalysisEnabled = environment.globalOptions.isAnnotationBasedNullAnalysisEnabled; - if (annotationBindings != null && annotationBindings.length > 0) { - this.binding.setTypeAnnotations(annotationBindings, isAnnotationBasedNullAnalysisEnabled); - scope.referenceCompilationUnit().compilationResult.hasAnnotations = true; - } - if (isAnnotationBasedNullAnalysisEnabled) { - if (this.binding != null && this.binding.isValidBinding()) { - if (scope.hasDefaultNullnessFor(Binding.DefaultLocationTypeParameter, this.sourceStart())) { - if (this.binding.hasNullTypeAnnotations()) { - if ((this.binding.tagBits & TagBits.AnnotationNonNull) != 0) - scope.problemReporter().nullAnnotationIsRedundant(this); - } else { // no explicit type annos, add the default: - TypeVariableBinding previousBinding = this.binding; - this.binding = (TypeVariableBinding) environment.createNonNullAnnotatedType(this.binding); - - if (scope instanceof MethodScope) { - /* - * for method type parameters, references to the bindings have already been copied into - * MethodBinding.typeVariables - update them. - */ - MethodScope methodScope = (MethodScope) scope; - if (methodScope.referenceContext instanceof AbstractMethodDeclaration) { - MethodBinding methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding; - if (methodBinding != null) { - methodBinding.updateTypeVariableBinding(previousBinding, this.binding); - } - } - } - } - } - this.binding.evaluateNullAnnotations(scope, this); - } - } - if (this.binding != null) - this.binding.tagBits |= TagBits.AnnotationResolved; - } - } - - @Override - public StringBuilder printStatement(int indent, StringBuilder output) { - if (this.annotations != null) { - printAnnotations(this.annotations, output); - output.append(' '); - } - output.append(this.name); - if (this.type != null) { - output.append(" extends "); //$NON-NLS-1$ - this.type.print(0, output); - } - if (this.bounds != null){ - for (int i = 0; i < this.bounds.length; i++) { - output.append(" & "); //$NON-NLS-1$ - this.bounds[i].print(0, output); - } - } - return output; - } - - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - // nothing to do - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, scope); - } - if (this.type != null) { - this.type.traverse(visitor, scope); - } - if (this.bounds != null) { - int boundsLength = this.bounds.length; - for (int i = 0; i < boundsLength; i++) { - this.bounds[i].traverse(visitor, scope); - } - } - } - visitor.endVisit(this, scope); - } - - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - int annotationsLength = this.annotations.length; - for (int i = 0; i < annotationsLength; i++) - this.annotations[i].traverse(visitor, scope); - } - if (this.type != null) { - this.type.traverse(visitor, scope); - } - if (this.bounds != null) { - int boundsLength = this.bounds.length; - for (int i = 0; i < boundsLength; i++) { - this.bounds[i].traverse(visitor, scope); - } - } - } - visitor.endVisit(this, scope); - } - - public void updateWithAnnotations(ClassScope scope) { - if (this.binding == null || (this.binding.tagBits & TagBits.AnnotationResolved) != 0) - return; - if (this.type != null) { - TypeBinding prevType = this.type.resolvedType; - this.type.updateWithAnnotations(scope, Binding.DefaultLocationTypeBound); - if (this.type.resolvedType instanceof ReferenceBinding && prevType != this.type.resolvedType) { //$IDENTITY-COMPARISON$ - ReferenceBinding newType = (ReferenceBinding) this.type.resolvedType; - this.binding.firstBound = newType; - if (newType.isClass()) - this.binding.superclass = newType; - } - } - if (this.bounds != null) { - for (int i = 0; i < this.bounds.length; i++) { - TypeReference bound = this.bounds[i]; - TypeBinding prevType = bound.resolvedType; - bound.updateWithAnnotations(scope, Binding.DefaultLocationTypeBound); - if (bound.resolvedType instanceof ReferenceBinding && prevType != bound.resolvedType) { //$IDENTITY-COMPARISON$ - ReferenceBinding newType = (ReferenceBinding) bound.resolvedType; - ReferenceBinding[] superInterfaces = this.binding.superInterfaces; - if (superInterfaces != null) { - for (int j = 0; j < superInterfaces.length; j++) { - if (prevType == superInterfaces[j]) { //$IDENTITY-COMPARISON$ - superInterfaces[j] = newType; - break; - } - } - } - } - } - } - resolveAnnotations(scope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypePattern.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypePattern.java deleted file mode 100644 index f6c1fea..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypePattern.java +++ /dev/null @@ -1,197 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2021, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.codegen.BranchLabel; -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.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.RecordComponentBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TagBits; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeBindingVisitor; -import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; - -public class TypePattern extends Pattern { - - public LocalDeclaration local; - - public TypePattern(LocalDeclaration local) { - this.local = local; - } - protected TypePattern() { - } - @Override - public TypeReference getType() { - return this.local.type; - } - @Override - public LocalVariableBinding[] bindingsWhenTrue() { - return this.local.binding == null ? NO_VARIABLES : new LocalVariableBinding[] { this.local.binding }; - } - @Override - public boolean checkUnsafeCast(Scope scope, TypeBinding castType, TypeBinding expressionType, TypeBinding match, boolean isNarrowing) { - if (!castType.isReifiable()) - return CastExpression.checkUnsafeCast(this, scope, castType, expressionType, match, isNarrowing); - else - return super.checkUnsafeCast(scope, castType, expressionType, match, isNarrowing); - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - flowInfo = this.local.analyseCode(currentScope, flowContext, flowInfo); - FlowInfo patternInfo = flowInfo.copy(); - patternInfo.markAsDefinitelyAssigned(this.local.binding); - if (!this.isTotalTypeNode) { - // non-total type patterns create a nonnull local: - patternInfo.markAsDefinitelyNonNull(this.local.binding); - } else { - // total type patterns inherit the nullness of the value being switched over, unless ... - if (flowContext.associatedNode instanceof SwitchStatement) { - SwitchStatement swStmt = (SwitchStatement) flowContext.associatedNode; - int nullStatus = swStmt.containsNull - ? FlowInfo.NON_NULL // ... null is handled in a separate case - : swStmt.expression.nullStatus(patternInfo, flowContext); - patternInfo.markNullStatus(this.local.binding, nullStatus); - } - } - return patternInfo; - } - @Override - public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel) { - LocalVariableBinding localBinding = this.local.binding; - if (!this.isTotalTypeNode) { - codeStream.checkcast(localBinding.type); - } - this.local.generateCode(currentScope, codeStream); - codeStream.store(localBinding, false); - localBinding.recordInitializationStartPC(codeStream.position); - } - @Override - public LocalDeclaration getPatternVariable() { - return this.local; - } - - @Override - public boolean coversType(TypeBinding type) { - if (type == null || this.resolvedType == null) - return false; - return (type.isSubtypeOf(this.resolvedType, false)); - } - @Override - protected boolean isPatternTypeCompatible(TypeBinding other, BlockScope scope) { - TypeBinding patternType = this.resolvedType; - if (patternType == null) // ill resolved pattern - return false; - if (patternType.isBaseType()) { - if (!TypeBinding.equalsEquals(other, patternType)) { - scope.problemReporter().incompatiblePatternType(this, other, patternType); - return false; - } - } else if (!checkCastTypesCompatibility(scope, other, patternType, null, true)) { - scope.problemReporter().incompatiblePatternType(this, other, patternType); - return false; - } - return true; - } - @Override - public boolean dominates(Pattern p) { - if (p.resolvedType == null || this.resolvedType == null) - return false; - return p.resolvedType.erasure().isSubtypeOf(this.resolvedType.erasure(), false); - } - - @Override - public TypeBinding resolveType(BlockScope scope) { - if (this.resolvedType != null) - return this.resolvedType; // Srikanth, fix reentry - - this.local.modifiers |= ExtraCompilerModifiers.AccOutOfFlowScope; - if (this.local.type == null || this.local.type.isTypeNameVar(scope)) { - /* - * If the LocalVariableType is var then the pattern variable must appear in a pattern list of a - * record pattern with type R. Let T be the type of the corresponding component field in R. The type - * of the pattern variable is the upward projection of T with respect to all synthetic type - * variables mentioned by T. - */ - Pattern enclosingPattern = this.getEnclosingPattern(); - if (enclosingPattern instanceof RecordPattern) { - ReferenceBinding recType = (ReferenceBinding) enclosingPattern.resolvedType; - if (recType != null) { - RecordComponentBinding[] components = recType.components(); - if (components.length > this.index) { - RecordComponentBinding rcb = components[this.index]; - if (rcb.type != null && (rcb.tagBits & TagBits.HasMissingType) != 0) { - scope.problemReporter().invalidType(this, rcb.type); - } - TypeVariableBinding[] mentionedTypeVariables = findSyntheticTypeVariables(rcb.type); - if (mentionedTypeVariables != null && mentionedTypeVariables.length > 0) { - this.local.type.resolvedType = recType.upwardsProjection(scope, - mentionedTypeVariables); - } else { - if (this.local.type != null) - this.local.type.resolvedType = rcb.type; - this.resolvedType = rcb.type; - } - } - } - } - } - this.local.resolve(scope, true); - if (this.local.binding != null) { - this.local.binding.modifiers |= ExtraCompilerModifiers.AccOutOfFlowScope; // start out this way, will be BlockScope.include'd when definitely assigned - this.local.binding.tagBits |= TagBits.IsPatternBinding; - if (this.local.type != null) - this.resolvedType = this.local.binding.type; - } - - return this.resolvedType; - } - // Synthetics? Ref 4.10.5 also watch out for spec changes in rec pattern.. - private TypeVariableBinding[] findSyntheticTypeVariables(TypeBinding typeBinding) { - final Set mentioned = new HashSet<>(); - TypeBindingVisitor.visit(new TypeBindingVisitor() { - @Override - public boolean visit(TypeVariableBinding typeVariable) { - if (typeVariable.isCapture()) - mentioned.add(typeVariable); - return super.visit(typeVariable); - } - }, typeBinding); - if (mentioned.isEmpty()) return null; - return mentioned.toArray(new TypeVariableBinding[mentioned.size()]); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - this.local.traverse(visitor, scope); - } - visitor.endVisit(this, scope); - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - return this.local.printAsExpression(indent, output); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypeReference.java deleted file mode 100644 index 2daaab9..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/TypeReference.java +++ /dev/null @@ -1,871 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2020 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 392099 - [1.8][compiler][null] Apply null annotation on types for null analysis - * bug 392862 - [1.8][compiler][null] Evaluate null annotations on array types - * bug 392384 - [1.8][compiler][null] Restore nullness info from type annotations in class files - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Bug 415850 - [1.8] Ensure RunJDTCoreTests can cope with null annotations enabled - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 427163 - [1.8][null] bogus error "Contradictory null specification" on varags - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - * Bug 434570 - Generic type mismatch for parametrized class annotation attribute with inner class - * Bug 434600 - Incorrect null analysis error reporting on type parameters - * Bug 439516 - [1.8][null] NonNullByDefault wrongly applied to implicit type bound of binary type - * Bug 438458 - [1.8][null] clean up handling of null type annotations wrt type variables - * Bug 435570 - [1.8][null] @NonNullByDefault illegally tries to affect "throws E" - * Bug 435805 - [1.8][compiler][null] Java 8 compiler does not recognize declaration style null annotations - * Bug 437072 - [compiler][null] Null analysis emits possibly incorrect warning for new int[][] despite @NonNullByDefault - * Bug 466713 - Null Annotations: NullPointerException using as Type Param - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 383624 - [1.8][compiler] Revive code generation support for type annotations (from Olivier's work) - * Bug 409236 - [1.8][compiler] Type annotations on intersection cast types dropped by code generator - * Bug 415399 - [1.8][compiler] Type annotations on constructor results dropped by the code generator - * Jesper S Møller - Contributions for - * bug 527554 - [18.3] Compiler support for JEP 286 Local-Variable Type - * bug 529556 - [18.3] Add content assist support for 'var' as a type - * - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching.CheckMode; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.AnnotationContext; -import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; -import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding; -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.Substitution; -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.problem.ProblemSeverities; -@SuppressWarnings({}) -public abstract class TypeReference extends Expression { - public static final TypeReference[] NO_TYPE_ARGUMENTS = new TypeReference[0]; - - /** - * Simplified specification of where in a (possibly complex) type reference - * we are looking for type annotations. - * @see TypeReference#hasNullTypeAnnotation(AnnotationPosition) - */ - public static enum AnnotationPosition { - /** - * For arrays: the outermost dimension, for parameterized types the type, for nested types the innermost type. - * This is the level that a declaration annotation would apply to. - */ - MAIN_TYPE, - /** For arrays: the leaf component type, else like MAIN_TYPE. */ - LEAF_TYPE, - /** Any position admitting type annotations. */ - ANY - } - -static class AnnotationCollector extends ASTVisitor { - List annotationContexts; - Expression typeReference; - int targetType; - int info = 0; - int info2 = 0; - LocalVariableBinding localVariable; - Annotation[][] annotationsOnDimensions; - int dimensions; - Wildcard currentWildcard; - - public AnnotationCollector( - TypeParameter typeParameter, - int targetType, - int typeParameterIndex, - List annotationContexts) { - this.annotationContexts = annotationContexts; - this.typeReference = typeParameter.type; - this.targetType = targetType; - this.info = typeParameterIndex; - } - - public AnnotationCollector( - LocalDeclaration localDeclaration, - int targetType, - LocalVariableBinding localVariable, - List annotationContexts) { - this.annotationContexts = annotationContexts; - this.typeReference = localDeclaration.type; - this.targetType = targetType; - this.localVariable = localVariable; - } - - public AnnotationCollector( - LocalDeclaration localDeclaration, - int targetType, - int parameterIndex, - List annotationContexts) { - this.annotationContexts = annotationContexts; - this.typeReference = localDeclaration.type; - this.targetType = targetType; - this.info = parameterIndex; - } - - public AnnotationCollector( - TypeReference typeReference, - int targetType, - List annotationContexts) { - this.annotationContexts = annotationContexts; - this.typeReference = typeReference; - this.targetType = targetType; - } - public AnnotationCollector( - Expression typeReference, - int targetType, - int info, - List annotationContexts) { - this.annotationContexts = annotationContexts; - this.typeReference = typeReference; - this.info = info; - this.targetType = targetType; - } - public AnnotationCollector( - TypeReference typeReference, - int targetType, - int info, - int typeIndex, - List annotationContexts) { - this.annotationContexts = annotationContexts; - this.typeReference = typeReference; - this.info = info; - this.targetType = targetType; - this.info2 = typeIndex; - } - public AnnotationCollector( - TypeReference typeReference, - int targetType, - int info, - List annotationContexts, - Annotation[][] annotationsOnDimensions, - int dimensions) { - this.annotationContexts = annotationContexts; - this.typeReference = typeReference; - this.info = info; - this.targetType = targetType; - this.annotationsOnDimensions = annotationsOnDimensions; - // Array references like 'new String[]' manifest as an ArrayAllocationExpression - // with a 'type' of String. When the type is not carrying the dimensions count - // it is passed in via the dimensions parameter. It is not possible to use - // annotationsOnDimensions as it will be null if there are no annotations on any - // of the dimensions. - this.dimensions = dimensions; - } - - public AnnotationCollector(RecordComponent recordComponent, int targetType, List annotationContexts) { - this.annotationContexts = annotationContexts; - this.typeReference = recordComponent.type; - this.targetType = targetType; - } - - private boolean targetingTypeParameter() { - return this.targetType == AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER || this.targetType == AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER; - } - - private boolean internalVisit(Annotation annotation) { - AnnotationContext annotationContext = null; - if (annotation.isRuntimeTypeInvisible(targetingTypeParameter())) { - annotationContext = new AnnotationContext(annotation, this.typeReference, this.targetType, AnnotationContext.INVISIBLE); - } else if (annotation.isRuntimeTypeVisible(targetingTypeParameter())) { - annotationContext = new AnnotationContext(annotation, this.typeReference, this.targetType, AnnotationContext.VISIBLE); - } - if (annotationContext != null) { - annotationContext.wildcard = this.currentWildcard; - switch(this.targetType) { - case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER : - case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER : - case AnnotationTargetTypeConstants.CLASS_EXTENDS: - case AnnotationTargetTypeConstants.METHOD_FORMAL_PARAMETER : - case AnnotationTargetTypeConstants.THROWS : - case AnnotationTargetTypeConstants.EXCEPTION_PARAMETER : - case AnnotationTargetTypeConstants.INSTANCEOF: - case AnnotationTargetTypeConstants.NEW : - case AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE : - case AnnotationTargetTypeConstants.METHOD_REFERENCE : - annotationContext.info = this.info; - break; - case AnnotationTargetTypeConstants.LOCAL_VARIABLE : - case AnnotationTargetTypeConstants.RESOURCE_VARIABLE : - annotationContext.variableBinding = this.localVariable; - break; - case AnnotationTargetTypeConstants.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT : - case AnnotationTargetTypeConstants.METHOD_INVOCATION_TYPE_ARGUMENT : - case AnnotationTargetTypeConstants.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT : - case AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT : - case AnnotationTargetTypeConstants.CLASS_TYPE_PARAMETER_BOUND : - case AnnotationTargetTypeConstants.METHOD_TYPE_PARAMETER_BOUND : - case AnnotationTargetTypeConstants.CAST: - annotationContext.info2 = this.info2; - annotationContext.info = this.info; - break; - case AnnotationTargetTypeConstants.FIELD : -// case AnnotationTargetTypeConstants.RECORD_COMPONENT : // value same as FIELD - case AnnotationTargetTypeConstants.METHOD_RETURN : - case AnnotationTargetTypeConstants.METHOD_RECEIVER : - break; - - } - this.annotationContexts.add(annotationContext); - } - return true; - } - @Override - public boolean visit(MarkerAnnotation annotation, BlockScope scope) { - return internalVisit(annotation); - } - @Override - public boolean visit(NormalAnnotation annotation, BlockScope scope) { - return internalVisit(annotation); - } - @Override - public boolean visit(SingleMemberAnnotation annotation, BlockScope scope) { - return internalVisit(annotation); - } - @Override - public boolean visit(Wildcard wildcard, BlockScope scope) { - this.currentWildcard = wildcard; - return true; - } - @Override - public boolean visit(Argument argument, BlockScope scope) { - if ((argument.bits & ASTNode.IsUnionType) == 0) { - return true; - } - for (int i = 0, max = this.localVariable.initializationCount; i < max; i++) { - int startPC = this.localVariable.initializationPCs[i << 1]; - int endPC = this.localVariable.initializationPCs[(i << 1) + 1]; - if (startPC != endPC) { // only entries for non zero length - return true; - } - } - return false; - } - @Override - public boolean visit(Argument argument, ClassScope scope) { - if ((argument.bits & ASTNode.IsUnionType) == 0) { - return true; - } - for (int i = 0, max = this.localVariable.initializationCount; i < max; i++) { - int startPC = this.localVariable.initializationPCs[i << 1]; - int endPC = this.localVariable.initializationPCs[(i << 1) + 1]; - if (startPC != endPC) { // only entries for non zero length - return true; - } - } - return false; - } - @Override - public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) { - for (int i = 0, max = this.localVariable.initializationCount; i < max; i++) { - int startPC = this.localVariable.initializationPCs[i << 1]; - int endPC = this.localVariable.initializationPCs[(i << 1) + 1]; - if (startPC != endPC) { // only entries for non zero length - return true; - } - } - return false; - } - @Override - public boolean visit(TypeParameter typeParameter, BlockScope scope) { - // never implicitly traverse type parameters - // their annotations are explicitly handled in TypeParameter.getAllAnnotationContexts(int, int, List) - return false; - } - @Override - public void endVisit(Wildcard wildcard, BlockScope scope) { - this.currentWildcard = null; - } -} -/* - * Answer a base type reference (can be an array of base type). - */ -public static final TypeReference baseTypeReference(int baseType, int dim, Annotation [][] dimAnnotations) { - - if (dim == 0) { - switch (baseType) { - case (TypeIds.T_void) : - return new SingleTypeReference(TypeBinding.VOID.simpleName, 0); - case (TypeIds.T_boolean) : - return new SingleTypeReference(TypeBinding.BOOLEAN.simpleName, 0); - case (TypeIds.T_char) : - return new SingleTypeReference(TypeBinding.CHAR.simpleName, 0); - case (TypeIds.T_float) : - return new SingleTypeReference(TypeBinding.FLOAT.simpleName, 0); - case (TypeIds.T_double) : - return new SingleTypeReference(TypeBinding.DOUBLE.simpleName, 0); - case (TypeIds.T_byte) : - return new SingleTypeReference(TypeBinding.BYTE.simpleName, 0); - case (TypeIds.T_short) : - return new SingleTypeReference(TypeBinding.SHORT.simpleName, 0); - case (TypeIds.T_int) : - return new SingleTypeReference(TypeBinding.INT.simpleName, 0); - default : //T_long - return new SingleTypeReference(TypeBinding.LONG.simpleName, 0); - } - } - switch (baseType) { - case (TypeIds.T_void) : - return new ArrayTypeReference(TypeBinding.VOID.simpleName, dim, dimAnnotations, 0); - case (TypeIds.T_boolean) : - return new ArrayTypeReference(TypeBinding.BOOLEAN.simpleName, dim, dimAnnotations, 0); - case (TypeIds.T_char) : - return new ArrayTypeReference(TypeBinding.CHAR.simpleName, dim, dimAnnotations, 0); - case (TypeIds.T_float) : - return new ArrayTypeReference(TypeBinding.FLOAT.simpleName, dim, dimAnnotations, 0); - case (TypeIds.T_double) : - return new ArrayTypeReference(TypeBinding.DOUBLE.simpleName, dim, dimAnnotations, 0); - case (TypeIds.T_byte) : - return new ArrayTypeReference(TypeBinding.BYTE.simpleName, dim, dimAnnotations, 0); - case (TypeIds.T_short) : - return new ArrayTypeReference(TypeBinding.SHORT.simpleName, dim, dimAnnotations, 0); - case (TypeIds.T_int) : - return new ArrayTypeReference(TypeBinding.INT.simpleName, dim, dimAnnotations, 0); - default : //T_long - return new ArrayTypeReference(TypeBinding.LONG.simpleName, dim, dimAnnotations, 0); - } -} - -public static final TypeReference baseTypeReference(int baseType, int dim) { - return baseTypeReference(baseType, dim, null); -} - -// JSR308 type annotations... -public Annotation[][] annotations = null; - -// allows us to trap completion & selection nodes -public void aboutToResolve(Scope scope) { - // default implementation: do nothing -} -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - return flowInfo; -} -public void checkBounds(Scope scope) { - // only parameterized type references have bounds -} -public abstract TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs); - -protected Annotation[][] getMergedAnnotationsOnDimensions(int additionalDimensions, Annotation[][] additionalAnnotations) { - /* Note, we actually concatenate the additional annotations after base annotations, in bindings, they should appear before base annotations. - Given @English int @Nullable [] x @NonNull []; the type x is a @NonNull arrays of of @Nullable arrays of @English Strings, not the other - way about. Changing this in the compiler AST representation will cause too many ripples, so we leave it as is. On the bindings, the type - will reflect rotated (i.e will reflect correctly). See AnnotatableTypeSystem.flattenedAnnotations - */ - Annotation[][] annotationsOnDimensions = this.getAnnotationsOnDimensions(true); - int dimensions = this.dimensions(); - - if (annotationsOnDimensions == null && additionalAnnotations == null) - return null; - - final int totalDimensions = dimensions + additionalDimensions; - Annotation [][] mergedAnnotations = new Annotation[totalDimensions][]; - if (annotationsOnDimensions != null) { - System.arraycopy(annotationsOnDimensions, 0, mergedAnnotations, 0, dimensions); - } - if (additionalAnnotations != null) { - for (int i = dimensions, j = 0; i < totalDimensions; i++, j++) { - mergedAnnotations[i] = additionalAnnotations[j]; - } - } - return mergedAnnotations; -} - -public int dimensions() { - return 0; -} - - -/** - * This method is used to return the array dimension declared after the - * name of a local or a field declaration. - * For example: - * int i, j[] = null, k[][] = {{}}; - * It should return 0 for i, 1 for j and 2 for k. - * @return int the extra dimension found - */ -public int extraDimensions() { - return 0; -} - -public AnnotationContext[] getAllAnnotationContexts(int targetType) { - List allAnnotationContexts = new ArrayList<>(); - AnnotationCollector collector = new AnnotationCollector(this, targetType, allAnnotationContexts); - this.traverse(collector, (BlockScope) null); - return allAnnotationContexts.toArray(new AnnotationContext[allAnnotationContexts.size()]); -} -/** - * info can be either a type index (superclass/superinterfaces) or a pc into the bytecode - */ -public void getAllAnnotationContexts(int targetType, int info, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, info, allAnnotationContexts); - this.traverse(collector, (BlockScope) null); -} -public void getAllAnnotationContexts(int targetType, int info, List allAnnotationContexts, Annotation [] se7Annotations) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, info, allAnnotationContexts); - for (int i = 0, length = se7Annotations == null ? 0 : se7Annotations.length; i < length; i++) { - Annotation annotation = se7Annotations[i]; - annotation.traverse(collector, (BlockScope) null); - } - this.traverse(collector, (BlockScope) null); -} -/** - * info can be either a type index (superclass/superinterfaces) or a pc into the bytecode - */ -public void getAllAnnotationContexts(int targetType, int info, List allAnnotationContexts, Annotation[][] annotationsOnDimensions, int dimensions) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, info, allAnnotationContexts, annotationsOnDimensions, dimensions); - this.traverse(collector, (BlockScope) null); - if (annotationsOnDimensions != null) { - for (int i = 0, max = annotationsOnDimensions.length; i < max; i++) { - Annotation[] annotationsOnDimension = annotationsOnDimensions[i]; - if (annotationsOnDimension != null) { - for (int j = 0, max2 = annotationsOnDimension.length; j< max2; j++) { - annotationsOnDimension[j].traverse(collector, (BlockScope) null); - } - } - } - } -} -public void getAllAnnotationContexts(int targetType, int info, int typeIndex, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, info, typeIndex, allAnnotationContexts); - this.traverse(collector, (BlockScope) null); -} -public void getAllAnnotationContexts(int targetType, List allAnnotationContexts) { - AnnotationCollector collector = new AnnotationCollector(this, targetType, allAnnotationContexts); - this.traverse(collector, (BlockScope) null); -} -public Annotation[][] getAnnotationsOnDimensions() { - return getAnnotationsOnDimensions(false); -} - -public TypeReference [][] getTypeArguments() { - return null; -} -/** - * @param useSourceOrder if true annotations on dimensions are returned in source order, otherwise they are returned per - * how they ought to be interpreted by a type system, or external persistence view. For example, given the following: - * int @Nullable [] f @NonNull [] ==> f is really a @NonNull array of @Nullable arrays of ints. This is the type system - * view since extended dimensions bind more readily than type components that precede the identifier. This is how it ought - * to be encoded in bindings and how it ought to be persisted in class files. However for DOM/AST construction, we need the - * dimensions in source order, so we provide a way for the clients to ask what they want. - */ -public Annotation[][] getAnnotationsOnDimensions(boolean useSourceOrder) { - return null; -} - -public void setAnnotationsOnDimensions(Annotation [][] annotationsOnDimensions) { - // nothing to do. Subtypes should react suitably. -} - -public abstract char[] getLastToken(); - -/** - * @return char[][] - * TODO (jerome) should merge back into #getTypeName() - */ -public char [][] getParameterizedTypeName(){ - return getTypeName(); -} -protected abstract TypeBinding getTypeBinding(Scope scope); -/** - * @return char[][] - */ -public abstract char [][] getTypeName() ; - -protected TypeBinding internalResolveType(Scope scope, int location) { - // handle the error here - this.constant = Constant.NotAConstant; - if (this.resolvedType != null) { // is a shared type reference which was already resolved - if (this.resolvedType.isValidBinding()) { - return this.resolvedType; - } else { - switch (this.resolvedType.problemId()) { - case ProblemReasons.NotFound : - case ProblemReasons.NotVisible : - case ProblemReasons.InheritedNameHidesEnclosingName : - TypeBinding type = this.resolvedType.closestMatch(); - if (type == null) return null; - return scope.environment().convertToRawType(type, false /*do not force conversion of enclosing types*/); - default : - return null; - } - } - } - boolean hasError = false; - TypeBinding type = this.resolvedType = getTypeBinding(scope); - if (type == null) { - return null; // detected cycle while resolving hierarchy - } else if ((hasError = !type.isValidBinding()) == true) { - if (this.isTypeNameVar(scope)) { - reportVarIsNotAllowedHere(scope); - } else if (!scope.problemReporter().validateRestrictedKeywords(getLastToken(), this)) { - reportInvalidType(scope); - } - switch (type.problemId()) { - case ProblemReasons.NotFound : - case ProblemReasons.NotVisible : - case ProblemReasons.InheritedNameHidesEnclosingName : - type = type.closestMatch(); - if (type == null) return null; - break; - default : - return null; - } - } else { // check anyway - to cover a illegally declared "permits" type - scope.problemReporter().validateRestrictedKeywords(getLastToken(), this); - } - if (type.isArrayType() && ((ArrayBinding) type).leafComponentType == TypeBinding.VOID) { - scope.problemReporter().cannotAllocateVoidArray(this); - return null; - } - if (!(this instanceof QualifiedTypeReference) // QualifiedTypeReference#getTypeBinding called above will have already checked deprecation - && isTypeUseDeprecated(type, scope)) { - reportDeprecatedType(type, scope); - } - type = scope.environment().convertToRawType(type, false /*do not force conversion of enclosing types*/); - if (type.leafComponentType().isRawType() - && (this.bits & ASTNode.IgnoreRawTypeCheck) == 0 - && scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) { - scope.problemReporter().rawTypeReference(this, type); - } - if (hasError) { - resolveAnnotations(scope, 0); // don't apply null defaults to buggy type - return type; - } else { - // store the computed type only if no error, otherwise keep the problem type instead - this.resolvedType = type; - resolveAnnotations(scope, location); - return this.resolvedType; // pick up value that may have been changed in resolveAnnotations(..) - } -} -@Override -public boolean isTypeReference() { - return true; -} -public boolean isWildcard() { - return false; -} -public boolean isUnionType() { - return false; -} -public boolean isVarargs() { - return (this.bits & ASTNode.IsVarArgs) != 0; -} -public boolean isParameterizedTypeReference() { - return false; -} -protected void reportDeprecatedType(TypeBinding type, Scope scope, int index) { - scope.problemReporter().deprecatedType(type, this, index); -} - -protected void reportDeprecatedType(TypeBinding type, Scope scope) { - scope.problemReporter().deprecatedType(type, this, Integer.MAX_VALUE); -} - -protected void reportInvalidType(Scope scope) { - scope.problemReporter().invalidType(this, this.resolvedType); -} - -protected void reportVarIsNotAllowedHere(Scope scope) { - scope.problemReporter().varIsNotAllowedHere(this); -} - -public TypeBinding resolveSuperType(ClassScope scope) { - // assumes the implementation of resolveType(ClassScope) will call back to detect cycles - TypeBinding superType = resolveType(scope); - if (superType == null) return null; - - if (superType.isTypeVariable()) { - if (this.resolvedType.isValidBinding()) { - this.resolvedType = new ProblemReferenceBinding(getTypeName(), (ReferenceBinding)this.resolvedType, ProblemReasons.IllegalSuperTypeVariable); - reportInvalidType(scope); - } - return null; - } - return superType; -} - -@Override -public final TypeBinding resolveType(BlockScope blockScope) { - return resolveType(blockScope, true /* checkbounds if any */); -} - -public TypeBinding resolveType(BlockScope scope, boolean checkBounds) { - return resolveType(scope, checkBounds, 0); -} - -public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) { - return internalResolveType(scope, location); -} - -@Override -public TypeBinding resolveType(ClassScope scope) { - return resolveType(scope, 0); -} - -public TypeBinding resolveType(ClassScope scope, int location) { - return internalResolveType(scope, location); -} - -public TypeBinding resolveTypeArgument(BlockScope blockScope, ReferenceBinding genericType, int rank) { - return resolveType(blockScope, true /* check bounds*/, Binding.DefaultLocationTypeArgument); -} - -public TypeBinding resolveTypeArgument(ClassScope classScope, ReferenceBinding genericType, int rank) { - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=294057, circularity is allowed when we are - // resolving type arguments i.e interface A {} interface B extends A {} - // interface D extends C {} interface C extends B {} - ReferenceBinding ref = classScope.referenceContext.binding; - boolean pauseHierarchyCheck = false; - try { - if (ref.isHierarchyBeingConnected()) { - pauseHierarchyCheck = (ref.tagBits & TagBits.PauseHierarchyCheck) == 0; - ref.tagBits |= TagBits.PauseHierarchyCheck; - } - return resolveType(classScope, Binding.DefaultLocationTypeArgument); - } finally { - if (pauseHierarchyCheck) { - ref.tagBits &= ~TagBits.PauseHierarchyCheck; - } - } -} - -@Override -public abstract void traverse(ASTVisitor visitor, BlockScope scope); - -@Override -public abstract void traverse(ASTVisitor visitor, ClassScope scope); - -public void updateWithAnnotations(Scope scope, int location) { - // resolving annotations now is needed and safe because during connectTypeHierarchy() - // resolving via internalResolveType() we had readyForAnnotations = false. - resolveAnnotations(scope, location); -} -/* shared part of Parameterized{Single,Qualified}TypeReference: */ -protected TypeBinding updateParameterizedTypeWithAnnotations(Scope scope, TypeBinding type, TypeReference[] argRefs) { - if (argRefs != null) { - for (TypeReference argRef : argRefs) { - argRef.updateWithAnnotations(scope, Binding.DefaultLocationTypeArgument); - } - if (type instanceof ParameterizedTypeBinding) { - ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) type; - TypeBinding[] argumentBindings = parameterizedType.arguments; - TypeBinding[] updatedArgs = null; - if (argumentBindings.length == argRefs.length) { - for (int i = 0; i < argRefs.length; i++) { - TypeReference argRef = argRefs[i]; - TypeBinding argBinding = argumentBindings[i]; - if (argRef.resolvedType != null && argRef.resolvedType.isValidBinding() && argRef.resolvedType != argBinding) { //$IDENTITY-COMPARISON$ - if (updatedArgs == null) - updatedArgs = Arrays.copyOf(argumentBindings, argumentBindings.length); - updatedArgs[i] = argRef.resolvedType; - } - } - } - if (updatedArgs != null) { - return scope.environment().createParameterizedType(parameterizedType.genericType(), updatedArgs, parameterizedType.enclosingType()); - } - } - } - return type; -} - -protected void resolveAnnotations(Scope scope, int location) { - if (!hasCompletedHierarchyCheckWithMembers(scope.enclosingReceiverType())) - return; - Annotation[][] annotationsOnDimensions = getAnnotationsOnDimensions(); - if (this.annotations != null || annotationsOnDimensions != null) { - BlockScope resolutionScope = Scope.typeAnnotationsResolutionScope(scope); - if (resolutionScope != null) { - int dimensions = this.dimensions(); - if (this.annotations != null) { - TypeBinding leafComponentType = this.resolvedType.leafComponentType(); - leafComponentType = resolveAnnotations(resolutionScope, this.annotations, leafComponentType); - this.resolvedType = dimensions > 0 ? scope.environment().createArrayType(leafComponentType, dimensions) : leafComponentType; - // contradictory null annotations on the type are already detected in Annotation.resolveType() (SE7 treatment) - } - if (annotationsOnDimensions != null) { - this.resolvedType = resolveAnnotations(resolutionScope, annotationsOnDimensions, this.resolvedType); - if (this.resolvedType instanceof ArrayBinding) { - long[] nullTagBitsPerDimension = ((ArrayBinding)this.resolvedType).nullTagBitsPerDimension; - if (nullTagBitsPerDimension != null) { - for (int i = 0; i < dimensions; i++) { // skip last annotations at [dimensions] (concerns the leaf type) - long nullTagBits = nullTagBitsPerDimension[i] & TagBits.AnnotationNullMASK; - if (nullTagBits == TagBits.AnnotationNullMASK) { - scope.problemReporter().contradictoryNullAnnotations(annotationsOnDimensions[i]); - nullTagBitsPerDimension[i] = 0; - } else if (nullTagBits == TagBits.AnnotationNonNull) { - if (scope.hasDefaultNullnessFor(Binding.DefaultLocationArrayContents, this.sourceStart)) - scope.problemReporter().nullAnnotationIsRedundant(this, annotationsOnDimensions[i]); - } - } - } - } - } - } - } - if (scope.compilerOptions().isAnnotationBasedNullAnalysisEnabled - && this.resolvedType != null - && !this.resolvedType.isTypeVariable() - && !this.resolvedType.isWildcard() - && location != 0 - && scope.hasDefaultNullnessForType(this.resolvedType, location, this.sourceStart)) - { - long nullTagBits = this.resolvedType.tagBits & TagBits.AnnotationNullMASK; - if (nullTagBits == 0) { - if (location == Binding.DefaultLocationTypeBound && this.resolvedType.id == TypeIds.T_JavaLangObject) { - scope.problemReporter().implicitObjectBoundNoNullDefault(this); - } else { - this.resolvedType = scope.environment().createNonNullAnnotatedType(this.resolvedType); - } - } else if (nullTagBits == TagBits.AnnotationNonNull) { - if (location != Binding.DefaultLocationParameter) { // parameters are handled in MethodBinding.fillInDefaultNonNullness18() - scope.problemReporter().nullAnnotationIsRedundant(this, getTopAnnotations()); - } - } - } -} - -protected static boolean hasCompletedHierarchyCheckWithMembers(TypeBinding type) { - if (type != null && (type.original() instanceof SourceTypeBinding stb)) { - if ((stb.tagBits & TagBits.EndHierarchyCheck) == 0) { - return false; - } - ReferenceBinding[] memberTypes = stb.memberTypes; - if (memberTypes != null) { - for (ReferenceBinding member : memberTypes) { - if (!hasCompletedHierarchyCheckWithMembers(member)) - return false; - } - } - } - return true; -} - -public Annotation[] getTopAnnotations() { - if (this.annotations != null) - return this.annotations[getAnnotatableLevels()-1]; - return new Annotation[0]; -} - -public int getAnnotatableLevels() { - return 1; -} -/** Check all typeArguments for illegal null annotations on base types. */ -protected void checkIllegalNullAnnotations(Scope scope, TypeReference[] typeArguments) { - if (scope.environment().usesNullTypeAnnotations() && typeArguments != null) { - for (int i = 0; i < typeArguments.length; i++) { - TypeReference arg = typeArguments[i]; - if (arg.resolvedType != null) - arg.checkIllegalNullAnnotation(scope); - } - } -} -/** Check whether this type reference conforms to the null constraints defined for the corresponding type variable. */ -protected void checkNullConstraints(Scope scope, Substitution substitution, TypeBinding[] variables, int rank) { - if (variables != null && variables.length > rank) { - TypeBinding variable = variables[rank]; - if (variable.hasNullTypeAnnotations()) { - if (NullAnnotationMatching.analyse(variable, this.resolvedType, null, substitution, -1, null, CheckMode.BOUND_CHECK).isAnyMismatch()) - scope.problemReporter().nullityMismatchTypeArgument(variable, this.resolvedType, this); - } - } - checkIllegalNullAnnotation(scope); -} -protected void checkIllegalNullAnnotation(Scope scope) { - if (this.resolvedType.leafComponentType().isBaseType() && hasNullTypeAnnotation(AnnotationPosition.LEAF_TYPE)) - scope.problemReporter().illegalAnnotationForBaseType(this, this.annotations[0], this.resolvedType.tagBits & TagBits.AnnotationNullMASK); -} -/** Retrieve the null annotation that has been translated to the given nullTagBits. */ -public Annotation findAnnotation(long nullTagBits) { - if (this.annotations != null) { - Annotation[] innerAnnotations = this.annotations[this.annotations.length-1]; - if (innerAnnotations != null) { - int annBit = nullTagBits == TagBits.AnnotationNonNull ? TypeIds.BitNonNullAnnotation : TypeIds.BitNullableAnnotation; - for (int i = 0; i < innerAnnotations.length; i++) { - if (innerAnnotations[i] != null && innerAnnotations[i].hasNullBit(annBit)) - return innerAnnotations[i]; - } - } - } - return null; -} -public boolean hasNullTypeAnnotation(AnnotationPosition position) { - if (this.annotations != null) { - if (position == AnnotationPosition.MAIN_TYPE) { - Annotation[] innerAnnotations = this.annotations[this.annotations.length-1]; - return containsNullAnnotation(innerAnnotations); - } else { - for (Annotation[] someAnnotations: this.annotations) { - if (containsNullAnnotation(someAnnotations)) - return true; - } - } - } - return false; -} -public static boolean containsNullAnnotation(Annotation[] annotations) { - if (annotations != null) { - for (int i = 0; i < annotations.length; i++) { - if (annotations[i] != null && (annotations[i].hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation))) - return true; - } - } - return false; -} -public TypeReference[] getTypeReferences() { - return new TypeReference [] { this }; -} - -public boolean isBaseTypeReference() { - return false; -} -private char[] getTypeName(int index) { - char[][] typeName = this.getTypeName(); - return typeName != null && typeName.length > index ? typeName[index] : - CharOperation.NO_CHAR; -} -/** - * Checks to see if the declaration uses 'var' as type name - * @param scope Relevant scope, for error reporting - * @return true, if source level is Java 10 or above and the type name is just 'var', false otherwise - */ -public boolean isTypeNameVar(Scope scope) { - CompilerOptions compilerOptions = scope != null ? scope.compilerOptions() : null; - if (compilerOptions != null && compilerOptions.sourceLevel < ClassFileConstants.JDK10) { - return false; - } - return CharOperation.equals(getTypeName(0), TypeConstants.VAR); -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java deleted file mode 100644 index 75d60d0..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UnaryExpression.java +++ /dev/null @@ -1,350 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * bug 383368 - [compiler][null] syntactic null analysis for field references - * bug 403086 - [compiler][null] include the effect of 'assert' in syntactic null analysis for fields - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class UnaryExpression extends OperatorExpression { - - public Expression expression; - public Constant optimizedBooleanConstant; - - public UnaryExpression(Expression expression, int operator) { - this.expression = expression; - this.bits |= operator << OperatorSHIFT; // encode operator - } - - @Override - public FlowInfo analyseCode( - BlockScope currentScope, - FlowContext flowContext, - FlowInfo flowInfo) { - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { - flowContext.tagBits ^= FlowContext.INSIDE_NEGATION; - flowInfo = this.expression. - analyseCode(currentScope, flowContext, flowInfo). - asNegatedCondition(); - flowContext.tagBits ^= FlowContext.INSIDE_NEGATION; - } else { - flowInfo = this.expression. - analyseCode(currentScope, flowContext, flowInfo); - } - this.expression.checkNPE(currentScope, flowContext, flowInfo); - return flowInfo; - } - - @Override - protected void updateFlowOnBooleanResult(FlowInfo flowInfo, boolean result) { - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) - this.expression.updateFlowOnBooleanResult(flowInfo, !result); - } - - @Override - public Constant optimizedBooleanConstant() { - - return this.optimizedBooleanConstant == null - ? this.constant - : this.optimizedBooleanConstant; - } - - /** - * Code generation for an unary operation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - * @param valueRequired boolean - */ - @Override - public void generateCode( - BlockScope currentScope, - CodeStream codeStream, - boolean valueRequired) { - - int pc = codeStream.position; - BranchLabel falseLabel, endifLabel; - if (this.constant != Constant.NotAConstant) { - // inlined value - if (valueRequired) { - codeStream.generateConstant(this.constant, this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - switch ((this.bits & OperatorMASK) >> OperatorSHIFT) { - case NOT : - switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) /* runtime type */ { - case T_boolean : - // ! - // Generate code for the condition - this.expression.generateOptimizedBoolean( - currentScope, - codeStream, - null, - (falseLabel = new BranchLabel(codeStream)), - valueRequired); - if (valueRequired) { - codeStream.iconst_0(); - if (falseLabel.forwardReferenceCount() > 0) { - codeStream.goto_(endifLabel = new BranchLabel(codeStream)); - codeStream.decrStackSize(1); - falseLabel.place(); - codeStream.iconst_1(); - endifLabel.place(); - } - } else { // 6596: if (!(a && b)){} - must still place falseLabel - falseLabel.place(); - } - break; - } - break; - case TWIDDLE : - switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4 /* runtime */) { - case T_int : - // ~int - this.expression.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.iconst_m1(); - codeStream.ixor(); - } - break; - case T_long : - this.expression.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - codeStream.ldc2_w(-1L); - codeStream.lxor(); - } - } - break; - case MINUS : - // - - if (this.constant != Constant.NotAConstant) { - if (valueRequired) { - switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4){ /* runtime */ - case T_int : - codeStream.generateInlinedValue(this.constant.intValue() * -1); - break; - case T_float : - codeStream.generateInlinedValue(this.constant.floatValue() * -1.0f); - break; - case T_long : - codeStream.generateInlinedValue(this.constant.longValue() * -1L); - break; - case T_double : - codeStream.generateInlinedValue(this.constant.doubleValue() * -1.0); - } - } - } else { - this.expression.generateCode(currentScope, codeStream, valueRequired); - if (valueRequired) { - switch ((this.expression.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4){ /* runtime type */ - case T_int : - codeStream.ineg(); - break; - case T_float : - codeStream.fneg(); - break; - case T_long : - codeStream.lneg(); - break; - case T_double : - codeStream.dneg(); - } - } - } - break; - case PLUS : - this.expression.generateCode(currentScope, codeStream, valueRequired); - } - if (valueRequired) { - codeStream.generateImplicitConversion(this.implicitConversion); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - /** - * Boolean operator code generation - * Optimized operations are: {@code &&, ||, <, <=, >, >=, &, |, ^ } - */ - @Override - public void generateOptimizedBoolean( - BlockScope currentScope, - CodeStream codeStream, - BranchLabel trueLabel, - BranchLabel falseLabel, - boolean valueRequired) { - - if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == T_boolean)) { - super.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - return; - } - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { - this.expression.generateOptimizedBoolean( - currentScope, - codeStream, - falseLabel, - trueLabel, - valueRequired); - } else { - super.generateOptimizedBoolean( - currentScope, - codeStream, - trueLabel, - falseLabel, - valueRequired); - } - } - - @Override - public StringBuilder printExpressionNoParenthesis(int indent, StringBuilder output) { - - output.append(operatorToString()).append(' '); - return this.expression.printExpression(0, output); - } - @Override - public TypeBinding resolveType(BlockScope scope) { - boolean expressionIsCast; - if ((expressionIsCast = this.expression instanceof CastExpression) == true) this.expression.bits |= DisableUnnecessaryCastCheck; // will check later on - TypeBinding expressionType = this.expression.resolveType(scope); - if (expressionType == null) { - this.constant = Constant.NotAConstant; - return null; - } - int expressionTypeID = expressionType.id; - // autoboxing support - boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5; - if (use15specifics) { - if (!expressionType.isBaseType()) { - expressionTypeID = scope.environment().computeBoxingType(expressionType).id; - } - } - if (expressionTypeID > 15) { - this.constant = Constant.NotAConstant; - scope.problemReporter().invalidOperator(this, expressionType); - return null; - } - - int tableId; - switch ((this.bits & OperatorMASK) >> OperatorSHIFT) { - case NOT : - tableId = AND_AND; - break; - case TWIDDLE : - tableId = LEFT_SHIFT; - break; - default : - tableId = MINUS; - } //+ and - cases - - // the code is an int - // (cast) left Op (cast) rigth --> result - // 0000 0000 0000 0000 0000 - // <<16 <<12 <<8 <<4 <<0 - int operatorSignature = OperatorSignatures[tableId][(expressionTypeID << 4) + expressionTypeID]; - this.expression.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), expressionType); - this.bits |= operatorSignature & 0xF; - switch (operatorSignature & 0xF) { // only switch on possible result type..... - case T_boolean : - this.resolvedType = TypeBinding.BOOLEAN; - break; - case T_byte : - this.resolvedType = TypeBinding.BYTE; - break; - case T_char : - this.resolvedType = TypeBinding.CHAR; - break; - case T_double : - this.resolvedType = TypeBinding.DOUBLE; - break; - case T_float : - this.resolvedType = TypeBinding.FLOAT; - break; - case T_int : - this.resolvedType = TypeBinding.INT; - break; - case T_long : - this.resolvedType = TypeBinding.LONG; - break; - default : //error........ - this.constant = Constant.NotAConstant; - if (expressionTypeID != T_undefined) - scope.problemReporter().invalidOperator(this, expressionType); - return null; - } - // compute the constant when valid - if (this.expression.constant != Constant.NotAConstant) { - this.constant = - Constant.computeConstantOperation( - this.expression.constant, - expressionTypeID, - (this.bits & OperatorMASK) >> OperatorSHIFT); - } else { - this.constant = Constant.NotAConstant; - if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT) { - Constant cst = this.expression.optimizedBooleanConstant(); - if (cst != Constant.NotAConstant) - this.optimizedBooleanConstant = BooleanConstant.fromValue(!cst.booleanValue()); - } - } - if (expressionIsCast) { - // check need for operand cast - CastExpression.checkNeedForArgumentCast(scope, tableId, operatorSignature, this.expression, expressionTypeID); - } - return this.resolvedType; - } - @Override - public boolean containsPatternVariable() { - return this.expression.containsPatternVariable(); - } - @Override - public LocalDeclaration getPatternVariable() { - return this.expression.getPatternVariable(); - } - - @Override - public LocalVariableBinding[] bindingsWhenFalse() { - return ((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT ? - this.expression.bindingsWhenTrue(): NO_VARIABLES; - } - - @Override - public LocalVariableBinding[] bindingsWhenTrue() { - return ((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT ? - this.expression.bindingsWhenFalse(): NO_VARIABLES; - } - - - @Override - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.expression.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java deleted file mode 100644 index cfe054c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UnionTypeReference.java +++ /dev/null @@ -1,154 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011, 2014 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.Binding; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ClassScope; -import org.eclipse.jdt.internal.compiler.lookup.Scope; -import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -public class UnionTypeReference extends TypeReference { - public TypeReference[] typeReferences; - - public UnionTypeReference(TypeReference[] typeReferences) { - this.bits |= ASTNode.IsUnionType; - this.typeReferences = typeReferences; - this.sourceStart = typeReferences[0].sourceStart; - int length = typeReferences.length; - this.sourceEnd = typeReferences[length - 1].sourceEnd; - } - - @Override - public char[] getLastToken() { - return null; - } - - /** - * @see org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference#getTypeBinding(org.eclipse.jdt.internal.compiler.lookup.Scope) - */ - @Override - protected TypeBinding getTypeBinding(Scope scope) { - return null; // not supported here - combined with resolveType(...) - } - - @Override - public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) { - // return the lub (least upper bound of all type binding) - int length = this.typeReferences.length; - TypeBinding[] allExceptionTypes = new TypeBinding[length]; - boolean hasError = false; - for (int i = 0; i < length; i++) { - TypeBinding exceptionType = this.typeReferences[i].resolveType(scope, checkBounds, location); - if (exceptionType == null) { - return null; - } - switch(exceptionType.kind()) { - case Binding.PARAMETERIZED_TYPE : - if (exceptionType.isBoundParameterizedType()) { - hasError = true; - scope.problemReporter().invalidParameterizedExceptionType(exceptionType, this.typeReferences[i]); - // fall thru to create the variable - avoids additional errors because the variable is missing - } - break; - case Binding.TYPE_PARAMETER : - scope.problemReporter().invalidTypeVariableAsException(exceptionType, this.typeReferences[i]); - hasError = true; - // fall thru to create the variable - avoids additional errors because the variable is missing - break; - } - if (exceptionType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) == null - && exceptionType.isValidBinding()) { - scope.problemReporter().cannotThrowType(this.typeReferences[i], exceptionType); - hasError = true; - } - allExceptionTypes[i] = exceptionType; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=340486, ensure types are of union type. - for (int j = 0; j < i; j++) { - if (allExceptionTypes[j].isCompatibleWith(exceptionType)) { - scope.problemReporter().wrongSequenceOfExceptionTypes( - this.typeReferences[j], - allExceptionTypes[j], - exceptionType); - hasError = true; - } else if (exceptionType.isCompatibleWith(allExceptionTypes[j])) { - scope.problemReporter().wrongSequenceOfExceptionTypes( - this.typeReferences[i], - exceptionType, - allExceptionTypes[j]); - hasError = true; - } - } - } - if (hasError) { - return null; - } - // compute lub - return (this.resolvedType = scope.lowerUpperBound(allExceptionTypes)); - } - - @Override - public char[][] getTypeName() { - // we need to keep a return value that is a char[][] - return this.typeReferences[0].getTypeName(); - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - int length = this.typeReferences == null ? 0 : this.typeReferences.length; - for (int i = 0; i < length; i++) { - this.typeReferences[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - int length = this.typeReferences == null ? 0 : this.typeReferences.length; - for (int i = 0; i < length; i++) { - this.typeReferences[i].traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output) { - int length = this.typeReferences == null ? 0 : this.typeReferences.length; - printIndent(indent, output); - for (int i = 0; i < length; i++) { - this.typeReferences[i].printExpression(0, output); - if (i != length - 1) { - output.append(" | "); //$NON-NLS-1$ - } - } - return output; - } - @Override - public boolean isUnionType() { - return true; - } - @Override - public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) { - return this; // arrays are not legal as union types. - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java deleted file mode 100644 index d012c37..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UnlikelyArgumentCheck.java +++ /dev/null @@ -1,189 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015, 2017 GK Software AG and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Stephan Herrmann - initial API and implementation - *******************************************************************************/ - -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; -import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; -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.DangerousMethod; -import org.eclipse.jdt.internal.compiler.lookup.TypeIds; - -/* @NonNullByDefault */ -public class UnlikelyArgumentCheck { - public final DangerousMethod dangerousMethod; - public final TypeBinding typeToCheck; - public final TypeBinding expectedType; - public final TypeBinding typeToReport; - - private UnlikelyArgumentCheck(DangerousMethod dangerousMethod, TypeBinding typeToCheck, TypeBinding expectedType, - TypeBinding typeToReport) { - this.dangerousMethod = dangerousMethod; - this.typeToCheck = typeToCheck; - this.expectedType = expectedType; - this.typeToReport = typeToReport; - } - - /** - * Check if the invocation is likely a bug. - * @return false, if the typeToCheck does not seem to related to the expectedType - */ - public boolean isDangerous(BlockScope currentScope) { - TypeBinding typeToCheck2 = this.typeToCheck; - // take autoboxing into account - if (typeToCheck2.isBaseType()) { - typeToCheck2 = currentScope.boxing(typeToCheck2); - } - TypeBinding expectedType2 = this.expectedType; - if (expectedType2.isBaseType()) { // can happen for the first parameter of java.util.Object.equals - expectedType2 = currentScope.boxing(expectedType2); - } - if(this.dangerousMethod != DangerousMethod.Equals && currentScope.compilerOptions().reportUnlikelyCollectionMethodArgumentTypeStrict) { - return !typeToCheck2.isCompatibleWith(expectedType2, currentScope); - } - // unless both types are true type variables (not captures), take the erasure of both. - if (typeToCheck2.isCapture() || !typeToCheck2.isTypeVariable() || expectedType2.isCapture() - || !expectedType2.isTypeVariable()) { - typeToCheck2 = typeToCheck2.erasure(); - expectedType2 = expectedType2.erasure(); - } - return !typeToCheck2.isCompatibleWith(expectedType2, currentScope) - && !expectedType2.isCompatibleWith(typeToCheck2, currentScope); - } - - /** - * When targeting a well-known dangerous method, returns an UnlikelyArgumentCheck object that contains the types to - * check against each other and to report - */ - public static /* @Nullable */ UnlikelyArgumentCheck determineCheckForNonStaticSingleArgumentMethod( - TypeBinding argumentType, Scope scope, char[] selector, TypeBinding actualReceiverType, - TypeBinding[] parameters) { - // detecting only methods with a single argument, typed either as Object or as Collection: - if (parameters.length != 1) - return null; - int paramTypeId = parameters[0].original().id; - if (paramTypeId != TypeIds.T_JavaLangObject && paramTypeId != TypeIds.T_JavaUtilCollection) - return null; - - // check selectors before typeBits as to avoid unnecessary super-traversals for the receiver type - DangerousMethod suspect = DangerousMethod.detectSelector(selector); - if (suspect == null) - return null; - - if (actualReceiverType.hasTypeBit(TypeIds.BitMap)) { - if (paramTypeId == TypeIds.T_JavaLangObject) { - switch (suspect) { - case ContainsKey: - case Get: - case Remove: - // map operations taking a key - ReferenceBinding mapType = actualReceiverType - .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilMap, false); - if (mapType != null && mapType.isParameterizedType()) - return new UnlikelyArgumentCheck(suspect, argumentType, - ((ParameterizedTypeBinding) mapType).typeArguments()[0], mapType); - break; - case ContainsValue: - // map operation taking a value - mapType = actualReceiverType.findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilMap, false); - if (mapType != null && mapType.isParameterizedType()) - return new UnlikelyArgumentCheck(suspect, argumentType, - ((ParameterizedTypeBinding) mapType).typeArguments()[1], mapType); - break; - default: // no other suspects are detected in java.util.Map - } - } - } - if (actualReceiverType.hasTypeBit(TypeIds.BitCollection)) { - if (paramTypeId == TypeIds.T_JavaLangObject) { - switch (suspect) { - case Remove: - case Contains: - // collection operations taking a single element - ReferenceBinding collectionType = actualReceiverType - .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilCollection, false); - if (collectionType != null && collectionType.isParameterizedType()) - return new UnlikelyArgumentCheck(suspect, argumentType, - ((ParameterizedTypeBinding) collectionType).typeArguments()[0], collectionType); - break; - default: // no other suspects with Object-parameter are detected in java.util.Collection - } - } else if (paramTypeId == TypeIds.T_JavaUtilCollection) { - switch (suspect) { - case RemoveAll: - case ContainsAll: - case RetainAll: - // collection operations taking another collection - ReferenceBinding collectionType = actualReceiverType - .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilCollection, false); - ReferenceBinding argumentCollectionType = argumentType - .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilCollection, false); - if (collectionType != null && argumentCollectionType != null - && argumentCollectionType.isParameterizedTypeWithActualArguments() - && collectionType.isParameterizedTypeWithActualArguments()) { - return new UnlikelyArgumentCheck(suspect, - ((ParameterizedTypeBinding) argumentCollectionType).typeArguments()[0], - ((ParameterizedTypeBinding) collectionType).typeArguments()[0], collectionType); - } - break; - default: // no other suspects with Collection-parameter are detected in java.util.Collection - } - } - if (actualReceiverType.hasTypeBit(TypeIds.BitList)) { - if (paramTypeId == TypeIds.T_JavaLangObject) { - switch (suspect) { - case IndexOf: - case LastIndexOf: - // list operations taking a single element - ReferenceBinding listType = actualReceiverType - .findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilList, false); - if (listType != null && listType.isParameterizedType()) - return new UnlikelyArgumentCheck(suspect, argumentType, - ((ParameterizedTypeBinding) listType).typeArguments()[0], listType); - break; - default: // no other suspects are detected in java.util.List - } - } - } - } - if (paramTypeId == TypeIds.T_JavaLangObject && suspect == DangerousMethod.Equals) { - return new UnlikelyArgumentCheck(suspect, argumentType, actualReceiverType, actualReceiverType); - } - return null; // not replacing - } - public static /* @Nullable */ UnlikelyArgumentCheck determineCheckForStaticTwoArgumentMethod( - TypeBinding secondParameter, Scope scope, char[] selector, TypeBinding firstParameter, - TypeBinding[] parameters, TypeBinding actualReceiverType) { - // detecting only methods with two arguments, both typed as Object: - if (parameters.length != 2) - return null; - int paramTypeId1 = parameters[0].original().id; - int paramTypeId2 = parameters[1].original().id; - - if (paramTypeId1 != TypeIds.T_JavaLangObject || paramTypeId2 != TypeIds.T_JavaLangObject) - return null; - - // check selectors before typeBits as to avoid unnecessary super-traversals for the receiver type - DangerousMethod suspect = DangerousMethod.detectSelector(selector); - if (suspect == null) - return null; - - if (actualReceiverType.id == TypeIds.T_JavaUtilObjects && suspect == DangerousMethod.Equals) { - return new UnlikelyArgumentCheck(suspect, secondParameter, firstParameter, firstParameter); - } - return null; - } -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UsesStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UsesStatement.java deleted file mode 100644 index edd2ebc..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/UsesStatement.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -public class UsesStatement extends ModuleStatement { - - public TypeReference serviceInterface; - - public UsesStatement(TypeReference serviceInterface) { - this.serviceInterface = serviceInterface; - } - @Override - public StringBuilder print(int indent, StringBuilder output) { - printIndent(indent, output); - output.append("uses "); //$NON-NLS-1$ - this.serviceInterface.print(0, output); - output.append(";"); //$NON-NLS-1$ - return output; - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java deleted file mode 100644 index 8c75ffa..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/WhileStatement.java +++ /dev/null @@ -1,351 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * 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 345305 - [compiler][null] Compiler misidentifies a case of "variable can only be null" - * bug 403147 - [compiler][null] FUP of bug 400761: consolidate interaction between unboxing, NPE, and deferred checking - * Bug 415790 - [compiler][resource]Incorrect potential resource leak warning in for loop with close in try/catch - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.impl.*; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.*; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class WhileStatement extends Statement { - - public Expression condition; - public Statement action; - private BranchLabel breakLabel, continueLabel; - int preCondInitStateIndex = -1; - int condIfTrueInitStateIndex = -1; - int mergedInitStateIndex = -1; - - public WhileStatement(Expression condition, Statement action, int s, int e) { - - this.condition = condition; - this.action = action; - // remember useful empty statement - if (action instanceof EmptyStatement) action.bits |= IsUsefulEmptyStatement; - this.sourceStart = s; - this.sourceEnd = e; - } - - @Override - public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - - this.breakLabel = new BranchLabel(); - this.continueLabel = new BranchLabel(); - int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED; - - Constant cst = this.condition.constant; - boolean isConditionTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isConditionFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - - cst = this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true; - boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - - this.preCondInitStateIndex = currentScope.methodScope().recordInitializationStates(flowInfo); - LoopingFlowContext condLoopContext; - FlowInfo condInfo = flowInfo.nullInfoLessUnconditionalCopy(); - - // we need to collect the contribution to nulls of the coming paths through the - // loop, be they falling through normally or branched to break, continue labels - // or catch blocks - condInfo = this.condition.analyseCode( - currentScope, - (condLoopContext = - new LoopingFlowContext(flowContext, flowInfo, this, null, - null, currentScope, true)), - condInfo); - this.condition.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - - LoopingFlowContext loopingContext; - FlowInfo actionInfo; - FlowInfo exitBranch; - if (this.action == null - || (this.action.isEmptyBlock() && currentScope.compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) { - condLoopContext.complainOnDeferredFinalChecks(currentScope, - condInfo); - condLoopContext.complainOnDeferredNullChecks(currentScope, - condInfo.unconditionalInits()); - if (isConditionTrue) { - return FlowInfo.DEAD_END; - } else { - FlowInfo mergedInfo = flowInfo.copy().addInitializationsFrom(condInfo.initsWhenFalse()); - if (isConditionOptimizedTrue){ - mergedInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - this.mergedInitStateIndex = - currentScope.methodScope().recordInitializationStates(mergedInfo); - return mergedInfo; - } - } else { - // in case the condition was inlined to false, record the fact that there is no way to reach any - // statement inside the looping action - loopingContext = - new LoopingFlowContext( - flowContext, - flowInfo, - this, - this.breakLabel, - this.continueLabel, - currentScope, - true); - loopingContext.copyNullCheckedFieldsFrom(condLoopContext); - if (isConditionFalse) { - actionInfo = FlowInfo.DEAD_END; - } else { - actionInfo = condInfo.initsWhenTrue().copy(); - if (isConditionOptimizedFalse){ - actionInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD); - } - } - - // for computing local var attributes - this.condIfTrueInitStateIndex = - currentScope.methodScope().recordInitializationStates( - condInfo.initsWhenTrue()); - - if (this.action.complainIfUnreachable(actionInfo, currentScope, initialComplaintLevel, true) < Statement.COMPLAINED_UNREACHABLE) { - this.condition.updateFlowOnBooleanResult(actionInfo, true); - actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo); - } - - // code generation can be optimized when no need to continue in the loop - exitBranch = flowInfo.copy(); - // need to start over from flowInfo so as to get null inits - int combinedTagBits = actionInfo.tagBits & loopingContext.initsOnContinue.tagBits; - if ((combinedTagBits & FlowInfo.UNREACHABLE) != 0) { - if ((combinedTagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0) - this.continueLabel = null; - exitBranch.addInitializationsFrom(condInfo.initsWhenFalse()); - actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits()); - condLoopContext.complainOnDeferredNullChecks(currentScope, - actionInfo, false); - loopingContext.complainOnDeferredNullChecks(currentScope, - actionInfo, false); - } else { - condLoopContext.complainOnDeferredFinalChecks(currentScope, - condInfo); - actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits()); - condLoopContext.complainOnDeferredNullChecks(currentScope, - actionInfo); - loopingContext.complainOnDeferredFinalChecks(currentScope, - actionInfo); - loopingContext.complainOnDeferredNullChecks(currentScope, - actionInfo); - exitBranch. - addPotentialInitializationsFrom( - actionInfo.unconditionalInits()). - addInitializationsFrom(condInfo.initsWhenFalse()); - } - if (loopingContext.hasEscapingExceptions()) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=321926 - FlowInfo loopbackFlowInfo = flowInfo.copy(); - if (this.continueLabel != null) { // we do get to the bottom - // loopback | (loopback + action): - loopbackFlowInfo = loopbackFlowInfo.mergedWith(loopbackFlowInfo.unconditionalCopy().addNullInfoFrom(actionInfo).unconditionalInits()); - } - loopingContext.simulateThrowAfterLoopBack(loopbackFlowInfo); - } - } - - // end of loop - FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( - (loopingContext.initsOnBreak.tagBits & - FlowInfo.UNREACHABLE) != 0 ? - loopingContext.initsOnBreak : - flowInfo.addInitializationsFrom(loopingContext.initsOnBreak), // recover upstream null info - isConditionOptimizedTrue, - exitBranch, - isConditionOptimizedFalse, - !isConditionTrue /*while(true); unreachable(); */); - this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); - this.condition.updateFlowOnBooleanResult(mergedInfo, false); - return mergedInfo; - } - - /** - * While code generation - * - * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope - * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream - */ - @Override - public void generateCode(BlockScope currentScope, CodeStream codeStream) { - - if ((this.bits & IsReachable) == 0) { - return; - } - if (containsPatternVariable()) { - this.condition.addPatternVariables(currentScope, codeStream); - } - int pc = codeStream.position; - Constant cst = this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false; - if (isConditionOptimizedFalse) { - this.condition.generateCode(currentScope, codeStream, false); - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - codeStream.recordPositionsFrom(pc, this.sourceStart); - return; - } - - this.breakLabel.initialize(codeStream); - - // generate condition - if (this.continueLabel == null) { - // no need to reverse condition - if (this.condition.constant == Constant.NotAConstant) { - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - null, - this.breakLabel, - true); - } - } else { - this.continueLabel.initialize(codeStream); - if (!(((this.condition.constant != Constant.NotAConstant) - && (this.condition.constant.booleanValue() == true)) - || (this.action == null) - || this.action.isEmptyBlock())) { - int jumpPC = codeStream.position; - codeStream.goto_(this.continueLabel); - codeStream.recordPositionsFrom(jumpPC, this.condition.sourceStart); - } - } - // generate the action - BranchLabel actionLabel = new BranchLabel(codeStream); - if (this.action != null) { - actionLabel.tagBits |= BranchLabel.USED; - // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect - if (this.condIfTrueInitStateIndex != -1) { - // insert all locals initialized inside the condition into the action generated prior to the condition - codeStream.addDefinitelyAssignedVariables( - currentScope, - this.condIfTrueInitStateIndex); - } - actionLabel.place(); - this.action.generateCode(currentScope, codeStream); - // May loose some local variable initializations : affecting the local variable attributes - if (this.preCondInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.preCondInitStateIndex); - } - } else { - actionLabel.place(); - } - // output condition and branch back to the beginning of the repeated action - if (this.continueLabel != null) { - this.continueLabel.place(); - this.condition.generateOptimizedBoolean( - currentScope, - codeStream, - actionLabel, - null, - true); - } - - // May loose some local variable initializations : affecting the local variable attributes - if (this.mergedInitStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.mergedInitStateIndex); - } - this.breakLabel.place(); - codeStream.recordPositionsFrom(pc, this.sourceStart); - } - - @Override - public void resolve(BlockScope scope) { - - TypeBinding type = this.condition.resolveTypeExpecting(scope, TypeBinding.BOOLEAN); - this.condition.computeConversion(scope, type, type); - if (this.action != null) { - this.action.resolveWithBindings(this.condition.bindingsWhenTrue(), scope); - } - } - - @Override - public boolean containsPatternVariable() { - return this.condition.containsPatternVariable(); - } - - @Override - public StringBuilder printStatement(int tab, StringBuilder output) { - - printIndent(tab, output).append("while ("); //$NON-NLS-1$ - this.condition.printExpression(0, output).append(')'); - if (this.action == null) - output.append(';'); - else - this.action.printStatement(tab + 1, output); - return output; - } - - @Override - public void traverse( - ASTVisitor visitor, - BlockScope blockScope) { - - if (visitor.visit(this, blockScope)) { - this.condition.traverse(visitor, blockScope); - if (this.action != null) - this.action.traverse(visitor, blockScope); - } - visitor.endVisit(this, blockScope); - } - - @Override - public LocalVariableBinding[] bindingsWhenComplete() { - return this.condition.containsPatternVariable() && this.action != null && !this.action.breaksOut(null) ? - this.condition.bindingsWhenFalse() : NO_VARIABLES; - } - - @Override - public boolean doesNotCompleteNormally() { - Constant cst = this.condition.constant; - boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true; - cst = this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true; - return (isConditionTrue || isConditionOptimizedTrue) && (this.action == null || !this.action.breaksOut(null)); - } - - @Override - public boolean completesByContinue() { - return this.action.continuesAtOuterLabel(); - } - - @Override - public boolean canCompleteNormally() { - Constant cst = this.condition.constant; - boolean isConditionTrue = cst == null || cst != Constant.NotAConstant && cst.booleanValue() == true; - cst = this.condition.optimizedBooleanConstant(); - boolean isConditionOptimizedTrue = cst == null ? true : cst != Constant.NotAConstant && cst.booleanValue() == true; - if (!(isConditionTrue || isConditionOptimizedTrue)) - return true; - return this.action != null && this.action.breaksOut(null); - } - - @Override - public boolean continueCompletes() { - return this.action.continuesAtOuterLabel(); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Wildcard.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Wildcard.java deleted file mode 100644 index 2f2915d..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/Wildcard.java +++ /dev/null @@ -1,175 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for - * Bug 415397 - [1.8][compiler] Type Annotations on wildcard type argument dropped - * Stephan Herrmann - Contribution for - * Bug 415043 - [1.8][null] Follow-up re null type annotations after bug 392099 - * Bug 417295 - [1.8[[null] Massage type annotated null analysis to gel well with deep encoded type bindings. - * Bug 429958 - [1.8][null] evaluate new DefaultLocation attribute of @NonNullByDefault - * Bug 440462 - [null][compiler]NPE in EJC for erroneous null annotations - * Bug 441693 - [1.8][null] Bogus warning for type argument annotated with @NonNull - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.lookup.*; - -/** - * Node to represent Wildcard - */ -public class Wildcard extends SingleTypeReference { - - public static final int UNBOUND = 0; - public static final int EXTENDS = 1; - public static final int SUPER = 2; - - public TypeReference bound; - public int kind; - - public Wildcard(int kind) { - super(WILDCARD_NAME, 0); - this.kind = kind; - } - - @Override - public char [][] getParameterizedTypeName() { - switch (this.kind) { - case Wildcard.UNBOUND : - return new char[][] { WILDCARD_NAME }; - case Wildcard.EXTENDS : - return new char[][] { CharOperation.concat(WILDCARD_NAME, WILDCARD_EXTENDS, CharOperation.concatWith(this.bound.getParameterizedTypeName(), '.')) }; - default: // SUPER - return new char[][] { CharOperation.concat(WILDCARD_NAME, WILDCARD_SUPER, CharOperation.concatWith(this.bound.getParameterizedTypeName(), '.')) }; - } - } - - @Override - public char [][] getTypeName() { - switch (this.kind) { - case Wildcard.UNBOUND : - return new char[][] { WILDCARD_NAME }; - case Wildcard.EXTENDS : - return new char[][] { CharOperation.concat(WILDCARD_NAME, WILDCARD_EXTENDS, CharOperation.concatWith(this.bound.getTypeName(), '.')) }; - default: // SUPER - return new char[][] { CharOperation.concat(WILDCARD_NAME, WILDCARD_SUPER, CharOperation.concatWith(this.bound.getTypeName(), '.')) }; - } - } - - private TypeBinding internalResolveType(Scope scope, ReferenceBinding genericType, int rank) { - TypeBinding boundType = null; - if (this.bound != null) { - boundType = scope.kind == Scope.CLASS_SCOPE - ? this.bound.resolveType((ClassScope)scope, Binding.DefaultLocationTypeBound) - : this.bound.resolveType((BlockScope)scope, true /* check bounds*/, Binding.DefaultLocationTypeBound); - this.bits |= (this.bound.bits & ASTNode.HasTypeAnnotations); - if (boundType == null) { - return null; - } - } - this.resolvedType = scope.environment().createWildcard(genericType, rank, boundType, null /*no extra bound*/, this.kind); - resolveAnnotations(scope, 0); // no defaultNullness for wildcards - - if(scope.environment().usesNullTypeAnnotations()) { - ((WildcardBinding)this.resolvedType).evaluateNullAnnotations(scope, this); - } - - return this.resolvedType; - } - - @Override - public StringBuilder printExpression(int indent, StringBuilder output){ - if (this.annotations != null && this.annotations[0] != null) { - printAnnotations(this.annotations[0], output); - output.append(' '); - } - switch (this.kind) { - case Wildcard.UNBOUND : - output.append(WILDCARD_NAME); - break; - case Wildcard.EXTENDS : - output.append(WILDCARD_NAME).append(WILDCARD_EXTENDS); - this.bound.printExpression(0, output); - break; - default: // SUPER - output.append(WILDCARD_NAME).append(WILDCARD_SUPER); - this.bound.printExpression(0, output); - break; - } - return output; - } - - // only invoked for improving resilience when unable to bind generic type from parameterized reference - @Override - public TypeBinding resolveType(BlockScope scope, boolean checkBounds, int location) { - if (this.bound != null) { - this.bound.resolveType(scope, checkBounds, Binding.DefaultLocationTypeBound); - this.bits |= (this.bound.bits & ASTNode.HasTypeAnnotations); - } - return null; - } - // only invoked for improving resilience when unable to bind generic type from parameterized reference - @Override - public TypeBinding resolveType(ClassScope scope, int location) { - if (this.bound != null) { - this.bound.resolveType(scope, Binding.DefaultLocationTypeBound); - this.bits |= (this.bound.bits & ASTNode.HasTypeAnnotations); - } - return null; - } - @Override - public TypeBinding resolveTypeArgument(BlockScope blockScope, ReferenceBinding genericType, int rank) { - return internalResolveType(blockScope, genericType, rank); // no defaultNullness for wildcards - } - - @Override - public TypeBinding resolveTypeArgument(ClassScope classScope, ReferenceBinding genericType, int rank) { - return internalResolveType(classScope, genericType, rank); // no defaultNullness for wildcards - } - - @Override - public void traverse(ASTVisitor visitor, BlockScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - Annotation [] typeAnnotations = this.annotations[0]; - for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) { - typeAnnotations[i].traverse(visitor, scope); - } - } - if (this.bound != null) { - this.bound.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - - @Override - public void traverse(ASTVisitor visitor, ClassScope scope) { - if (visitor.visit(this, scope)) { - if (this.annotations != null) { - Annotation [] typeAnnotations = this.annotations[0]; - for (int i = 0, length = typeAnnotations == null ? 0 : typeAnnotations.length; i < length; i++) { - typeAnnotations[i].traverse(visitor, scope); - } - } - if (this.bound != null) { - this.bound.traverse(visitor, scope); - } - } - visitor.endVisit(this, scope); - } - @Override - public boolean isWildcard() { - return true; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java deleted file mode 100644 index 761acfc..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/ast/YieldStatement.java +++ /dev/null @@ -1,283 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.ast; - -import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.codegen.CodeStream; -import org.eclipse.jdt.internal.compiler.flow.*; -import org.eclipse.jdt.internal.compiler.impl.Constant; -import org.eclipse.jdt.internal.compiler.lookup.*; - -public class YieldStatement extends BranchStatement { - - public Expression expression; - public SwitchExpression switchExpression; - public TryStatement tryStatement; - /** - * @noreference This field is not intended to be referenced by clients. - */ - public boolean isImplicit; - static final char[] SECRET_YIELD_RESULT_VALUE_NAME = " secretYieldValue".toCharArray(); //$NON-NLS-1$ - private LocalVariableBinding secretYieldResultValue = null; - -public YieldStatement(Expression exp, int sourceStart, int sourceEnd) { - super(null, sourceStart, sourceEnd); - this.expression = exp; -} -@Override -public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { - // this.switchExpression != null && this.expression != null true here. - - // here requires to generate a sequence of finally blocks invocations depending corresponding - // to each of the traversed try statements, so that execution will terminate properly. - - - // lookup the null label, this should answer the returnContext - for implicit yields, the nesting - // doesn't occur since it immediately follow '->' and hence identical to default break - ie the - // immediate breakable context is guaranteed to be the one intended; - // while explicit yield should move up the parent to the switch expression. - FlowContext targetContext = flowContext.getTargetContextForYield(!this.isImplicit); - - flowInfo = this.expression.analyseCode(currentScope, flowContext, flowInfo); - this.expression.checkNPEbyUnboxing(currentScope, flowContext, flowInfo); - if (flowInfo.reachMode() == FlowInfo.REACHABLE && currentScope.compilerOptions().isAnnotationBasedNullAnalysisEnabled) - checkAgainstNullAnnotation(currentScope, flowContext, flowInfo, this.expression); - - targetContext.recordAbruptExit(); - targetContext.expireNullCheckedFieldInfo(); - - this.initStateIndex = - currentScope.methodScope().recordInitializationStates(flowInfo); - - this.targetLabel = targetContext.breakLabel(); - FlowContext traversedContext = flowContext; - int subCount = 0; - this.subroutines = new SubRoutineStatement[5]; - - do { - SubRoutineStatement sub; - if ((sub = traversedContext.subroutine()) != null) { - if (subCount == this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount*2]), 0, subCount); // grow - } - this.subroutines[subCount++] = sub; - if (sub.isSubRoutineEscaping()) { - break; - } - } - traversedContext.recordReturnFrom(flowInfo.unconditionalInits()); - traversedContext.recordBreakTo(targetContext); - - if (traversedContext instanceof InsideSubRoutineFlowContext) { - ASTNode node = traversedContext.associatedNode; - if (node instanceof TryStatement) { - flowInfo.addInitializationsFrom(((TryStatement) node).subRoutineInits); // collect inits - } - } else if (traversedContext == targetContext) { - // only record break info once accumulated through subroutines, and only against target context - targetContext.recordBreakFrom(flowInfo); - break; - } - } while ((traversedContext = traversedContext.getLocalParent()) != null); - - // resize subroutines - if (subCount != this.subroutines.length) { - System.arraycopy(this.subroutines, 0, (this.subroutines = new SubRoutineStatement[subCount]), 0, subCount); - } - return FlowInfo.DEAD_END; -} -@Override -protected void setSubroutineSwitchExpression(SubRoutineStatement sub) { - sub.setSwitchExpression(this.switchExpression); -} -protected void addSecretYieldResultValue(BlockScope scope) { - SwitchExpression se = this.switchExpression; - if (se == null || !se.containsTry) - return; - LocalVariableBinding local = new LocalVariableBinding( - YieldStatement.SECRET_YIELD_RESULT_VALUE_NAME, - se.resolvedType, - ClassFileConstants.AccDefault, - false); - local.setConstant(Constant.NotAConstant); - local.useFlag = LocalVariableBinding.USED; - local.declaration = new LocalDeclaration(YieldStatement.SECRET_YIELD_RESULT_VALUE_NAME, 0, 0); - assert se.yieldResolvedPosition >= 0; - local.resolvedPosition = se.yieldResolvedPosition; - assert local.resolvedPosition < scope.maxOffset; - scope.addLocalVariable(local); - this.secretYieldResultValue = local; -} - -@Override -protected void restartExceptionLabels(CodeStream codeStream) { - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); -} -protected void generateExpressionResultCodeExpanded(BlockScope currentScope, CodeStream codeStream) { - SwitchExpression se = this.switchExpression; - addSecretYieldResultValue(currentScope); - assert this.secretYieldResultValue != null; - codeStream.record(this.secretYieldResultValue); - SingleNameReference lhs = new SingleNameReference(this.secretYieldResultValue.name, 0); - lhs.binding = this.secretYieldResultValue; - lhs.bits &= ~ASTNode.RestrictiveFlagMASK; // clear bits - lhs.bits |= Binding.LOCAL; - lhs.bits |= ASTNode.IsSecretYieldValueUsage; - ((LocalVariableBinding) lhs.binding).markReferenced(); // TODO : Can be skipped? - Assignment assignment = new Assignment(lhs, this.expression, 0); - assignment.generateCode(currentScope, codeStream); - - int pc = codeStream.position; - // generation of code responsible for invoking the finally - // blocks in sequence - if (this.subroutines != null){ - for (int i = 0, max = this.subroutines.length; i < max; i++){ - SubRoutineStatement sub = this.subroutines[i]; - SwitchExpression se1 = sub.getSwitchExpression(); - setSubroutineSwitchExpression(sub); - boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); - sub.setSwitchExpression(se1); - if (didEscape) { - codeStream.removeVariable(this.secretYieldResultValue); - codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); - if (this.initStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); - } - restartExceptionLabels(codeStream); - return; - } - } - } - se.loadStoredTypesAndKeep(codeStream); - codeStream.load(this.secretYieldResultValue); - codeStream.removeVariable(this.secretYieldResultValue); - - codeStream.goto_(this.targetLabel); - codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); - if (this.initStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); - } -} -@Override -public void generateCode(BlockScope currentScope, CodeStream codeStream) { - if ((this.bits & ASTNode.IsReachable) == 0) { - return; - } - if (this.switchExpression != null && this.switchExpression.containsTry && this.switchExpression.resolvedType != null ) { - generateExpressionResultCodeExpanded(currentScope, codeStream); - return; - } - this.expression.generateCode(currentScope, codeStream, this.switchExpression != null); - int pc = codeStream.position; - - // generation of code responsible for invoking the finally - // blocks in sequence - if (this.subroutines != null){ - for (int i = 0, max = this.subroutines.length; i < max; i++){ - SubRoutineStatement sub = this.subroutines[i]; - SwitchExpression se = sub.getSwitchExpression(); - setSubroutineSwitchExpression(sub); - boolean didEscape = sub.generateSubRoutineInvocation(currentScope, codeStream, this.targetLabel, this.initStateIndex, null); - sub.setSwitchExpression(se); - if (didEscape) { - codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, i, codeStream); - if (this.initStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); - } - restartExceptionLabels(codeStream); - return; - } - } - } - codeStream.goto_(this.targetLabel); - codeStream.recordPositionsFrom(pc, this.sourceStart); - SubRoutineStatement.reenterAllExceptionHandlers(this.subroutines, -1, codeStream); - if (this.initStateIndex != -1) { - codeStream.removeNotDefinitelyAssignedVariables(currentScope, this.initStateIndex); - codeStream.addDefinitelyAssignedVariables(currentScope, this.initStateIndex); - } -} -@Override -public void resolve(BlockScope scope) { - super.resolve(scope); - if (this.expression == null) { - return; - - } - if (this.switchExpression != null || this.isImplicit) { - if (this.switchExpression == null && this.isImplicit && !this.expression.statementExpression()) { - if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) { - /* JLS 13 14.11.2 - Switch labeled rules in switch statements differ from those in switch expressions (15.28). - In switch statements they must be switch labeled statement expressions, ... */ - scope.problemReporter().invalidExpressionAsStatement(this.expression); - return; - } - } - } else { - if (scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK14) { - scope.problemReporter().switchExpressionsYieldOutsideSwitchExpression(this); - } - } - TypeBinding type = this.expression.resolveType(scope); - if (this.switchExpression != null && type != null) - this.switchExpression.originalTypeMap.put(this.expression, type); -} - -@Override -public TypeBinding resolveExpressionType(BlockScope scope1) { - return this.expression != null ? this.expression.resolveType(scope1) : null; -} - -@Override -public StringBuilder printStatement(int tab, StringBuilder output) { - if (!this.isImplicit) - printIndent(tab, output).append("yield"); //$NON-NLS-1$ - if (this.expression != null) { - if (this.isImplicit) { - this.expression.print(tab, output); - } else { - output.append(' '); - this.expression.printExpression(tab, output); - } - } - return output.append(';'); -} - -@Override -public void traverse(ASTVisitor visitor, BlockScope blockscope) { - if (visitor.visit(this, blockscope)) { - if (this.expression != null) - this.expression.traverse(visitor, blockscope); - } - visitor.endVisit(this, blockscope); -} -@Override -public boolean doesNotCompleteNormally() { - return true; -} - -@Override -public boolean canCompleteNormally() { - return false; -} - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/BasicModule.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/BasicModule.java deleted file mode 100644 index caf7748..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/BasicModule.java +++ /dev/null @@ -1,252 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016 IBM Corporation. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.util.Arrays; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.ast.ExportsStatement; -import org.eclipse.jdt.internal.compiler.ast.ModuleDeclaration; -import org.eclipse.jdt.internal.compiler.ast.ModuleReference; -import org.eclipse.jdt.internal.compiler.ast.OpensStatement; -import org.eclipse.jdt.internal.compiler.ast.ProvidesStatement; -import org.eclipse.jdt.internal.compiler.ast.RequiresStatement; -import org.eclipse.jdt.internal.compiler.ast.TypeReference; -import org.eclipse.jdt.internal.compiler.ast.UsesStatement; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.env.IModulePathEntry; -import org.eclipse.jdt.internal.compiler.env.ISourceModule; -import org.eclipse.jdt.internal.compiler.env.ModuleReferenceImpl; -import org.eclipse.jdt.internal.compiler.env.PackageExportImpl; - -/** - * Retrofit a {@link ModuleDeclaration} into an {@link ISourceModule}. - * It remembers the underlying {@link ICompilationUnit} so the full structure - * can be recreated if needed. - */ -public class BasicModule implements ISourceModule { - static class Service implements IModule.IService { - char[] provides; - char[][] with; - @Override - public char[] name() { - return this.provides; - } - - @Override - public char[][] with() { - return this.with; - } - @Override - public String toString() { - StringBuilder buffer = new StringBuilder(); - buffer.append("provides"); //$NON-NLS-1$ - buffer.append(this.provides); - buffer.append(" with "); //$NON-NLS-1$ - buffer.append(this.with); - buffer.append(';'); - return buffer.toString(); - } - } - private static PackageExportImpl createPackageExport(ExportsStatement[] refs, int i) { - ExportsStatement ref = refs[i]; - PackageExportImpl exp = new PackageExportImpl(); - exp.pack = ref.pkgName; - ModuleReference[] imp = ref.targets; - if (imp != null) { - exp.exportedTo = new char[imp.length][]; - for(int j = 0; j < imp.length; j++) { - exp.exportedTo = imp[j].tokens; - } - } - return exp; - } - private static Service createService(TypeReference service, TypeReference[] with) { - Service ser = new Service(); - ser.provides = CharOperation.concatWith(service.getTypeName(), '.'); - ser.with = new char[with.length][]; - for (int i = 0; i < with.length; i++) { - ser.with[i] = CharOperation.concatWith(with[i].getTypeName(), '.'); - } - return ser; - } - private static PackageExportImpl createPackageOpen(OpensStatement ref) { - PackageExportImpl exp = new PackageExportImpl(); - exp.pack = ref.pkgName; - ModuleReference[] imp = ref.targets; - if (imp != null) { - exp.exportedTo = new char[imp.length][]; - for(int j = 0; j < imp.length; j++) { - exp.exportedTo = imp[j].tokens; - } - } - return exp; - } - - private boolean isOpen = false; - char[] name; - IModule.IModuleReference[] requires; - IModule.IPackageExport[] exports; - char[][] uses; - Service[] provides; - IModule.IPackageExport[] opens; - private final ICompilationUnit compilationUnit; - - public BasicModule(ModuleDeclaration descriptor, IModulePathEntry root) { - this.compilationUnit = descriptor.compilationResult().compilationUnit; - this.name = descriptor.moduleName; - if (descriptor.requiresCount > 0) { - RequiresStatement[] refs = descriptor.requires; - this.requires = new ModuleReferenceImpl[refs.length]; - for (int i = 0; i < refs.length; i++) { - ModuleReferenceImpl ref = new ModuleReferenceImpl(); - ref.name = CharOperation.concatWith(refs[i].module.tokens, '.'); - ref.modifiers = refs[i].modifiers; - this.requires[i] = ref; - } - } else { - this.requires = new ModuleReferenceImpl[0]; - } - if (descriptor.exportsCount > 0) { - ExportsStatement[] refs = descriptor.exports; - this.exports = new PackageExportImpl[refs.length]; - for (int i = 0; i < refs.length; i++) { - PackageExportImpl exp = createPackageExport(refs, i); - this.exports[i] = exp; - } - } else { - this.exports = new PackageExportImpl[0]; - } - if (descriptor.usesCount > 0) { - UsesStatement[] u = descriptor.uses; - this.uses = new char[u.length][]; - for(int i = 0; i < u.length; i++) { - this.uses[i] = CharOperation.concatWith(u[i].serviceInterface.getTypeName(), '.'); - } - } - if (descriptor.servicesCount > 0) { - ProvidesStatement[] services = descriptor.services; - this.provides = new Service[descriptor.servicesCount]; - for (int i = 0; i < descriptor.servicesCount; i++) { - this.provides[i] = createService(services[i].serviceInterface, services[i].implementations); - } - } - if (descriptor.opensCount > 0) { - OpensStatement[] refs = descriptor.opens; - this.opens = new PackageExportImpl[refs.length]; - for (int i = 0; i < refs.length; i++) { - PackageExportImpl exp = createPackageOpen(refs[i]); - this.opens[i] = exp; - } - } else { - this.opens = new PackageExportImpl[0]; - } - this.isOpen = descriptor.isOpen(); - } - @Override - public ICompilationUnit getCompilationUnit() { - return this.compilationUnit; - } - @Override - public char[] name() { - return this.name; - } - @Override - public IModule.IModuleReference[] requires() { - return this.requires; - } - @Override - public IModule.IPackageExport[] exports() { - return this.exports; - } - @Override - public char[][] uses() { - return this.uses; - } - @Override - public IService[] provides() { - return this.provides; - } - @Override - public IModule.IPackageExport[] opens() { - return this.opens; - } - @Override - public boolean isOpen() { - return this.isOpen; - } - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (!(o instanceof IModule)) - return false; - IModule mod = (IModule) o; - if (!CharOperation.equals(this.name, mod.name())) - return false; - return Arrays.equals(this.requires, mod.requires()); - } - @Override - public int hashCode() { - int result = 17; - int c = CharOperation.hashCode(this.name); - result = 31 * result + c; - c = Arrays.hashCode(this.requires); - result = 31 * result + c; - return result; - } - @Override - public String toString() { - StringBuilder buffer = new StringBuilder(getClass().getName()); - toStringContent(buffer); - return buffer.toString(); - } - protected void toStringContent(StringBuilder buffer) { - buffer.append("\nmodule "); //$NON-NLS-1$ - buffer.append(this.name).append(' '); - buffer.append('{').append('\n'); - if (this.requires != null) { - for(int i = 0; i < this.requires.length; i++) { - buffer.append("\trequires "); //$NON-NLS-1$ - if (this.requires[i].isTransitive()) { - buffer.append(" public "); //$NON-NLS-1$ - } - buffer.append(this.requires[i].name()); - buffer.append(';').append('\n'); - } - } - if (this.exports != null) { - buffer.append('\n'); - for(int i = 0; i < this.exports.length; i++) { - buffer.append("\texports "); //$NON-NLS-1$ - buffer.append(this.exports[i].toString()); - } - } - if (this.uses != null) { - buffer.append('\n'); - for (char[] cs : this.uses) { - buffer.append(cs); - buffer.append(';').append('\n'); - } - } - if (this.provides != null) { - buffer.append('\n'); - for(Service ser : this.provides) { - buffer.append(ser.toString()); - } - } - buffer.append('\n').append('}').toString(); - } -} \ No newline at end of file diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/BatchCompilerRequestor.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/BatchCompilerRequestor.java deleted file mode 100644 index 1346de8..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/BatchCompilerRequestor.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Gauthier JACQUES - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.ICompilerRequestor; - -public class BatchCompilerRequestor implements ICompilerRequestor { - - private final Main compiler; - private int lineDelta = 0; - - public BatchCompilerRequestor(Main compiler) { - this.compiler = compiler; - } - - @Override - public void acceptResult(CompilationResult compilationResult) { - if (compilationResult.lineSeparatorPositions != null) { - int unitLineCount = compilationResult.lineSeparatorPositions.length; - this.lineDelta += unitLineCount; - if (this.compiler.showProgress && this.lineDelta > 2000) { - // in -log mode, dump a dot every 2000 lines compiled - this.compiler.logger.logProgress(); - this.lineDelta = 0; - } - } - this.compiler.logger.startLoggingSource(compilationResult); - if (compilationResult.hasProblems() || compilationResult.hasTasks()) { - this.compiler.logger.logProblems(compilationResult.getAllProblems(), compilationResult.compilationUnit.getContents(), this.compiler); - reportProblems(compilationResult); - } - this.compiler.outputClassFiles(compilationResult); - this.compiler.logger.endLoggingSource(); - } - - protected void reportProblems(CompilationResult result) { - // Nothing to do - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java deleted file mode 100644 index 4617f36..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java +++ /dev/null @@ -1,395 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 440687 - [compiler][batch][null] improve command line option for external annotations - * Lars Vogel - Contributions for - * Bug 473178 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Stream; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.parser.Parser; -import org.eclipse.jdt.internal.compiler.parser.ScannerHelper; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; -import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; -import org.eclipse.jdt.internal.compiler.util.Util; - -@SuppressWarnings({"rawtypes", "unchecked"}) -public class ClasspathDirectory extends ClasspathLocation { - -private Hashtable directoryCache; -private final String[] missingPackageHolder = new String[1]; -private final int mode; // ability to only consider one kind of files (source vs. binaries), by default use both -private final String encoding; // only useful if referenced in the source path -private Hashtable> packageSecondaryTypes = null; -Map options; - -ClasspathDirectory(File directory, String encoding, int mode, - AccessRuleSet accessRuleSet, String destinationPath, Map options) { - super(accessRuleSet, destinationPath); - this.mode = mode; - this.options = options; - try { - this.path = directory.getCanonicalPath(); - } catch (IOException e) { - // should not happen as we know that the file exists - this.path = directory.getAbsolutePath(); - } - if (!this.path.endsWith(File.separator)) - this.path += File.separator; - this.directoryCache = new Hashtable(11); - this.encoding = encoding; -} -String[] directoryList(String qualifiedPackageName) { - if (File.separatorChar != '/' && qualifiedPackageName.indexOf('/') != -1) { - qualifiedPackageName = qualifiedPackageName.replace('/', File.separatorChar); - } - String[] dirList = (String[]) this.directoryCache.get(qualifiedPackageName); - if (dirList == this.missingPackageHolder) return null; // package exists in another classpath directory or jar - if (dirList != null) return dirList; - - File dir = new File(this.path + qualifiedPackageName); - notFound : if (dir.isDirectory()) { - // must protect against a case insensitive File call - // walk the qualifiedPackageName backwards looking for an uppercase character before the '/' - int index = qualifiedPackageName.length(); - int last = qualifiedPackageName.lastIndexOf(File.separatorChar); - while (--index > last && !ScannerHelper.isUpperCase(qualifiedPackageName.charAt(index))){/*empty*/} - if (index > last) { - if (last == -1) { - if (!doesFileExist(qualifiedPackageName, Util.EMPTY_STRING)) - break notFound; - } else { - String packageName = qualifiedPackageName.substring(last + 1); - String parentPackage = qualifiedPackageName.substring(0, last); - if (!doesFileExist(packageName, parentPackage)) - break notFound; - } - } - if ((dirList = dir.list()) == null) - dirList = CharOperation.NO_STRINGS; - this.directoryCache.put(qualifiedPackageName, dirList); - return dirList; - } - this.directoryCache.put(qualifiedPackageName, this.missingPackageHolder); - return null; -} -boolean doesFileExist(String fileName, String qualifiedPackageName) { - String[] dirList = directoryList(qualifiedPackageName); - if (dirList == null) return false; // most common case - - for (int i = dirList.length; --i >= 0;) - if (fileName.equals(dirList[i])) - return true; - return false; -} -@Override -public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { - return null; -} -private ClasspathAnswer findClassInternal(char[] typeName, String qualifiedPackageName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (!isPackage(qualifiedPackageName, null)) return null; // most common case TODO(SHMOD): use module name from this.module? - String fileName = new String(typeName); - boolean binaryExists = ((this.mode & BINARY) != 0) && doesFileExist(fileName + SUFFIX_STRING_class, qualifiedPackageName); - boolean sourceExists = ((this.mode & SOURCE) != 0) && doesFileExist(fileName + SUFFIX_STRING_java, qualifiedPackageName); - if (sourceExists && !asBinaryOnly) { - String fullSourcePath = this.path + qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - 6) + SUFFIX_STRING_java; - CompilationUnit unit = new CompilationUnit(null, fullSourcePath, this.encoding, this.destinationPath); - unit.module = this.module == null ? null : this.module.name(); - if (!binaryExists) - return new ClasspathAnswer(unit, - fetchAccessRestriction(qualifiedBinaryFileName), this); - String fullBinaryPath = this.path + qualifiedBinaryFileName; - long binaryModified = new File(fullBinaryPath).lastModified(); - long sourceModified = new File(fullSourcePath).lastModified(); - if (sourceModified > binaryModified) - return new ClasspathAnswer(unit, - fetchAccessRestriction(qualifiedBinaryFileName), this); - } - if (binaryExists) { - try { - ClassFileReader reader = ClassFileReader.read(this.path + qualifiedBinaryFileName); - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=321115, package names are to be treated case sensitive. - String typeSearched = qualifiedPackageName.length() > 0 ? - qualifiedPackageName.replace(File.separatorChar, '/') + "/" + fileName //$NON-NLS-1$ - : fileName; - if (!CharOperation.equals(reader.getName(), typeSearched.toCharArray())) { - reader = null; - } - if (reader != null) { - char[] modName = reader.moduleName != null ? reader.moduleName : this.module != null ? this.module.name() : null; - return new ClasspathAnswer( - reader, - fetchAccessRestriction(qualifiedBinaryFileName), - modName, - this); - } - } catch (IOException | ClassFormatException e) { - // treat as if file is missing - } - } - return null; -} -public ClasspathAnswer findSecondaryInClass(char[] typeName, String qualifiedPackageName, String qualifiedBinaryFileName) { - //"package-info" is a reserved class name and can never be a secondary type (it is much faster to stop the search here). - if(CharOperation.equals(TypeConstants.PACKAGE_INFO_NAME, typeName)) { - return null; - } - - String typeNameString = new String(typeName); - String moduleName = this.module != null ? String.valueOf(this.module.name()) : null; // TODO(SHMOD): test for ModuleBinding.ANY & UNNAMED - boolean prereqs = this.options != null && isPackage(qualifiedPackageName, moduleName) && ((this.mode & SOURCE) != 0) && doesFileExist(typeNameString + SUFFIX_STRING_java, qualifiedPackageName); - return prereqs ? null : findSourceSecondaryType(typeNameString, qualifiedPackageName, qualifiedBinaryFileName); /* only secondary types */ -} - -@Override -public boolean hasAnnotationFileFor(String qualifiedTypeName) { - int pos = qualifiedTypeName.lastIndexOf('/'); - if (pos != -1 && (pos + 1 < qualifiedTypeName.length())) { - String fileName = qualifiedTypeName.substring(pos + 1) + ExternalAnnotationProvider.ANNOTATION_FILE_SUFFIX; - return doesFileExist(fileName, qualifiedTypeName.substring(0, pos)); - } - return false; -} -@Override -public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { - return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); -} -@Override -public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (File.separatorChar == '/') - return findClassInternal(typeName, qualifiedPackageName, qualifiedBinaryFileName, asBinaryOnly); - - return findClassInternal(typeName, qualifiedPackageName.replace('/', File.separatorChar), - qualifiedBinaryFileName.replace('/', File.separatorChar), asBinaryOnly); -} -/** - * Add all the secondary types in the package - */ -private Hashtable getSecondaryTypes(String qualifiedPackageName) { - Hashtable packageEntry = new Hashtable<>(); - - String[] dirList = (String[]) this.directoryCache.get(qualifiedPackageName); - if (dirList == this.missingPackageHolder // package exists in another classpath directory or jar - || dirList == null) - return packageEntry; - - File dir = new File(this.path + qualifiedPackageName); - File[] listFiles = dir.isDirectory() ? dir.listFiles() : null; - if (listFiles == null) return packageEntry; - - for (int i = 0, l = listFiles.length; i < l; ++i) { - File f = listFiles[i]; - if (f.isDirectory()) continue; - String s = f.getAbsolutePath(); - if (s == null) continue; - if (!(s.endsWith(SUFFIX_STRING_java) || s.endsWith(SUFFIX_STRING_JAVA))) continue; - CompilationUnit cu = new CompilationUnit(null, s, this.encoding, this.destinationPath); - CompilationResult compilationResult = new CompilationResult(s.toCharArray(), 1, 1, 10); - ProblemReporter problemReporter = - new ProblemReporter( - DefaultErrorHandlingPolicies.proceedWithAllProblems(), - new CompilerOptions(this.options), - new DefaultProblemFactory()); - Parser parser = new Parser(problemReporter, false); - parser.reportSyntaxErrorIsRequired = false; - - CompilationUnitDeclaration unit = parser.parse(cu, compilationResult); - org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = unit != null ? unit.types : null; - if (types == null) continue; - for (int j = 0, k = types.length; j < k; j++) { - TypeDeclaration type = types[j]; - char[] name = type.isSecondary() ? type.name : null; // add only secondary types - if (name != null) - packageEntry.put(new String(name), s); - } - } - return packageEntry; -} -private ClasspathAnswer findSourceSecondaryType(String typeName, String qualifiedPackageName, String qualifiedBinaryFileName) { - - if (this.packageSecondaryTypes == null) this.packageSecondaryTypes = new Hashtable<>(); - Hashtable packageEntry = this.packageSecondaryTypes.get(qualifiedPackageName); - if (packageEntry == null) { - packageEntry = getSecondaryTypes(qualifiedPackageName); - this.packageSecondaryTypes.put(qualifiedPackageName, packageEntry); - } - String fileName = packageEntry.get(typeName); - return fileName != null ? new ClasspathAnswer(new CompilationUnit(null, - fileName, this.encoding, this.destinationPath), - fetchAccessRestriction(qualifiedBinaryFileName), this) : null; -} - - -@Override -public char[][][] findTypeNames(String qualifiedPackageName, String moduleName) { - if (!isPackage(qualifiedPackageName, moduleName)) { - return null; // most common case - } - File dir = new File(this.path + qualifiedPackageName); - if (!dir.exists() || !dir.isDirectory()) { - return null; - } - String[] listFiles = dir.list(new FilenameFilter() { - @Override - public boolean accept(File directory1, String name) { - String fileName = name.toLowerCase(); - return fileName.endsWith(".class") || fileName.endsWith(".java"); //$NON-NLS-1$ //$NON-NLS-2$ - } - }); - int length; - if (listFiles == null || (length = listFiles.length) == 0) { - return null; - } - Set secondary = getSecondaryTypes(qualifiedPackageName).keySet(); - char[][][] result = new char[length + secondary.size()][][]; - char[][] packageName = CharOperation.splitOn(File.separatorChar, qualifiedPackageName.toCharArray()); - for (int i = 0; i < length; i++) { - String fileName = listFiles[i]; - int indexOfLastDot = fileName.indexOf('.'); - String typeName = indexOfLastDot > 0 ? fileName.substring(0, indexOfLastDot) : fileName; - result[i] = CharOperation.arrayConcat(packageName, typeName.toCharArray()); - } - if (secondary.size() > 0) { - int idx = length; - for (String type : secondary) { - result[idx++] = CharOperation.arrayConcat(packageName, type.toCharArray()); - } - } - return result; -} -@Override -public void initialize() throws IOException { - // nothing to do -} -@Override -public char[][] getModulesDeclaringPackage(String qualifiedPackageName, /*@Nullable*/String moduleName) { - String qp2 = File.separatorChar == '/' ? qualifiedPackageName : qualifiedPackageName.replace('/', File.separatorChar); - return singletonModuleNameIf(directoryList(qp2) != null); -} -@Override -public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { - String qp2 = File.separatorChar == '/' ? qualifiedPackageName : qualifiedPackageName.replace('/', File.separatorChar); - String[] dirList = directoryList(qp2); - if (dirList != null) { - for (String entry : dirList) { - String entryLC = entry.toLowerCase(); - if (entryLC.endsWith(SUFFIX_STRING_java) || entryLC.endsWith(SUFFIX_STRING_class)) - return true; - } - } - return false; -} -@Override -public boolean hasCUDeclaringPackage(String qualifiedPackageName, Function pkgNameExtractor) { - String qp2 = File.separatorChar == '/' ? qualifiedPackageName : qualifiedPackageName.replace('/', File.separatorChar); - String[] directoryList = directoryList(qp2); - if(directoryList == null) - return false; - return Stream.of(directoryList).anyMatch(entry -> { - String entryLC = entry.toLowerCase(); - boolean hasDeclaration = false; - String fullPath = this.path + qp2 + "/" + entry; //$NON-NLS-1$ - String pkgName = null; - if (entryLC.endsWith(SUFFIX_STRING_class)) { - return true; - } else if (entryLC.endsWith(SUFFIX_STRING_java)) { - CompilationUnit cu = new CompilationUnit(null, fullPath, this.encoding); - pkgName = pkgNameExtractor.apply(cu); - } - if (pkgName != null && pkgName.equals(qp2.replace(File.separatorChar, '.'))) - hasDeclaration = true; - return hasDeclaration; - }); -} - -@Override -public char[][] listPackages() { - Set packageNames = new HashSet<>(); - try { - Path basePath = Path.of(this.path); - Files.walkFileTree(basePath, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { - if (file.toString().toLowerCase().endsWith(SUFFIX_STRING_class)) { - packageNames.add(file.getParent().relativize(basePath).toString().replace('/', '.')); - } - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException e) { - // treat as if files are missing - } - return packageNames.stream().map(String::toCharArray).toArray(char[][]::new); -} - -@Override -public void reset() { - super.reset(); - this.directoryCache = new Hashtable(11); -} -@Override -public String toString() { - return "ClasspathDirectory " + this.path; //$NON-NLS-1$ -} -@Override -public char[] normalizedPath() { - if (this.normalizedPath == null) { - this.normalizedPath = this.path.toCharArray(); - if (File.separatorChar == '\\') { - CharOperation.replace(this.normalizedPath, '\\', '/'); - } - } - return this.normalizedPath; -} -@Override -public String getPath() { - return this.path; -} -@Override -public int getMode() { - return this.mode; -} -@Override -public IModule getModule() { - return this.module; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java deleted file mode 100644 index 0a69cb9..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJar.java +++ /dev/null @@ -1,332 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 440477 - [null] Infrastructure for feeding external annotations into compilation - * Bug 440687 - [compiler][batch][null] improve command line option for external annotations - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator; -import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.util.ManifestAnalyzer; -import org.eclipse.jdt.internal.compiler.util.SuffixConstants; -import org.eclipse.jdt.internal.compiler.util.Util; - -@SuppressWarnings({"rawtypes", "unchecked"}) -public class ClasspathJar extends ClasspathLocation { - -protected File file; -protected ZipFile zipFile; -protected ZipFile annotationZipFile; -protected boolean closeZipFileAtEnd; -protected Set packageCache; -protected List annotationPaths; - -public ClasspathJar(File file, boolean closeZipFileAtEnd, - AccessRuleSet accessRuleSet, String destinationPath) { - super(accessRuleSet, destinationPath); - this.file = file; - this.closeZipFileAtEnd = closeZipFileAtEnd; -} - -@Override -public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { - // expected to be called once only - if multiple calls desired, consider - // using a cache - try { - initialize(); - ArrayList result = new ArrayList<>(); - ZipEntry manifest = this.zipFile.getEntry(TypeConstants.META_INF_MANIFEST_MF); - if (manifest != null) { // non-null implies regular file - ManifestAnalyzer analyzer = new ManifestAnalyzer(); - boolean success; - try (InputStream inputStream = this.zipFile.getInputStream(manifest)) { - success = analyzer.analyzeManifestContents(inputStream); - } - List calledFileNames = analyzer.getCalledFileNames(); - if (problemReporter != null) { - if (!success || analyzer.getClasspathSectionsCount() == 1 && calledFileNames == null) { - problemReporter.invalidClasspathSection(getPath()); - } else if (analyzer.getClasspathSectionsCount() > 1) { - problemReporter.multipleClasspathSections(getPath()); - } - } - if (calledFileNames != null) { - Iterator calledFilesIterator = calledFileNames.iterator(); - String directoryPath = getPath(); - int lastSeparator = directoryPath.lastIndexOf(File.separatorChar); - directoryPath = directoryPath.substring(0, lastSeparator + 1); // potentially empty (see bug 214731) - while (calledFilesIterator.hasNext()) { - File linkedFile = new File(directoryPath + (String) calledFilesIterator.next()); - if (linkedFile.isFile()) { - result.add(new ClasspathJar(linkedFile, this.closeZipFileAtEnd, this.accessRuleSet, this.destinationPath)); - } - } - } - } - return result; - } catch (IOException | IllegalArgumentException e) { - // JRE 9 could throw an IAE if the path is incorrect. We are to ignore such - // linked jars - return null; - } -} -@Override -public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { - return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); -} -@Override -public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - - try { - IBinaryType reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName); - if (reader != null) { - char[] modName = this.module == null ? null : this.module.name(); - if (reader instanceof ClassFileReader) { - ClassFileReader classReader = (ClassFileReader) reader; - if (classReader.moduleName == null) - classReader.moduleName = modName; - else - modName = classReader.moduleName; - } - searchPaths: - if (this.annotationPaths != null) { - String qualifiedClassName = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length()-SuffixConstants.EXTENSION_CLASS.length()-1); - for (String annotationPath : this.annotationPaths) { - try { - if (this.annotationZipFile == null) { - this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(annotationPath, null); - } - reader = ExternalAnnotationDecorator.create(reader, annotationPath, qualifiedClassName, this.annotationZipFile); - - if (reader.getExternalAnnotationStatus() == ExternalAnnotationStatus.TYPE_IS_ANNOTATED) { - break searchPaths; - } - } catch (IOException e) { - // don't let error on annotations fail class reading - } - } - // location is configured for external annotations, but no .eea found, decorate in order to answer NO_EEA_FILE: - reader = new ExternalAnnotationDecorator(reader, null); - } - return new ClasspathAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), modName, this); - } - } catch (ClassFormatException | IOException e) { - // treat as if class file is missing - } - return null; -} -@Override -public boolean hasAnnotationFileFor(String qualifiedTypeName) { - if (this.zipFile == null) - return false; - return this.zipFile.getEntry(qualifiedTypeName+ExternalAnnotationProvider.ANNOTATION_FILE_SUFFIX) != null; -} -@Override -public char[][][] findTypeNames(final String qualifiedPackageName, String moduleName) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - final char[] packageArray = qualifiedPackageName.toCharArray(); - final ArrayList answers = new ArrayList(); - nextEntry : for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { - String fileName = ((ZipEntry) e.nextElement()).getName(); - - // add the package name & all of its parent packages - int last = fileName.lastIndexOf('/'); - if (last > 0) { - // extract the package name - String packageName = fileName.substring(0, last); - if (!qualifiedPackageName.equals(packageName)) - continue nextEntry; - int indexOfDot = fileName.lastIndexOf('.'); - if (indexOfDot != -1) { - String typeName = fileName.substring(last + 1, indexOfDot); - answers.add( - CharOperation.arrayConcat( - CharOperation.splitOn('/', packageArray), - typeName.toCharArray())); - } - } - } - int size = answers.size(); - if (size != 0) { - char[][][] result = new char[size][][]; - answers.toArray(result); - return result; - } - return null; -} - -@Override -public void initialize() throws IOException { - if (this.zipFile == null) { - this.zipFile = new ZipFile(this.file); - } -} -void acceptModule(ClassFileReader reader) { - if (reader != null) { - acceptModule(reader.getModuleDeclaration()); - } -} -void acceptModule(byte[] content) { - if (content == null) - return; - ClassFileReader reader = null; - try { - reader = new ClassFileReader(content, IModule.MODULE_INFO_CLASS.toCharArray()); - } catch (ClassFormatException e) { - e.printStackTrace(); - } - if (reader != null && reader.getModuleDeclaration() != null) { - acceptModule(reader); - } -} -protected void addToPackageCache(String fileName, boolean endsWithSep) { - int last = endsWithSep ? fileName.length() : fileName.lastIndexOf('/'); - while (last > 0) { - // extract the package name - String packageName = fileName.substring(0, last); - if (this.packageCache.contains(packageName)) - return; - this.packageCache.add(packageName); - last = packageName.lastIndexOf('/'); - } -} -@Override -public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { - if (this.packageCache != null) - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); - - this.packageCache = new HashSet<>(41); - this.packageCache.add(Util.EMPTY_STRING); - - for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { - String fileName = ((ZipEntry) e.nextElement()).getName(); - addToPackageCache(fileName, false); - } - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); -} -@Override -public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { - qualifiedPackageName += '/'; - for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { - String fileName = e.nextElement().getName(); - if (fileName.startsWith(qualifiedPackageName) && fileName.length() > qualifiedPackageName.length()) { - String tail = fileName.substring(qualifiedPackageName.length()); - if (tail.indexOf('/') != -1) - continue; - if (tail.toLowerCase().endsWith(SUFFIX_STRING_class)) - return true; - } - } - return false; -} - -@Override -public char[][] listPackages() { - Set packageNames = new HashSet<>(); - for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { - String fileName = e.nextElement().getName(); - int lastSlash = fileName.lastIndexOf('/'); - if (lastSlash != -1 && fileName.toLowerCase().endsWith(SUFFIX_STRING_class)) - packageNames.add(fileName.substring(0, lastSlash).replace('/', '.')); - } - return packageNames.stream().map(String::toCharArray).toArray(char[][]::new); -} - -@Override -public void reset() { - super.reset(); - if (this.closeZipFileAtEnd) { - if (this.zipFile != null) { - try { - this.zipFile.close(); - } catch(IOException e) { - // ignore - } - this.zipFile = null; - } - if (this.annotationZipFile != null) { - try { - this.annotationZipFile.close(); - } catch(IOException e) { - // ignore - } - this.annotationZipFile = null; - } - } - this.packageCache = null; - this.annotationPaths = null; -} -@Override -public String toString() { - return "Classpath for jar file " + this.file.getPath(); //$NON-NLS-1$ -} -@Override -public char[] normalizedPath() { - if (this.normalizedPath == null) { - String path2 = this.getPath(); - char[] rawName = path2.toCharArray(); - if (File.separatorChar == '\\') { - CharOperation.replace(rawName, '\\', '/'); - } - this.normalizedPath = CharOperation.subarray(rawName, 0, CharOperation.lastIndexOf('.', rawName)); - } - return this.normalizedPath; -} -@Override -public String getPath() { - if (this.path == null) { - try { - this.path = this.file.getCanonicalPath(); - } catch (IOException e) { - // in case of error, simply return the absolute path - this.path = this.file.getAbsolutePath(); - } - } - return this.path; -} -@Override -public int getMode() { - return BINARY; -} - -@Override -public IModule getModule() { - return this.module; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java deleted file mode 100644 index 6f2abdc..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247.java +++ /dev/null @@ -1,308 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018, 2023 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * Contributors: - * IBM Corporation - initial API and implementation - * Christoph Läubrich - use Filesystem helper method - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.util.CtSym; -import org.eclipse.jdt.internal.compiler.util.JRTUtil; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class ClasspathJep247 extends ClasspathJrt { - - protected java.nio.file.FileSystem fs; - protected String compliance = null; - protected long jdklevel; - protected String releaseInHex = null; - protected String[] subReleases = null; - protected Path releasePath = null; - protected Set packageCache; - protected File jdkHome; - protected String modulePath = null; - - public ClasspathJep247(File jdkHome, String release, AccessRuleSet accessRuleSet) { - super(jdkHome, false, accessRuleSet, null); - this.compliance = release; - this.jdklevel = CompilerOptions.releaseToJDKLevel(this.compliance); - this.jdkHome = jdkHome; - this.file = new File(new File(jdkHome, "lib"), "jrt-fs.jar"); //$NON-NLS-1$ //$NON-NLS-2$ - } - @Override - public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { - return null; - } - @Override - public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { - return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); - } - @Override - public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - - try { - //TODO: Check if any conversion needed for path separator - IBinaryType reader = null; - byte[] content = null; - qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ - Path p = null; - if (this.subReleases != null && this.subReleases.length > 0) { - for (String rel : this.subReleases) { - p = this.fs.getPath(rel, qualifiedBinaryFileName); - if (Files.exists(p)) { - content = JRTUtil.safeReadBytes(p); - if (content != null) - break; - } - } - } else { - p = this.fs.getPath(this.releaseInHex, qualifiedBinaryFileName); - content = JRTUtil.safeReadBytes(p); - } - if (content != null) { - reader = new ClassFileReader(p.toUri(), content, qualifiedBinaryFileName.toCharArray()); - reader = maybeDecorateForExternalAnnotations(qualifiedBinaryFileName, reader); - char[] modName = moduleName != null ? moduleName.toCharArray() : null; - return new ClasspathAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), modName, this); - } - } catch (ClassFormatException | IOException e) { - // continue - } - return null; - } - - @Override - public void initialize() throws IOException { - if (this.compliance == null) { - return; - } - this.releaseInHex = CtSym.getReleaseCode(this.compliance); - Path filePath = this.jdkHome.toPath().resolve("lib").resolve("ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ - if (!Files.exists(filePath)) { - return; - } - this.fs = JRTUtil.getJarFileSystem(filePath); - this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$ - if (!Files.exists(this.fs.getPath(this.releaseInHex))) { - throw new IllegalArgumentException("release " + this.compliance + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ - } - super.initialize(); - } - @Override - public void loadModules() { - // Modules below level 9 are not dealt with here. Leave it to ClasspathJrt - if (this.jdklevel <= ClassFileConstants.JDK1_8) { - super.loadModules(); - return; - } - final Path modPath = this.fs.getPath(this.releaseInHex + "-modules"); //$NON-NLS-1$ - if (!Files.exists(modPath)) { - throw new IllegalArgumentException("release " + this.compliance + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ - } - this.modulePath = this.file.getPath() + "|" + modPath.toString(); //$NON-NLS-1$ - Map cache = ModulesCache.computeIfAbsent(this.modulePath, key -> { - Map newCache = new HashMap<>(); - try (DirectoryStream stream = Files.newDirectoryStream(modPath)) { - for (final java.nio.file.Path subdir: stream) { - Files.walkFileTree(subdir, new FileVisitor() { - - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) - throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { - byte[] content = null; - if (Files.exists(f)) { - content = JRTUtil.safeReadBytes(f); - if (content == null) { - return FileVisitResult.CONTINUE; - } - try { - ClasspathJep247.this.acceptModule(new ClassFileReader(f.toUri(), content, f.getFileName().toString().toCharArray()), newCache); - } catch (ClassFormatException e) { - e.printStackTrace(); - } - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } catch (IOException e) { - String error = "Failed to walk modules for " + key; //$NON-NLS-1$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - return null; - } - } - return newCache.isEmpty() ? null : Collections.unmodifiableMap(newCache); - }); - - this.moduleNamesCache.addAll(cache.keySet()); - } - - @Override - void acceptModule(ClassFileReader reader, Map cache) { - // Modules below level 9 are not dealt with here. Leave it to ClasspathJrt - if (this.jdklevel <= ClassFileConstants.JDK1_8) { - super.acceptModule(reader, cache); - return; - } - if (reader != null) { - IModule moduleDecl = reader.getModuleDeclaration(); - if (moduleDecl != null) { - cache.put(String.valueOf(moduleDecl.name()), moduleDecl); - } - } - } - protected void addToPackageCache(String packageName, boolean endsWithSep) { - if (this.packageCache.contains(packageName)) - return; - this.packageCache.add(packageName); - } - @Override - public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { - if (this.packageCache == null) { - this.packageCache = new HashSet<>(41); - this.packageCache.add(Util.EMPTY_STRING); - List sub = new ArrayList<>(); - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String rel = JRTUtil.sanitizedFileName(subdir); - if (rel.contains(this.releaseInHex)) { - sub.add(rel); - } else { - continue; - } - Files.walkFileTree(subdir, new FileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { - if (dir.getNameCount() <= 1) - return FileVisitResult.CONTINUE; - Path relative = dir.subpath(1, dir.getNameCount()); - addToPackageCache(relative.toString(), false); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } catch (IOException e) { - String error = "Failed to find module " + moduleName + " defining package " + qualifiedPackageName //$NON-NLS-1$ //$NON-NLS-2$ - + " in release " + this.releasePath + " in " + this; //$NON-NLS-1$ //$NON-NLS-2$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - } - } - this.subReleases = sub.toArray(new String[sub.size()]); - } - if (moduleName == null) { - // Delegate to the boss, even if it means inaccurate error reporting at times - List mods = JRTUtil.getModulesDeclaringPackage(this.file, qualifiedPackageName, moduleName); - return CharOperation.toCharArrays(mods); - } - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); - } - - @Override - public String toString() { - return "Classpath for JEP 247 for JDK " + this.file.getPath(); //$NON-NLS-1$ - } - @Override - public char[] normalizedPath() { - if (this.normalizedPath == null) { - String path2 = this.getPath(); - char[] rawName = path2.toCharArray(); - if (File.separatorChar == '\\') { - CharOperation.replace(rawName, '\\', '/'); - } - this.normalizedPath = CharOperation.subarray(rawName, 0, CharOperation.lastIndexOf('.', rawName)); - } - return this.normalizedPath; - } - @Override - public String getPath() { - if (this.path == null) { - try { - this.path = this.file.getCanonicalPath(); - } catch (IOException e) { - // in case of error, simply return the absolute path - this.path = this.file.getAbsolutePath(); - } - } - return this.path; - } - @Override - public int getMode() { - return BINARY; - } - @Override - public boolean forbidsExportFrom(String modName) { - return servesModule(modName.toCharArray()); - } - -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java deleted file mode 100644 index 0e8c614..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJep247Jdk12.java +++ /dev/null @@ -1,322 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2019, 2022 IBM Corporation. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v20.html - * - * Contributors: - * IBM Corporation - initial API and implementation - * Christoph Läubrich - use Filesystem helper method - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.util.CtSym; -import org.eclipse.jdt.internal.compiler.util.JRTUtil; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class ClasspathJep247Jdk12 extends ClasspathJep247 { - - Map modules; - static String MODULE_INFO = "module-info.sig"; //$NON-NLS-1$ - - public ClasspathJep247Jdk12(File jdkHome, String release, AccessRuleSet accessRuleSet) { - super(jdkHome, release, accessRuleSet); - } - @Override - public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { - return null; - } - @Override - public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { - return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); - } - @Override - public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - - try { - IBinaryType reader = null; - Path p = null; - byte[] content = null; - char[] foundModName = null; - qualifiedBinaryFileName = qualifiedBinaryFileName.replace(".class", ".sig"); //$NON-NLS-1$ //$NON-NLS-2$ - if (this.subReleases != null && this.subReleases.length > 0) { - done: for (String rel : this.subReleases) { - if (moduleName == null) { - p = this.fs.getPath(rel); - try (DirectoryStream stream = Files.newDirectoryStream(p)) { - for (final java.nio.file.Path subdir: stream) { - p = this.fs.getPath(rel, JRTUtil.sanitizedFileName(subdir), qualifiedBinaryFileName); - if (Files.exists(p)) { - content = JRTUtil.safeReadBytes(p); - foundModName = JRTUtil.sanitizedFileName(subdir).toCharArray(); - if (content != null) - break done; - } - } - } - } else { - p = this.fs.getPath(rel, moduleName, qualifiedBinaryFileName); - if (Files.exists(p)) { - content = JRTUtil.safeReadBytes(p); - if (content != null) - break; - } - } - } - } else { - p = this.fs.getPath(this.releaseInHex, qualifiedBinaryFileName); - content = JRTUtil.safeReadBytes(p); - } - if (content != null) { - reader = new ClassFileReader(p.toUri(), content, qualifiedBinaryFileName.toCharArray()); - reader = maybeDecorateForExternalAnnotations(qualifiedBinaryFileName, reader); - char[] modName = moduleName != null ? moduleName.toCharArray() : foundModName; - return new ClasspathAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), modName, this); - } - } catch (ClassFormatException | IOException e) { - // continue - } - return null; - } - - @Override - public void initialize() throws IOException { - if (this.compliance == null) { - return; - } - if (this.fs != null) { - super.initialize(); - return; - } - this.releaseInHex = CtSym.getReleaseCode(this.compliance); - Path filePath = this.jdkHome.toPath().resolve("lib").resolve("ct.sym"); //$NON-NLS-1$ //$NON-NLS-2$ - if (!Files.exists(filePath)) { - return; - } - this.fs = JRTUtil.getJarFileSystem(filePath); - this.releasePath = this.fs.getPath("/"); //$NON-NLS-1$ - if (!Files.exists(this.fs.getPath(this.releaseInHex))) { - throw new IllegalArgumentException("release " + this.compliance + " is not found in the system"); //$NON-NLS-1$//$NON-NLS-2$ - } - List sub = new ArrayList<>(); - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String rel = JRTUtil.sanitizedFileName(subdir); - if (rel.contains(this.releaseInHex)) - sub.add(rel); - } - this.subReleases = sub.toArray(new String[sub.size()]); - } catch (IOException e) { - String error = "Failed to walk subreleases for release " + this.releasePath + " in " + filePath; //$NON-NLS-1$ //$NON-NLS-2$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - } - } - super.initialize(); - } - @Override - public void loadModules() { - // Modules below level 9 are not dealt with here. Leave it to ClasspathJrt - if (this.jdklevel <= ClassFileConstants.JDK1_8) { - super.loadModules(); - return; - } - final Path modPath = this.fs.getPath(this.releaseInHex); - this.modulePath = this.file.getPath() + "|" + modPath.toString(); //$NON-NLS-1$ - Map cache = ModulesCache.computeIfAbsent(this.modulePath, key -> { - HashMap newCache = new HashMap<>(); - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String rel = JRTUtil.sanitizedFileName(subdir); - if (!rel.contains(this.releaseInHex)) { - continue; - } - Files.walkFileTree(subdir, Collections.emptySet(), 2, new FileVisitor() { - - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) - throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { - if (attrs.isDirectory() || f.getNameCount() < 3) { - return FileVisitResult.CONTINUE; - } - if (f.getFileName().toString().equals(MODULE_INFO) && Files.exists(f)) { - byte[] content = JRTUtil.safeReadBytes(f); - if (content == null) { - return FileVisitResult.CONTINUE; - } - Path m = f.subpath(1, f.getNameCount() - 1); - String name = JRTUtil.sanitizedFileName(m); - ClasspathJep247Jdk12.this.acceptModule(name, content, newCache); - } - return FileVisitResult.SKIP_SIBLINGS; - } - - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } catch (IOException e) { - String error = "Failed to walk modules for " + key; //$NON-NLS-1$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - return null; - } - } - return newCache.isEmpty() ? null : Collections.unmodifiableMap(newCache); - }); - this.modules = cache; - this.moduleNamesCache.addAll(cache.keySet()); - } - @Override - public Collection getModuleNames(Collection limitModule, Function getModule) { - return selectModules(this.moduleNamesCache, limitModule, getModule); - } - @Override - public IModule getModule(char[] moduleName) { - // Modules below level 9 are not dealt with here. Leave it to ClasspathJrt - if (this.jdklevel <= ClassFileConstants.JDK1_8) { - return super.getModule(moduleName); - } - if (this.modules != null) { - return this.modules.get(String.valueOf(moduleName)); - } - return null; - } - void acceptModule(String name, byte[] content, Map cache) { - if (content == null) - return; - - if (cache.containsKey(name)) - return; - - ClassFileReader reader = null; - try { - reader = new ClassFileReader(content, IModule.MODULE_INFO_CLASS.toCharArray()); - } catch (ClassFormatException e) { - e.printStackTrace(); - } - if (reader != null) { - acceptModule(reader, cache); - } - } - @Override - void acceptModule(ClassFileReader reader, Map cache) { - // Modules below level 9 are not dealt with here. Leave it to ClasspathJrt - if (this.jdklevel <= ClassFileConstants.JDK1_8) { - super.acceptModule(reader, cache); - return; - } - if (reader != null) { - IModule moduleDecl = reader.getModuleDeclaration(); - if (moduleDecl != null) { - cache.put(String.valueOf(moduleDecl.name()), moduleDecl); - } - } - } - @Override - public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { - if (this.jdklevel >= ClassFileConstants.JDK9) { - // Delegate to the boss, even if it means inaccurate error reporting at times - List mods = JRTUtil.getModulesDeclaringPackage(this.file, qualifiedPackageName, moduleName); - return CharOperation.toCharArrays(mods); - } - if (this.packageCache == null) { - this.packageCache = new HashSet<>(41); - this.packageCache.add(Util.EMPTY_STRING); - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - String rel = JRTUtil.sanitizedFileName(subdir); - if (!rel.contains(this.releaseInHex)) { - continue; - } - try (DirectoryStream stream2 = Files.newDirectoryStream(subdir)) { - for (final java.nio.file.Path subdir2: stream2) { - Files.walkFileTree(subdir2, new FileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { - if (dir.getNameCount() <= 2) - return FileVisitResult.CONTINUE; - Path relative = dir.subpath(2, dir.getNameCount()); - addToPackageCache(relative.toString(), false); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } - } - } catch (IOException e) { - String error = "Failed to find module " + moduleName + " defining package " + qualifiedPackageName //$NON-NLS-1$ //$NON-NLS-2$ - + " in release " + this.releasePath + " in " + this; //$NON-NLS-1$ //$NON-NLS-2$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - } - } - } - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJmod.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJmod.java deleted file mode 100644 index 2121857..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJmod.java +++ /dev/null @@ -1,189 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.zip.ZipEntry; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator; -import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus; -import org.eclipse.jdt.internal.compiler.util.SuffixConstants; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class ClasspathJmod extends ClasspathJar { - - public static char[] CLASSES = "classes".toCharArray(); //$NON-NLS-1$ - public static char[] CLASSES_FOLDER = "classes/".toCharArray(); //$NON-NLS-1$ - -public ClasspathJmod(File file, boolean closeZipFileAtEnd, - AccessRuleSet accessRuleSet, String destinationPath) { - super(file, closeZipFileAtEnd, accessRuleSet, destinationPath); -} - -@Override -public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { - // don't do anything - return null; -} -@Override -public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - - try { - qualifiedBinaryFileName = new String(CharOperation.append(CLASSES_FOLDER, qualifiedBinaryFileName.toCharArray())); - IBinaryType reader = ClassFileReader.read(this.zipFile, qualifiedBinaryFileName); - if (reader != null) { - char[] modName = this.module == null ? null : this.module.name(); - if (reader instanceof ClassFileReader) { - ClassFileReader classReader = (ClassFileReader) reader; - if (classReader.moduleName == null) - classReader.moduleName = modName; - else - modName = classReader.moduleName; - } - searchPaths: - if (this.annotationPaths != null) { - String qualifiedClassName = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length()-SuffixConstants.EXTENSION_CLASS.length()-1); - for (String annotationPath : this.annotationPaths) { - try { - if (this.annotationZipFile == null) { - this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(annotationPath, null); - } - reader = ExternalAnnotationDecorator.create(reader, annotationPath, qualifiedClassName, this.annotationZipFile); - - if (reader.getExternalAnnotationStatus() == ExternalAnnotationStatus.TYPE_IS_ANNOTATED) { - break searchPaths; - } - } catch (IOException e) { - // don't let error on annotations fail class reading - } - } - // location is configured for external annotations, but no .eea found, decorate in order to answer NO_EEA_FILE: - reader = new ExternalAnnotationDecorator(reader, null); - } - return new ClasspathAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), modName, this); - } - } catch (ClassFormatException | IOException e) { - // treat as if class file is missing - } - return null; -} -@Override -public boolean hasAnnotationFileFor(String qualifiedTypeName) { - qualifiedTypeName = new String(CharOperation.append(CLASSES_FOLDER, qualifiedTypeName.toCharArray())); - return this.zipFile.getEntry(qualifiedTypeName+ExternalAnnotationProvider.ANNOTATION_FILE_SUFFIX) != null; -} -@SuppressWarnings({ "rawtypes", "unchecked" }) -@Override -public char[][][] findTypeNames(final String qualifiedPackageName, String moduleName) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - final char[] packageArray = qualifiedPackageName.toCharArray(); - final ArrayList answers = new ArrayList(); - nextEntry : for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { - String fileName = ((ZipEntry) e.nextElement()).getName(); - - // add the package name & all of its parent packages - int first = CharOperation.indexOf(CLASSES_FOLDER, fileName.toCharArray(), false); - int last = fileName.lastIndexOf('/'); - if (last > 0) { - // extract the package name - String packageName = fileName.substring(first + 1, last); - if (!qualifiedPackageName.equals(packageName)) - continue nextEntry; - int indexOfDot = fileName.lastIndexOf('.'); - if (indexOfDot != -1) { - String typeName = fileName.substring(last + 1, indexOfDot); - answers.add( - CharOperation.arrayConcat( - CharOperation.splitOn('/', packageArray), - typeName.toCharArray())); - } - } - } - int size = answers.size(); - if (size != 0) { - char[][][] result = new char[size][][]; - answers.toArray(result); - return result; - } - return null; -} -@Override -public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { - if (this.packageCache != null) - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); - - this.packageCache = new HashSet<>(41); - this.packageCache.add(Util.EMPTY_STRING); - - for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { - char[] entryName = e.nextElement().getName().toCharArray(); - int index = CharOperation.indexOf('/', entryName); - if (index != -1) { - char[] folder = CharOperation.subarray(entryName, 0, index); - if (CharOperation.equals(CLASSES, folder)) { - char[] fileName = CharOperation.subarray(entryName, index + 1, entryName.length); - addToPackageCache(new String(fileName), false); - } - } - } - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); -} -@Override -public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { - qualifiedPackageName += '/'; - for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { - char[] entryName = e.nextElement().getName().toCharArray(); - int index = CharOperation.indexOf('/', entryName); - if (index != -1) { - char[] folder = CharOperation.subarray(entryName, 0, index); - if (CharOperation.equals(CLASSES, folder)) { - String fileName = new String(CharOperation.subarray(entryName, index + 1, entryName.length)); - if (fileName.startsWith(qualifiedPackageName) && fileName.length() > qualifiedPackageName.length()) { - String tail = fileName.substring(qualifiedPackageName.length()); - if (tail.indexOf('/') != -1) - continue; - if (tail.toLowerCase().endsWith(SUFFIX_STRING_class)) - return true; - } - } - } - } - return false; -} -@Override -public String toString() { - return "Classpath for JMod file " + this.file.getPath(); //$NON-NLS-1$ -} -@Override -public IModule getModule() { - return this.module; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java deleted file mode 100644 index ddce53f..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJrt.java +++ /dev/null @@ -1,416 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016, 2023 IBM Corporation. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.zip.ZipFile; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.env.IModule.IPackageExport; -import org.eclipse.jdt.internal.compiler.env.IMultiModuleEntry; -import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus; -import org.eclipse.jdt.internal.compiler.util.CtSym; -import org.eclipse.jdt.internal.compiler.util.JRTUtil; - -@SuppressWarnings({"rawtypes", "unchecked"}) -public class ClasspathJrt extends ClasspathLocation implements IMultiModuleEntry { - public File file; - protected ZipFile annotationZipFile; - protected boolean closeZipFileAtEnd; - protected static Map> ModulesCache = new ConcurrentHashMap<>(); - public final Set moduleNamesCache; - //private Set packageCache; - protected List annotationPaths; - - public ClasspathJrt(File file, boolean closeZipFileAtEnd, - AccessRuleSet accessRuleSet, String destinationPath) { - super(accessRuleSet, destinationPath); - this.file = file; - this.closeZipFileAtEnd = closeZipFileAtEnd; - this.moduleNamesCache = new HashSet<>(); - } - - @Override - public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { - return null; - } - @Override - public char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { - List modules = JRTUtil.getModulesDeclaringPackage(this.file, qualifiedPackageName, moduleName); - return CharOperation.toCharArrays(modules); - } - @Override - public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { - return JRTUtil.hasCompilationUnit(this.file, qualifiedPackageName, moduleName); - } - @Override - public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName) { - return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); - } - @Override - public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - - try { - IBinaryType reader = ClassFileReader.readFromModule(this.file, moduleName, qualifiedBinaryFileName, this.moduleNamesCache::contains); - - if (reader != null) { - reader = maybeDecorateForExternalAnnotations(qualifiedBinaryFileName, reader); - char[] answerModuleName = reader.getModule(); - if (answerModuleName == null && moduleName != null) - answerModuleName = moduleName.toCharArray(); - return new ClasspathAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), answerModuleName, this); - } - } catch (ClassFormatException | IOException e) { - // treat as if class file is missing - } - return null; - } - - protected IBinaryType maybeDecorateForExternalAnnotations(String qualifiedBinaryFileName, IBinaryType reader) { - searchPaths: - if (this.annotationPaths != null) { - int extensionPos = qualifiedBinaryFileName.lastIndexOf('.'); // extension could be .class or .sig - String qualifiedClassName = qualifiedBinaryFileName.substring(0, extensionPos); - for (String annotationPath : this.annotationPaths) { - try { - if (this.annotationZipFile == null) { - this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(annotationPath, null); - } - reader = ExternalAnnotationDecorator.create(reader, annotationPath, qualifiedClassName, this.annotationZipFile); - - if (reader.getExternalAnnotationStatus() == ExternalAnnotationStatus.TYPE_IS_ANNOTATED) { - break searchPaths; - } - } catch (IOException e) { - // don't let error on annotations fail class reading - } - } - // location is configured for external annotations, but no .eea found, decorate in order to answer NO_EEA_FILE: - reader = new ExternalAnnotationDecorator(reader, null); - } - return reader; - } - @Override - public boolean hasAnnotationFileFor(String qualifiedTypeName) { - return false; // TODO(SHMOD): implement - } - @Override - public char[][][] findTypeNames(final String qualifiedPackageName, final String moduleName) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - final char[] packageArray = qualifiedPackageName.toCharArray(); - final ArrayList answers = new ArrayList(); - - try { - JRTUtil.walkModuleImage(this.file, new JRTUtil.JrtFileVisitor() { - - @Override - public FileVisitResult visitPackage(java.nio.file.Path dir, java.nio.file.Path modPath, BasicFileAttributes attrs) throws IOException { - if (qualifiedPackageName.startsWith(dir.toString())) { - return FileVisitResult.CONTINUE; - } - return FileVisitResult.SKIP_SUBTREE; - } - - @Override - public FileVisitResult visitFile(java.nio.file.Path dir, java.nio.file.Path modPath, BasicFileAttributes attrs) throws IOException { - Path parent = dir.getParent(); - if (parent == null) - return FileVisitResult.CONTINUE; - if (!parent.toString().equals(qualifiedPackageName)) { - return FileVisitResult.CONTINUE; - } - String fileName = dir.getName(dir.getNameCount() - 1).toString(); - // The path already excludes the folders and all the '/', hence the -1 for last index of '/' - addTypeName(answers, fileName, -1, packageArray); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitModule(Path p, String name) throws IOException { - if (moduleName == null) - return FileVisitResult.CONTINUE; - if (!moduleName.equals(name)) { - return FileVisitResult.SKIP_SUBTREE; - } - return FileVisitResult.CONTINUE; - } - - }, JRTUtil.NOTIFY_ALL); - } catch (IOException e) { - String error = "Failed to find module " + moduleName + " defining package " + qualifiedPackageName //$NON-NLS-1$ //$NON-NLS-2$ - + " in " + this; //$NON-NLS-1$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - } - } - - int size = answers.size(); - if (size != 0) { - char[][][] result = new char[size][][]; - answers.toArray(result); - return result; - } - return null; - } - - protected void addTypeName(final ArrayList answers, String fileName, int last, char[] packageName) { - int indexOfDot = fileName.lastIndexOf('.'); - if (indexOfDot != -1) { - String typeName = fileName.substring(last + 1, indexOfDot); - answers.add( - CharOperation.arrayConcat( - CharOperation.splitOn('/', packageName), - typeName.toCharArray())); - } - } - @Override - public void initialize() throws IOException { - loadModules(); - } - - public void loadModules() { - Map cache = ModulesCache.computeIfAbsent(this.file.getPath(), key -> { - HashMap newCache = new HashMap<>(); - try { - org.eclipse.jdt.internal.compiler.util.JRTUtil.walkModuleImage(this.file, - new org.eclipse.jdt.internal.compiler.util.JRTUtil.JrtFileVisitor() { - - @Override - public FileVisitResult visitPackage(Path dir, Path mod, BasicFileAttributes attrs) - throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path f, Path mod, BasicFileAttributes attrs) - throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitModule(Path p, String name) throws IOException { - try { - ClasspathJrt.this.acceptModule(JRTUtil.getClassfile(ClasspathJrt.this.file, IModule.MODULE_INFO_CLASS, name), newCache); - } catch (ClassFormatException e) { - throw new IOException(e); - } - return FileVisitResult.SKIP_SUBTREE; - } - }, JRTUtil.NOTIFY_MODULES); - - } catch (IOException e) { - String error = "Failed to walk modules for " + key; //$NON-NLS-1$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - return null; - } - } - return newCache.isEmpty() ? null : Collections.unmodifiableMap(newCache); - }); - this.moduleNamesCache.addAll(cache.keySet()); - } - - void acceptModule(ClassFileReader reader, Map cache) { - if (reader != null) { - IModule moduleDecl = reader.getModuleDeclaration(); - if (moduleDecl != null) { - cache.put(String.valueOf(moduleDecl.name()), moduleDecl); - } - } - } - - @Override - public Collection getModuleNames(Collection limitModule, Function getModule) { - Map cache = ModulesCache.get(this.file.getPath()); - return selectModules(cache.keySet(), limitModule, getModule); - } - @Override - protected List allModules(Iterable allSystemModules, Function getModuleName, Function getModule) { - List result = new ArrayList<>(); - boolean hasJavaDotSE = false; - for (T mod : allSystemModules) { - String moduleName = getModuleName.apply(mod); - if ("java.se".equals(moduleName)) { //$NON-NLS-1$ - result.add(moduleName); - hasJavaDotSE = true; - break; - } - } - for (T mod : allSystemModules) { - String moduleName = getModuleName.apply(mod); - boolean isJavaDotStart = moduleName.startsWith("java."); //$NON-NLS-1$ - boolean isPotentialRoot = !isJavaDotStart; // always include non-java.* - if (!hasJavaDotSE) - isPotentialRoot |= isJavaDotStart; // no java.se => add all java.* - - if (isPotentialRoot) { - IModule m = getModule.apply(mod); - if (m != null) { - for (IPackageExport packageExport : m.exports()) { - if (!packageExport.isQualified()) { - result.add(moduleName); - break; - } - } - } - } - } - return result; - } -// protected void addToPackageCache(String fileName, boolean endsWithSep) { -// int last = endsWithSep ? fileName.length() : fileName.lastIndexOf('/'); -// while (last > 0) { -// // extract the package name -// String packageName = fileName.substring(0, last); -// if (this.packageCache.contains(packageName)) -// return; -// this.packageCache.add(packageName); -// last = packageName.lastIndexOf('/'); -// } -// } -// public synchronized boolean isPackage(String qualifiedPackageName) { -// if (this.packageCache != null) -// return this.packageCache.contains(qualifiedPackageName); -// -// this.packageCache = new HashSet<>(41); -// this.packageCache.add(Util.EMPTY_STRING); -// -// try { -// JRTUtil.walkModuleImage(this.file, new JRTUtil.JrtFileVisitor() { -// -// @Override -// public FileVisitResult visitPackage(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException { -// addToPackageCache(dir.toString(), true); -// return FileVisitResult.CONTINUE; -// } -// -// @Override -// public FileVisitResult visitFile(java.nio.file.Path dir, java.nio.file.Path mod, BasicFileAttributes attrs) throws IOException { -// return FileVisitResult.CONTINUE; -// } -// -// @Override -// public FileVisitResult visitModule(java.nio.file.Path mod) throws IOException { -// return FileVisitResult.CONTINUE; -// } -// -// }, JRTUtil.NOTIFY_PACKAGES); -// } catch (IOException e) { -// // Ignore and move on -// } -// return this.packageCache.contains(qualifiedPackageName); -// } - @Override - public void reset() { - if (this.closeZipFileAtEnd) { - if (this.annotationZipFile != null) { - try { - this.annotationZipFile.close(); - } catch(IOException e) { - // ignore - } - this.annotationZipFile = null; - } - } - if (this.annotationPaths != null) { - //this.packageCache = null; - this.annotationPaths = null; - } - } - @Override - public String toString() { - return "Classpath for JRT System " + this.file.getPath(); //$NON-NLS-1$ - } - @Override - public char[] normalizedPath() { - if (this.normalizedPath == null) { - String path2 = this.getPath(); - char[] rawName = path2.toCharArray(); - if (File.separatorChar == '\\') { - CharOperation.replace(rawName, '\\', '/'); - } - this.normalizedPath = CharOperation.subarray(rawName, 0, CharOperation.lastIndexOf('.', rawName)); - } - return this.normalizedPath; - } - @Override - public String getPath() { - if (this.path == null) { - try { - this.path = this.file.getCanonicalPath(); - } catch (IOException e) { - // in case of error, simply return the absolute path - this.path = this.file.getAbsolutePath(); - } - } - return this.path; - } - @Override - public int getMode() { - return BINARY; - } - @Override - public boolean hasModule() { - return true; - } - @Override - public IModule getModule(char[] moduleName) { - Map modules = ModulesCache.get(this.file.getPath()); - if (modules != null) { - return modules.get(String.valueOf(moduleName)); - } - return null; - } - @Override - public boolean servesModule(char[] moduleName) { - return getModule(moduleName) != null; - } - - public static void clearCache(String path, String releaseVersion) { - if (releaseVersion != null) { - path += '|'+ CtSym.getReleaseCode(releaseVersion); - } - ModulesCache.remove(path); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJsr199.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJsr199.java deleted file mode 100644 index 25fcfb0..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathJsr199.java +++ /dev/null @@ -1,280 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2015, 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Kenneth Olson - initial API and implementation - * Dennis Hendriks - initial API and implementation - * IBM Corporation - Contribution for bug 188796 - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.env.IModule; - -@SuppressWarnings({ "rawtypes", "unchecked" }) -public class ClasspathJsr199 extends ClasspathLocation { - private static final Set fileTypes = new HashSet<>(); - - static { - fileTypes.add(JavaFileObject.Kind.CLASS); - } - - private final JavaFileManager fileManager; - private final JavaFileManager.Location location; - private Classpath jrt; - - public ClasspathJsr199(JavaFileManager file, JavaFileManager.Location location) { - super(null, null); - this.fileManager = file; - this.location = location; - } - public ClasspathJsr199(Classpath jrt, JavaFileManager file, JavaFileManager.Location location) { - super(null, null); - this.fileManager = file; - this.jrt = jrt; - this.location = location; - } - /* - * Maintain two separate constructors to avoid this being constructed with any other kind of classpath - * (other than ClasspathJrt and ClasspathJep249 - */ - public ClasspathJsr199(ClasspathJep247 older, JavaFileManager file, JavaFileManager.Location location) { - super(null, null); - this.fileManager = file; - this.jrt = older; - this.location = location; - } - - @Override - public List fetchLinkedJars(FileSystem.ClasspathSectionProblemReporter problemReporter) { - // Assume no linked jars - return null; - } - - @Override - public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, - String aQualifiedBinaryFileName, boolean asBinaryOnly) { - if (this.jrt != null) { - return this.jrt.findClass(typeName, qualifiedPackageName, moduleName, aQualifiedBinaryFileName, asBinaryOnly); - } - String qualifiedBinaryFileName = File.separatorChar == '/' - ? aQualifiedBinaryFileName - : aQualifiedBinaryFileName.replace(File.separatorChar, '/'); - - try { - int lastDot = qualifiedBinaryFileName.lastIndexOf('.'); - String className = lastDot < 0 ? qualifiedBinaryFileName : qualifiedBinaryFileName.substring(0, lastDot); - JavaFileObject jfo = null; - try { - jfo = this.fileManager.getJavaFileForInput(this.location, className, JavaFileObject.Kind.CLASS); - } catch (IOException e) { - // treat as if class file is missing - } - - if (jfo == null) - return null; // most common case - - try (InputStream inputStream = jfo.openInputStream()) { - ClassFileReader reader = ClassFileReader.read(inputStream, qualifiedBinaryFileName); - if (reader != null) { - return new ClasspathAnswer(reader, fetchAccessRestriction(qualifiedBinaryFileName), this); - } - } - } catch (ClassFormatException e) { - // treat as if class file is missing - } catch (IOException e) { - // treat as if class file is missing - } - return null; - } - - @Override - public char[][][] findTypeNames(String aQualifiedPackageName, String moduleName) { - if (this.jrt != null) { - return this.jrt.findTypeNames(aQualifiedPackageName, moduleName); - } - String qualifiedPackageName = File.separatorChar == '/' ? aQualifiedPackageName : aQualifiedPackageName.replace( - File.separatorChar, '/'); - - Iterable files = null; - try { - files = this.fileManager.list(this.location, qualifiedPackageName, fileTypes, false); - } catch (IOException e) { - // treat as if empty - } - if (files == null) { - return null; - } - ArrayList answers = new ArrayList(); - char[][] packageName = CharOperation.splitOn(File.separatorChar, qualifiedPackageName.toCharArray()); - - for (JavaFileObject file : files) { - String fileName = file.toUri().getPath(); - - int last = fileName.lastIndexOf('/'); - if (last > 0) { - int indexOfDot = fileName.lastIndexOf('.'); - if (indexOfDot != -1) { - String typeName = fileName.substring(last + 1, indexOfDot); - answers.add(CharOperation.arrayConcat(packageName, typeName.toCharArray())); - } - } - } - int size = answers.size(); - if (size != 0) { - char[][][] result = new char[size][][]; - answers.toArray(result); - return result; - } - return null; - } - - @Override - public void initialize() throws IOException { - if (this.jrt != null) { - this.jrt.initialize(); - } - } - - @Override - public void acceptModule(IModule mod) { - // do nothing - } - - @Override - public char[][] getModulesDeclaringPackage(String aQualifiedPackageName, String moduleName) { - if (this.jrt != null) { - return this.jrt.getModulesDeclaringPackage(aQualifiedPackageName, moduleName); - } - String qualifiedPackageName = File.separatorChar == '/' ? aQualifiedPackageName : aQualifiedPackageName.replace( - File.separatorChar, '/'); - - boolean result = false; - try { - Iterable files = this.fileManager.list(this.location, qualifiedPackageName, fileTypes, false); - Iterator f = files.iterator(); - // if there is any content, assume a package - if (f.hasNext()) { - result = true; - } else { - // I hate to do this since it is expensive and will throw off garbage - // but can't think of an alternative now - files = this.fileManager.list(this.location, qualifiedPackageName, fileTypes, true); - f = files.iterator(); - // if there is any content, assume a package - if (f.hasNext()) { - result = true; - } - } - } catch (IOException e) { - // treat as if missing - } - return singletonModuleNameIf(result); - } - - @Override - public boolean hasCompilationUnit(String qualifiedPackageName, String moduleName) { - if (this.jrt != null) - return this.jrt.hasCompilationUnit(qualifiedPackageName, moduleName); - return false; - } - - @Override - public void reset() { - try { - super.reset(); - this.fileManager.flush(); - } catch (IOException e) { - // ignore - } - if (this.jrt != null) { - this.jrt.reset(); - } - } - - @Override - public String toString() { - return "Classpath for Jsr 199 JavaFileManager: " + this.location; //$NON-NLS-1$ - } - - @Override - public char[] normalizedPath() { - if (this.normalizedPath == null) { - this.normalizedPath = this.getPath().toCharArray(); - } - return this.normalizedPath; - } - - @Override - public String getPath() { - if (this.path == null) { - this.path = this.location.getName(); - } - return this.path; - } - - @Override - public int getMode() { - return BINARY; - } - - @Override - public boolean hasAnnotationFileFor(String qualifiedTypeName) { - return false; - } - - @Override - public Collection getModuleNames(Collection limitModules) { - if (this.jrt != null) - return this.jrt.getModuleNames(limitModules); - return Collections.emptyList(); - } - - @Override - public boolean hasModule() { - if (this.jrt != null) { - return this.jrt.hasModule(); - } - return super.hasModule(); - } - - @Override - public IModule getModule(char[] name) { - if (this.jrt != null) { - return this.jrt.getModule(name); - } - return super.getModule(name); - } - - @Override - public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, - String moduleName, String qualifiedBinaryFileName) { - // - return findClass(typeName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, false); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java deleted file mode 100644 index e2c3c7c..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathLocation.java +++ /dev/null @@ -1,199 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Function; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.env.AccessRestriction; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.env.IModule.IModuleReference; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.util.SuffixConstants; - -public abstract class ClasspathLocation implements FileSystem.Classpath, - SuffixConstants { - - public static final int SOURCE = 1; - public static final int BINARY = 2; - - String path; - char[] normalizedPath; - public AccessRuleSet accessRuleSet; - IModule module; - - public String destinationPath; - // destination path for compilation units that are reached through this - // classpath location; the coding is consistent with the one of - // Main.destinationPath: - // == null: unspecified, use whatever value is set by the enclosing - // context, id est Main; - // == Main.NONE: absorbent element, do not output class files; - // else: use as the path of the directory into which class files must - // be written. - // potentially carried by any entry that contains to be compiled files - - protected ClasspathLocation(AccessRuleSet accessRuleSet, - String destinationPath) { - this.accessRuleSet = accessRuleSet; - this.destinationPath = destinationPath; - } - - /** - * Return the first access rule which is violated when accessing a given - * type, or null if no 'non accessible' access rule applies. - * - * @param qualifiedBinaryFileName - * tested type specification, formed as: - * "org/eclipse/jdt/core/JavaCore.class"; on systems that - * use \ as File.separator, the - * "org\eclipse\jdt\core\JavaCore.class" is accepted as well - * @return the first access rule which is violated when accessing a given - * type, or null if none applies - */ - protected AccessRestriction fetchAccessRestriction(String qualifiedBinaryFileName) { - if (this.accessRuleSet == null) - return null; - char [] qualifiedTypeName = qualifiedBinaryFileName. - substring(0, qualifiedBinaryFileName.length() - SUFFIX_CLASS.length) - .toCharArray(); - if (File.separatorChar == '\\') { - CharOperation.replace(qualifiedTypeName, File.separatorChar, '/'); - } - return this.accessRuleSet.getViolatedRestriction(qualifiedTypeName); - } - - public int getMode() { - return SOURCE | BINARY; - } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + this.getMode(); - result = prime * result + ((this.path == null) ? 0 : this.path.hashCode()); - return result; - } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - ClasspathLocation other = (ClasspathLocation) obj; - String localPath = this.getPath(); - String otherPath = other.getPath(); - if (localPath == null) { - if (otherPath != null) - return false; - } else if (!localPath.equals(otherPath)) - return false; - if (this.getMode() != other.getMode()) - return false; - return true; - } - @Override - public String getPath() { - return this.path; - } - @Override - public String getDestinationPath() { - return this.destinationPath; - } - - @Override - public void acceptModule(IModule mod) { - this.module = mod; - } - @Override - public boolean isAutomaticModule() { - return this.module == null ? false : this.module.isAutomatic(); - } - @Override - public Collection getModuleNames(Collection limitModules) { - return getModuleNames(limitModules, m -> getModule(m.toCharArray())); - } - @Override - public Collection getModuleNames(Collection limitModules, Function getModule) { - if (this.module != null) { - String name = String.valueOf(this.module.name()); - return selectModules(Collections.singleton(name), limitModules, getModule); - } - return Collections.emptyList(); - } - protected Collection selectModules(Set modules, Collection limitModules, Function getModule) { - Collection rootModules; - if (limitModules != null) { - Set result = new HashSet<>(modules); - result.retainAll(limitModules); - rootModules = result; - } else { - rootModules = allModules(modules, s -> s, m -> getModule(m.toCharArray())); - } - Set allModules = new HashSet<>(rootModules); - for (String mod : rootModules) - addRequired(mod, allModules, getModule); - return allModules; - } - - private void addRequired(String mod, Set allModules, Function getModule) { - IModule iMod = getModule(mod.toCharArray()); - if (iMod != null) { - for (IModuleReference requiredRef : iMod.requires()) { - IModule reqMod = getModule.apply(new String(requiredRef.name())); - if (reqMod != null) { - String reqModName = String.valueOf(reqMod.name()); - if (allModules.add(reqModName)) - addRequired(reqModName, allModules, getModule); - } - } - } - } - protected List allModules(Iterable allSystemModules, Function getModuleName, Function getModule) { - List result = new ArrayList<>(); - for (T mod : allSystemModules) { - String moduleName = getModuleName.apply(mod); - result.add(moduleName); - } - return result; - } - - @Override - public boolean isPackage(String qualifiedPackageName, String moduleName) { - return getModulesDeclaringPackage(qualifiedPackageName, moduleName) != null; - } - - protected char[][] singletonModuleNameIf(boolean condition) { - if (!condition) - return null; - if (this.module != null) - return new char[][] { this.module.name() }; - return new char[][] { ModuleBinding.UNNAMED }; - } - - @Override - public void reset() { - this.module = null; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java deleted file mode 100644 index 80c4455..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathMultiReleaseJar.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.nio.file.DirectoryStream; -import java.nio.file.FileVisitResult; -import java.nio.file.FileVisitor; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.zip.ZipEntry; - -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding.ExternalAnnotationStatus; -import org.eclipse.jdt.internal.compiler.util.JRTUtil; -import org.eclipse.jdt.internal.compiler.util.SuffixConstants; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class ClasspathMultiReleaseJar extends ClasspathJar { - private java.nio.file.FileSystem fs = null; - Path releasePath = null; - String compliance = null; - - public ClasspathMultiReleaseJar(File file, boolean closeZipFileAtEnd, - AccessRuleSet accessRuleSet, String destinationPath, String compliance) { - super(file, closeZipFileAtEnd, accessRuleSet, destinationPath); - this.compliance = compliance; - } - @Override - public void initialize() throws IOException { - super.initialize(); - if (this.file.exists()) { - this.fs = JRTUtil.getJarFileSystem(this.file.toPath()); - this.releasePath = this.fs.getPath("/", "META-INF", "versions", this.compliance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - if (!Files.exists(this.releasePath)) { - this.releasePath = null; - } - } - } - @SuppressWarnings("rawtypes") - @Override - public synchronized char[][] getModulesDeclaringPackage(String qualifiedPackageName, String moduleName) { - if (this.releasePath == null) { - return super.getModulesDeclaringPackage(qualifiedPackageName, moduleName); - } - if (this.packageCache != null) - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); - - this.packageCache = new HashSet<>(41); - this.packageCache.add(Util.EMPTY_STRING); - - for (Enumeration e = this.zipFile.entries(); e.hasMoreElements(); ) { - String fileName = ((ZipEntry) e.nextElement()).getName(); - addToPackageCache(fileName, false); - } - try { - if (this.releasePath != null && Files.exists(this.releasePath)) { - // go through the packages - try (DirectoryStream stream = Files.newDirectoryStream(this.releasePath)) { - for (final java.nio.file.Path subdir: stream) { - Files.walkFileTree(subdir, new FileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) - throws IOException { - return FileVisitResult.CONTINUE; - } - @Override - public FileVisitResult visitFile(java.nio.file.Path f, BasicFileAttributes attrs) - throws IOException { - Path p = ClasspathMultiReleaseJar.this.releasePath.relativize(f); - addToPackageCache(p.toString(), false); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFileFailed(java.nio.file.Path f, IOException exc) throws IOException { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(java.nio.file.Path dir, IOException exc) - throws IOException { - return FileVisitResult.CONTINUE; - } - }); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - // move on; - } - return singletonModuleNameIf(this.packageCache.contains(qualifiedPackageName)); - } - @Override - public ClasspathAnswer findClass(char[] binaryFileName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (!isPackage(qualifiedPackageName, moduleName)) return null; // most common case - if (this.releasePath != null) { - try { - Path p = this.releasePath.resolve(qualifiedBinaryFileName); - byte[] content = Files.readAllBytes(p); - IBinaryType reader = null; - if (content != null) { - reader = new ClassFileReader(p.toUri(), content, qualifiedBinaryFileName.toCharArray()); - } - if (reader != null) { - char[] modName = this.module == null ? null : this.module.name(); - if (reader instanceof ClassFileReader) { - ClassFileReader classReader = (ClassFileReader) reader; - if (classReader.moduleName == null) - classReader.moduleName = modName; - else - modName = classReader.moduleName; - } - String fileNameWithoutExtension = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - SuffixConstants.SUFFIX_CLASS.length); - searchPaths: - if (this.annotationPaths != null) { - String qualifiedClassName = qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length()-SuffixConstants.EXTENSION_CLASS.length()-1); - for (String annotationPath : this.annotationPaths) { - try { - if (this.annotationZipFile == null) { - this.annotationZipFile = ExternalAnnotationDecorator.getAnnotationZipFile(annotationPath, null); - } - reader = ExternalAnnotationDecorator.create(reader, annotationPath, qualifiedClassName, this.annotationZipFile); - - if (reader.getExternalAnnotationStatus() == ExternalAnnotationStatus.TYPE_IS_ANNOTATED) { - break searchPaths; - } - } catch (IOException e) { - // don't let error on annotations fail class reading - } - } - // location is configured for external annotations, but no .eea found, decorate in order to answer NO_EEA_FILE: - reader = new ExternalAnnotationDecorator(reader, null); - } - if (this.accessRuleSet == null) - return new ClasspathAnswer(reader, null, modName, this); - return new ClasspathAnswer(reader, - this.accessRuleSet.getViolatedRestriction(fileNameWithoutExtension.toCharArray()), - modName, - this); - } - } catch (IOException | ClassFormatException e) { - // treat as if class file is missing - } - } - return super.findClass(binaryFileName, qualifiedPackageName, moduleName, qualifiedBinaryFileName, asBinaryOnly); - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java deleted file mode 100644 index 6f8ee36..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ClasspathSourceJar.java +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006, 2017 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.zip.ZipEntry; - -import org.eclipse.jdt.internal.compiler.batch.FileSystem.ClasspathAnswer; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class ClasspathSourceJar extends ClasspathJar { - private final String encoding; - - public ClasspathSourceJar(File file, boolean closeZipFileAtEnd, - AccessRuleSet accessRuleSet, String encoding, - String destinationPath) { - super(file, closeZipFileAtEnd, accessRuleSet, destinationPath); - this.encoding = encoding; - } - - @Override - public ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly) { - if (!isPackage(qualifiedPackageName, moduleName)) - return null; // most common case - - ZipEntry sourceEntry = this.zipFile.getEntry(qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - 6) + SUFFIX_STRING_java); - if (sourceEntry != null) { - try { - char[] contents = null; - try (InputStream stream = this.zipFile.getInputStream(sourceEntry)) { - contents = Util.getInputStreamAsCharArray(stream, this.encoding); - } - CompilationUnit compilationUnit = new CompilationUnit( - contents, - qualifiedBinaryFileName.substring(0, qualifiedBinaryFileName.length() - 6) + SUFFIX_STRING_java, - this.encoding, - this.destinationPath); - compilationUnit.module = this.module == null ? null : this.module.name(); - return new ClasspathAnswer( - compilationUnit, - fetchAccessRestriction(qualifiedBinaryFileName), - this); - } catch (IOException e) { - // treat as if source file is missing - } - } - return null; - } - - @Override - public int getMode() { - return SOURCE; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java deleted file mode 100644 index 3a9c945..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/CompilationUnit.java +++ /dev/null @@ -1,151 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.util.function.Function; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.problem.AbortCompilationUnit; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class CompilationUnit implements ICompilationUnit { - public char[] contents; - public char[] fileName; - public char[] mainTypeName; - String encoding; - public String destinationPath; - public char[] module; - // a specific destination path for this compilation unit; coding is - // aligned with Main.destinationPath: - // == null: unspecified, use whatever value is set by the enclosing - // context, id est Main; - // == Main.NONE: absorbent element, do not output class files; - // else: use as the path of the directory into which class files must - // be written. - private final boolean ignoreOptionalProblems; - private ModuleBinding moduleBinding; - /** - * annotation path can only be retrieved once the qualified type name is known. - * This is the provided function for computing the annotation path from that type name. - */ - private final Function annotationPathProvider; - -public CompilationUnit(char[] contents, String fileName, String encoding) { - this(contents, fileName, encoding, null); -} -public CompilationUnit(char[] contents, String fileName, String encoding, - String destinationPath) { - this(contents, fileName, encoding, destinationPath, false, null); -} -public CompilationUnit(char[] contents, String fileName, String encoding, - String destinationPath, boolean ignoreOptionalProblems, String modName) { - this(contents, fileName, encoding, destinationPath, ignoreOptionalProblems, modName, null); -} -public CompilationUnit(char[] contents, String fileName, String encoding, String destinationPath, - boolean ignoreOptionalProblems, String modName, Function annotationPathProvider) -{ - this.annotationPathProvider = annotationPathProvider; - this.contents = contents; - if (modName != null) - this.module = modName.toCharArray(); - char[] fileNameCharArray = fileName.toCharArray(); - switch(File.separatorChar) { - case '/' : - if (CharOperation.indexOf('\\', fileNameCharArray) != -1) { - CharOperation.replace(fileNameCharArray, '\\', '/'); - } - break; - case '\\' : - if (CharOperation.indexOf('/', fileNameCharArray) != -1) { - CharOperation.replace(fileNameCharArray, '/', '\\'); - } - } - this.fileName = fileNameCharArray; - int start = CharOperation.lastIndexOf(File.separatorChar, fileNameCharArray) + 1; - - int end = CharOperation.lastIndexOf('.', fileNameCharArray); - if (end == -1) { - end = fileNameCharArray.length; - } - - this.mainTypeName = CharOperation.subarray(fileNameCharArray, start, end); - this.encoding = encoding; - this.destinationPath = destinationPath; - this.ignoreOptionalProblems = ignoreOptionalProblems; -} -@Override -public char[] getContents() { - if (this.contents != null) - return this.contents; // answer the cached source - - // otherwise retrieve it - try { - return Util.getFileCharContent(new File(new String(this.fileName)), this.encoding); - } catch (IOException e) { - this.contents = CharOperation.NO_CHAR; // assume no source if asked again - throw new AbortCompilationUnit(null, e, this.encoding); - } -} -/** - * @see org.eclipse.jdt.internal.compiler.env.IDependent#getFileName() - */ -@Override -public char[] getFileName() { - return this.fileName; -} -@Override -public char[] getMainTypeName() { - return this.mainTypeName; -} -@Override -public char[][] getPackageName() { - return null; -} -@Override -public boolean ignoreOptionalProblems() { - return this.ignoreOptionalProblems; -} -@Override -public String toString() { - return "CompilationUnit[" + new String(this.fileName) + "]"; //$NON-NLS-2$ //$NON-NLS-1$ -} -@Override -public char[] getModuleName() { - return this.module; -} -@Override -public ModuleBinding module(LookupEnvironment rootEnvironment) { - if (this.moduleBinding != null) - return this.moduleBinding; - this.moduleBinding = rootEnvironment.getModule(this.module); - if (this.moduleBinding == null) - throw new IllegalStateException("Module should be known"); //$NON-NLS-1$ - return this.moduleBinding; -} -@Override -public String getDestinationPath() { - return this.destinationPath; -} -@Override -public String getExternalAnnotationPath(String qualifiedTypeName) { - if (this.annotationPathProvider != null) - return this.annotationPathProvider.apply(qualifiedTypeName); - return null; -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/FileFinder.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/FileFinder.java deleted file mode 100644 index 247c0c4..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/FileFinder.java +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2016 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.jdt.internal.compiler.env.IModule; - -public class FileFinder { - -/** - * Although the file finder is meant to be generic for any file name patters, - * at the moment it is used only for *.java files. This method handles the - * module-info.java in a special way by always placing it as the first element - * of the resulting array. - */ -public static String[] find(File f, String pattern) { - List files = new ArrayList<>(); - find0(f, pattern, files); - String[] result = new String[files.size()]; - files.toArray(result); - return result; -} -private static void find0(File f, String pattern, List collector) { - if (f.isDirectory()) { - String[] files = f.list(); - if (files == null) return; - for (int i = 0, max = files.length; i < max; i++) { - File current = new File(f, files[i]); - if (current.isDirectory()) { - find0(current, pattern, collector); - } else { - String name = current.getName().toLowerCase(); - if (name.endsWith(pattern)) { - // NOTE: This handles only the lower case name. Check with the spec about - // Naming of the module descriptor before making this code code insensitive. - if (name.endsWith(IModule.MODULE_INFO_JAVA)) { - collector.add(0, current.getAbsolutePath()); - } else { - collector.add(current.getAbsolutePath()); - } - } - } - } - } -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/FileSystem.java deleted file mode 100644 index 3212941..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/FileSystem.java +++ /dev/null @@ -1,805 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2021 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Stephan Herrmann - Contribution for - * Bug 440687 - [compiler][batch][null] improve command line option for external annotations - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.IOException; -import java.nio.file.InvalidPathException; -import java.nio.file.NoSuchFileException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.zip.ZipFile; - -import javax.lang.model.SourceVersion; - -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationDecorator; -import org.eclipse.jdt.internal.compiler.env.AccessRestriction; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.IBinaryType; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.env.IModuleAwareNameEnvironment; -import org.eclipse.jdt.internal.compiler.env.IModulePathEntry; -import org.eclipse.jdt.internal.compiler.env.ISourceType; -import org.eclipse.jdt.internal.compiler.env.IUpdatableModule; -import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.UpdateKind; -import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.UpdatesByKind; -import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.parser.Parser; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; -import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; -import org.eclipse.jdt.internal.compiler.util.JRTUtil; -import org.eclipse.jdt.internal.compiler.util.SuffixConstants; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class FileSystem implements IModuleAwareNameEnvironment, SuffixConstants { - - // Keep the type as ArrayList and not List as there are clients that are already written to expect ArrayList. - public static ArrayList EMPTY_CLASSPATH = new ArrayList<>(); - - public static class ClasspathAnswer extends NameEnvironmentAnswer { - - public final Classpath source; - - public ClasspathAnswer(IBinaryType binaryType, AccessRestriction accessRestriction, char[] module, Classpath source) { - super(binaryType, accessRestriction, module); - this.source = source; - } - - public ClasspathAnswer(IBinaryType binaryType, AccessRestriction accessRestriction, Classpath source) { - super(binaryType, accessRestriction); - this.source = source; - } - - public ClasspathAnswer(ICompilationUnit compilationUnit, AccessRestriction accessRestriction, char[] module, Classpath source) { - super(compilationUnit, accessRestriction, module); - this.source = source; - } - - public ClasspathAnswer(ICompilationUnit compilationUnit, AccessRestriction accessRestriction, Classpath source) { - super(compilationUnit, accessRestriction); - this.source = source; - } - - public ClasspathAnswer(ISourceType[] sourceTypes, AccessRestriction accessRestriction, - String externalAnnotationPath, char[] module, Classpath source) { - super(sourceTypes, accessRestriction, externalAnnotationPath, module); - this.source = source; - } - - public ClasspathAnswer(ReferenceBinding binding, ModuleBinding module, Classpath source) { - super(binding, module); - this.source = source; - } - - } - - /** - * A Classpath, even though an IModuleLocation, can represent a plain - * classpath location too. The FileSystem tells the Classpath whether to behave as a module or regular class - * path via {@link Classpath#acceptModule(IModule)}. - * - * Sub types of classpath are responsible for appropriate behavior based on this. - */ - public interface Classpath extends IModulePathEntry { - char[][][] findTypeNames(String qualifiedPackageName, String moduleName); - ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName); - ClasspathAnswer findClass(char[] typeName, String qualifiedPackageName, String moduleName, String qualifiedBinaryFileName, boolean asBinaryOnly); - boolean isPackage(String qualifiedPackageName, /*@Nullable*/String moduleName); - default boolean hasModule() { return getModule() != null; } - default boolean hasCUDeclaringPackage(String qualifiedPackageName, Function pkgNameExtractor) { - return hasCompilationUnit(qualifiedPackageName, null); - } - /** - * Return a list of the jar file names defined in the Class-Path section - * of the jar file manifest if any, null else. Only ClasspathJar (and - * extending classes) instances may return a non-null result. - * @param problemReporter problem reporter with which potential - * misconfiguration issues are raised - * @return a list of the jar file names defined in the Class-Path - * section of the jar file manifest if any - */ - List fetchLinkedJars(ClasspathSectionProblemReporter problemReporter); - /** - * This method resets the environment. The resulting state is equivalent to - * a new name environment without creating a new object. - */ - void reset(); - /** - * Return a normalized path for file based classpath entries. This is an - * absolute path in which file separators are transformed to the - * platform-agnostic '/', ending with a '/' for directories. This is an - * absolute path in which file separators are transformed to the - * platform-agnostic '/', deprived from the '.jar' (resp. '.zip') - * extension for jar (resp. zip) files. - * @return a normalized path for file based classpath entries - */ - char[] normalizedPath(); - /** - * Return the path for file based classpath entries. This is an absolute path - * ending with a file separator for directories, an absolute path including the '.jar' - * (resp. '.zip') extension for jar (resp. zip) files. - * @return the path for file based classpath entries - */ - String getPath(); - /** - * Initialize the entry - */ - void initialize() throws IOException; - /** - * Can the current location provide an external annotation file for the given type? - * @param qualifiedTypeName type name in qualified /-separated notation. - */ - boolean hasAnnotationFileFor(String qualifiedTypeName); - /** - * Accepts to represent a module location with the given module description. - */ - public void acceptModule(IModule module); - public String getDestinationPath(); - Collection getModuleNames(Collection limitModules); - Collection getModuleNames(Collection limitModules, Function getModule); - default boolean forbidsExportFrom(String modName) { return false; } - } - public interface ClasspathSectionProblemReporter { - void invalidClasspathSection(String jarFilePath); - void multipleClasspathSections(String jarFilePath); - } - - /** - * This class is defined how to normalize the classpath entries. - * It removes duplicate entries. - */ - public static class ClasspathNormalizer { - /** - * Returns the normalized classpath entries (no duplicate). - *

    The given classpath entries are FileSystem.Classpath. We check the getPath() in order to find - * duplicate entries.

    - * - * @param classpaths the given classpath entries - * @return the normalized classpath entries - */ - public static ArrayList normalize(ArrayList classpaths) { - ArrayList normalizedClasspath = new ArrayList<>(); - HashSet cache = new HashSet<>(); - for (Iterator iterator = classpaths.iterator(); iterator.hasNext(); ) { - FileSystem.Classpath classpath = iterator.next(); - if (!cache.contains(classpath)) { - normalizedClasspath.add(classpath); - cache.add(classpath); - } - } - return normalizedClasspath; - } - } - - protected Classpath[] classpaths; - // Used only in single-module mode when the module descriptor is - // provided via command line. - protected IModule module; - Set knownFileNames; - protected boolean annotationsFromClasspath; // should annotation files be read from the classpath (vs. explicit separate path)? - private static HashMap JRT_CLASSPATH_CACHE = null; - protected Map moduleLocations = new HashMap<>(); - - public Consumer nameEnvironmentListener = null; // listener for findType* methods - - /** Tasks resulting from --add-reads or --add-exports command line options. */ - Map moduleUpdates = new HashMap<>(); - static boolean isJRE12Plus = false; - - private boolean hasLimitModules = false; - - static { - try { - isJRE12Plus = SourceVersion.valueOf("RELEASE_12") != null; //$NON-NLS-1$ - } catch(IllegalArgumentException iae) { - // fall back to default - } - } - -/* - classPathNames is a collection is Strings representing the full path of each class path - initialFileNames is a collection is Strings, the trailing '.java' will be removed if its not already. -*/ -public FileSystem(String[] classpathNames, String[] initialFileNames, String encoding) { - this(classpathNames, initialFileNames, encoding, null, null); -} -public FileSystem(String[] classpathNames, String[] initialFileNames, String encoding, String release) { - this(classpathNames, initialFileNames, encoding, null, release); -} -protected FileSystem(String[] classpathNames, String[] initialFileNames, String encoding, Collection limitModules) { - this(classpathNames,initialFileNames, encoding, limitModules, null); -} -protected FileSystem(String[] classpathNames, String[] initialFileNames, String encoding, Collection limitModules, String release) { - final int classpathSize = classpathNames.length; - this.classpaths = new Classpath[classpathSize]; - int counter = 0; - this.hasLimitModules = limitModules != null && !limitModules.isEmpty(); - for (int i = 0; i < classpathSize; i++) { - Classpath classpath = getClasspath(classpathNames[i], encoding, null, null, release); - try { - classpath.initialize(); - for (String moduleName : classpath.getModuleNames(limitModules)) - this.moduleLocations.put(moduleName, classpath); - this.classpaths[counter++] = classpath; - } catch (IOException e) { - String error = "Failed to init " + classpath; //$NON-NLS-1$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - } - } - } - if (counter != classpathSize) { - System.arraycopy(this.classpaths, 0, (this.classpaths = new Classpath[counter]), 0, counter); - } - initializeKnownFileNames(initialFileNames); -} -protected FileSystem(Classpath[] paths, String[] initialFileNames, boolean annotationsFromClasspath, Set limitedModules) { - final int length = paths.length; - int counter = 0; - this.classpaths = new FileSystem.Classpath[length]; - this.hasLimitModules = limitedModules != null && !limitedModules.isEmpty(); - for (int i = 0; i < length; i++) { - final Classpath classpath = paths[i]; - try { - classpath.initialize(); - for (String moduleName : classpath.getModuleNames(limitedModules)) - this.moduleLocations.put(moduleName, classpath); - this.classpaths[counter++] = classpath; - } catch(InvalidPathException exception) { - // JRE 9 could throw an IAE if the linked JAR paths have invalid chars, such as ":" - // ignore - } catch (NoSuchFileException e) { - // we don't warn about inexisting jars (javac does the same as us) - // see org.eclipse.jdt.core.tests.compiler.regression.BatchCompilerTest.test017b() - } catch (IOException e) { - String error = "Failed to init " + classpath; //$NON-NLS-1$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - } - } - } - if (counter != length) { - // should not happen - System.arraycopy(this.classpaths, 0, (this.classpaths = new FileSystem.Classpath[counter]), 0, counter); - } - initializeModuleLocations(limitedModules); - initializeKnownFileNames(initialFileNames); - this.annotationsFromClasspath = annotationsFromClasspath; -} -private void initializeModuleLocations(Set limitedModules) { - // First create the mapping of all module/Classpath - // since the second iteration of getModuleNames() can't be relied on for - // to get the right origin of module - if (limitedModules == null) { - for (Classpath c : this.classpaths) { - for (String moduleName : c.getModuleNames(null)) - this.moduleLocations.put(moduleName, c); - } - } else { - Map moduleMap = new HashMap<>(); - for (Classpath c : this.classpaths) { - for (String moduleName : c.getModuleNames(null)) { - moduleMap.put(moduleName, c); - } - } - for (Classpath c : this.classpaths) { - for (String moduleName : c.getModuleNames(limitedModules, m -> getModuleFromEnvironment(m.toCharArray()))) { - Classpath classpath = moduleMap.get(moduleName); - this.moduleLocations.put(moduleName, classpath); - } - } - } -} -protected FileSystem(Classpath[] paths, String[] initialFileNames, boolean annotationsFromClasspath) { - this(paths, initialFileNames, annotationsFromClasspath, null); -} -public static Classpath getClasspath(String classpathName, String encoding, AccessRuleSet accessRuleSet) { - return getClasspath(classpathName, encoding, false, accessRuleSet, null, null, null); -} -public static Classpath getClasspath(String classpathName, String encoding, AccessRuleSet accessRuleSet, Map options, String release) { - return getClasspath(classpathName, encoding, false, accessRuleSet, null, options, release); -} -public static Classpath getJrtClasspath(String jdkHome, String encoding, AccessRuleSet accessRuleSet, Map options) { - return new ClasspathJrt(new File(convertPathSeparators(jdkHome)), true, accessRuleSet, null); -} -public static Classpath getOlderSystemRelease(String jdkHome, String release, AccessRuleSet accessRuleSet) { - return isJRE12Plus ? - new ClasspathJep247Jdk12(new File(convertPathSeparators(jdkHome)), release, accessRuleSet) : - new ClasspathJep247(new File(convertPathSeparators(jdkHome)), release, accessRuleSet); -} -public static Classpath getClasspath(String classpathName, String encoding, - boolean isSourceOnly, AccessRuleSet accessRuleSet, - String destinationPath, Map options, String release) { - Classpath result = null; - File file = new File(convertPathSeparators(classpathName)); - if (file.isDirectory()) { - if (file.exists()) { - result = new ClasspathDirectory(file, encoding, - isSourceOnly ? ClasspathLocation.SOURCE : - ClasspathLocation.SOURCE | ClasspathLocation.BINARY, - accessRuleSet, - destinationPath == null || destinationPath == Main.NONE ? - destinationPath : // keep == comparison valid - convertPathSeparators(destinationPath), options); - } - } else { - int format = Util.archiveFormat(classpathName); - if (format == Util.ZIP_FILE) { - if (isSourceOnly) { - // source only mode - result = new ClasspathSourceJar(file, true, accessRuleSet, - encoding, - destinationPath == null || destinationPath == Main.NONE ? - destinationPath : // keep == comparison valid - convertPathSeparators(destinationPath)); - } else if (destinationPath == null) { - // class file only mode - if (classpathName.endsWith(JRTUtil.JRT_FS_JAR)) { - if (JRT_CLASSPATH_CACHE == null) { - JRT_CLASSPATH_CACHE = new HashMap<>(); - } else { - result = JRT_CLASSPATH_CACHE.get(file); - } - if (result == null) { - result = new ClasspathJrt(file, true, accessRuleSet, null); - try { - result.initialize(); - } catch (IOException e) { - // Broken entry, but let clients have it anyway. - } - JRT_CLASSPATH_CACHE.put(file, result); - } - } else { - result = - (release == null) ? - new ClasspathJar(file, true, accessRuleSet, null) : - new ClasspathMultiReleaseJar(file, true, accessRuleSet, destinationPath, release); - } - } - } else if (format == Util.JMOD_FILE) { - return new ClasspathJmod(file, true, accessRuleSet, null); - } - - } - return result; -} -private void initializeKnownFileNames(String[] initialFileNames) { - if (initialFileNames == null) { - this.knownFileNames = new HashSet<>(0); - return; - } - this.knownFileNames = new HashSet<>(initialFileNames.length * 2); - for (int i = initialFileNames.length; --i >= 0;) { - File compilationUnitFile = new File(initialFileNames[i]); - char[] fileName = null; - try { - fileName = compilationUnitFile.getCanonicalPath().toCharArray(); - } catch (IOException e) { - // this should not happen as the file exists - continue; - } - char[] matchingPathName = null; - final int lastIndexOf = CharOperation.lastIndexOf('.', fileName); - if (lastIndexOf != -1) { - fileName = CharOperation.subarray(fileName, 0, lastIndexOf); - } - CharOperation.replace(fileName, '\\', '/'); - boolean globalPathMatches = false; - // the most nested path should be the selected one - for (Classpath classpath : this.classpaths) { - char[] matchCandidate = classpath.normalizedPath(); - boolean currentPathMatch = false; - if (classpath instanceof ClasspathDirectory - && CharOperation.prefixEquals(matchCandidate, fileName)) { - currentPathMatch = true; - if (matchingPathName == null) { - matchingPathName = matchCandidate; - } else { - if (currentPathMatch) { - // we have a second source folder that matches the path of the source file - if (matchCandidate.length > matchingPathName.length) { - // we want to preserve the shortest possible path - matchingPathName = matchCandidate; - } - } else { - // we want to preserve the shortest possible path - if (!globalPathMatches && matchCandidate.length < matchingPathName.length) { - matchingPathName = matchCandidate; - } - } - } - if (currentPathMatch) { - globalPathMatches = true; - } - } - } - if (matchingPathName == null) { - this.knownFileNames.add(new String(fileName)); // leave as is... - } else { - this.knownFileNames.add(new String(CharOperation.subarray(fileName, matchingPathName.length, fileName.length))); - } - matchingPathName = null; - } -} -/** TESTS ONLY */ -public void scanForModules(Parser parser) { - for (int i = 0, max = this.classpaths.length; i < max; i++) { - File file = new File(this.classpaths[i].getPath()); - IModule iModule = ModuleFinder.scanForModule(this.classpaths[i], file, parser, false, null); - if (iModule != null) - this.moduleLocations.put(String.valueOf(iModule.name()), this.classpaths[i]); - } -} -@Override -public void cleanup() { - for (int i = 0, max = this.classpaths.length; i < max; i++) - this.classpaths[i].reset(); -} -private static String convertPathSeparators(String path) { - return File.separatorChar == '/' - ? path.replace('\\', '/') - : path.replace('/', '\\'); -} -@SuppressWarnings("resource") // don't close classpathEntry.zipFile, which we don't own -private ClasspathAnswer findClass(String qualifiedTypeName, char[] typeName, boolean asBinaryOnly, /*NonNull*/char[] moduleName) { - ClasspathAnswer answer = internalFindClass(qualifiedTypeName, typeName, asBinaryOnly, moduleName); - if (this.annotationsFromClasspath && answer != null && answer.getBinaryType() instanceof ClassFileReader) { - for (int i = 0, length = this.classpaths.length; i < length; i++) { - Classpath classpathEntry = this.classpaths[i]; - if (classpathEntry.hasAnnotationFileFor(qualifiedTypeName)) { - // in case of 'this.annotationsFromClasspath' we indeed search for .eea entries inside the main zipFile of the entry: - ZipFile zip = classpathEntry instanceof ClasspathJar ? ((ClasspathJar) classpathEntry).zipFile : null; - boolean shouldClose = false; - try { - if (zip == null) { - zip = ExternalAnnotationDecorator.getAnnotationZipFile(classpathEntry.getPath(), null); - shouldClose = true; - } - answer.setBinaryType(ExternalAnnotationDecorator.create(answer.getBinaryType(), classpathEntry.getPath(), - qualifiedTypeName, zip)); - if (nameEnvironmentListener != null) nameEnvironmentListener.accept(answer); - return answer; - } catch (IOException e) { - // ignore broken entry, keep searching - } finally { - if (shouldClose && zip != null) - try { - zip.close(); - } catch (IOException e) { /* nothing */ } - } - } - } - // globally configured (annotationsFromClasspath), but no .eea found, decorate in order to answer NO_EEA_FILE: - answer.setBinaryType(new ExternalAnnotationDecorator(answer.getBinaryType(), null)); - } - if (nameEnvironmentListener != null && answer != null) nameEnvironmentListener.accept(answer); - return answer; -} -private ClasspathAnswer internalFindClass(String qualifiedTypeName, char[] typeName, boolean asBinaryOnly, /*NonNull*/char[] moduleName) { - if (this.knownFileNames.contains(qualifiedTypeName)) return null; // looking for a file which we know was provided at the beginning of the compilation - - String qualifiedBinaryFileName = qualifiedTypeName + SUFFIX_STRING_class; - String qualifiedPackageName = - qualifiedTypeName.length() == typeName.length - ? Util.EMPTY_STRING - : qualifiedBinaryFileName.substring(0, qualifiedTypeName.length() - typeName.length - 1); - - LookupStrategy strategy = LookupStrategy.get(moduleName); - if (strategy == LookupStrategy.Named) { - if (this.moduleLocations != null) { - // searching for a specific named module: - String moduleNameString = String.valueOf(moduleName); - Classpath classpath = this.moduleLocations.get(moduleNameString); - if (classpath != null) { - return classpath.findClass(typeName, qualifiedPackageName, moduleNameString, qualifiedBinaryFileName); - } - } - return null; - } - String qp2 = File.separatorChar == '/' ? qualifiedPackageName : qualifiedPackageName.replace('/', File.separatorChar); - ClasspathAnswer suggestedAnswer = null; - if (qualifiedPackageName == qp2) { - for (int i = 0, length = this.classpaths.length; i < length; i++) { - if (!strategy.matches(this.classpaths[i], Classpath::hasModule)) - continue; - ClasspathAnswer answer = this.classpaths[i].findClass(typeName, qualifiedPackageName, null, qualifiedBinaryFileName, asBinaryOnly); - if (answer != null) { - if (answer.moduleName() != null && !this.moduleLocations.containsKey(String.valueOf(answer.moduleName()))) - continue; // type belongs to an unobservable module - if (!answer.ignoreIfBetter()) { - if (answer.isBetter(suggestedAnswer)) - return answer; - } else if (answer.isBetter(suggestedAnswer)) - // remember suggestion and keep looking - suggestedAnswer = answer; - } - } - } else { - String qb2 = qualifiedBinaryFileName.replace('/', File.separatorChar); - for (int i = 0, length = this.classpaths.length; i < length; i++) { - Classpath p = this.classpaths[i]; - if (!strategy.matches(p, Classpath::hasModule)) - continue; - ClasspathAnswer answer = !(p instanceof ClasspathDirectory) - ? p.findClass(typeName, qualifiedPackageName, null, qualifiedBinaryFileName, asBinaryOnly) - : p.findClass(typeName, qp2, null, qb2, asBinaryOnly); - if (answer != null) { - if (answer.moduleName() != null && !this.moduleLocations.containsKey(String.valueOf(answer.moduleName()))) - continue; // type belongs to an unobservable module - if (!answer.ignoreIfBetter()) { - if (answer.isBetter(suggestedAnswer)) - return answer; - } else if (answer.isBetter(suggestedAnswer)) - // remember suggestion and keep looking - suggestedAnswer = answer; - } - } - } - return suggestedAnswer; -} - -@Override -public ClasspathAnswer findType(char[][] compoundName, char[] moduleName) { - if (compoundName != null) - return findClass( - new String(CharOperation.concatWith(compoundName, '/')), - compoundName[compoundName.length - 1], - false, - moduleName); - return null; -} -public char[][][] findTypeNames(char[][] packageName) { - char[][][] result = null; - if (packageName != null) { - String qualifiedPackageName = new String(CharOperation.concatWith(packageName, '/')); - String qualifiedPackageName2 = File.separatorChar == '/' ? qualifiedPackageName : qualifiedPackageName.replace('/', File.separatorChar); - if (qualifiedPackageName == qualifiedPackageName2) { - for (int i = 0, length = this.classpaths.length; i < length; i++) { - char[][][] answers = this.classpaths[i].findTypeNames(qualifiedPackageName, null); - if (answers != null) { - // concat with previous answers - if (result == null) { - result = answers; - } else { - int resultLength = result.length; - int answersLength = answers.length; - System.arraycopy(result, 0, (result = new char[answersLength + resultLength][][]), 0, resultLength); - System.arraycopy(answers, 0, result, resultLength, answersLength); - } - } - } - } else { - for (int i = 0, length = this.classpaths.length; i < length; i++) { - Classpath p = this.classpaths[i]; - char[][][] answers = !(p instanceof ClasspathDirectory) ? p.findTypeNames(qualifiedPackageName, null) - : p.findTypeNames(qualifiedPackageName2, null); - if (answers != null) { - // concat with previous answers - if (result == null) { - result = answers; - } else { - int resultLength = result.length; - int answersLength = answers.length; - System.arraycopy(result, 0, (result = new char[answersLength + resultLength][][]), 0, - resultLength); - System.arraycopy(answers, 0, result, resultLength, answersLength); - } - } - } - } - } - return result; -} - -@Override -public ClasspathAnswer findType(char[] typeName, char[][] packageName, char[] moduleName) { - if (typeName != null) - return findClass( - new String(CharOperation.concatWith(packageName, typeName, '/')), - typeName, - false, - moduleName); - return null; -} - -@Override -public char[][] getModulesDeclaringPackage(char[][] packageName, char[] moduleName) { - String qualifiedPackageName = new String(CharOperation.concatWith(packageName, '/')); - String moduleNameString = String.valueOf(moduleName); - - LookupStrategy strategy = LookupStrategy.get(moduleName); - if (strategy == LookupStrategy.Named) { - if (this.moduleLocations != null) { - // specific search in a given module: - Classpath classpath = this.moduleLocations.get(moduleNameString); - if (classpath != null) { - if (classpath.isPackage(qualifiedPackageName, moduleNameString)) - return new char[][] {moduleName}; - } - } - return null; - } - // search the entire environment and answer which modules declare that package: - char[][] allNames = null; - boolean hasUnobserable = false; - for (Classpath cp : this.classpaths) { - if (strategy.matches(cp, Classpath::hasModule)) { - if (strategy == LookupStrategy.Unnamed) { - // short-cut - if (cp.isPackage(qualifiedPackageName, moduleNameString)) - return new char[][] { ModuleBinding.UNNAMED }; - } else { - char[][] declaringModules = cp.getModulesDeclaringPackage(qualifiedPackageName, null); - if (declaringModules != null) { - if (cp instanceof ClasspathJrt && this.hasLimitModules) { - declaringModules = filterModules(declaringModules); - hasUnobserable |= declaringModules == null; - } - if (allNames == null) - allNames = declaringModules; - else - allNames = CharOperation.arrayConcat(allNames, declaringModules); - } - } - } - } - if (allNames == null && hasUnobserable) - return new char[][] { ModuleBinding.UNOBSERVABLE }; - return allNames; -} -private char[][] filterModules(char[][] declaringModules) { - char[][] filtered = Arrays.stream(declaringModules).filter(m -> this.moduleLocations.containsKey(new String(m))).toArray(char[][]::new); - if (filtered.length == 0) - return null; - return filtered; -} -private Parser getParser() { - Map opts = new HashMap<>(); - opts.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_9); - return new Parser( - new ProblemReporter(DefaultErrorHandlingPolicies.exitOnFirstError(), new CompilerOptions(opts), new DefaultProblemFactory(Locale.getDefault())), - false); -} -@Override -public boolean hasCompilationUnit(char[][] qualifiedPackageName, char[] moduleName, boolean checkCUs) { - String qPackageName = String.valueOf(CharOperation.concatWith(qualifiedPackageName, '/')); - String moduleNameString = String.valueOf(moduleName); - LookupStrategy strategy = LookupStrategy.get(moduleName); - Parser parser = checkCUs ? getParser() : null; - Function pkgNameExtractor = sourceUnit -> { - String pkgName = null; - CompilationResult compilationResult = new CompilationResult(sourceUnit, 0, 0, 1); - char[][] name = parser.parsePackageDeclaration(sourceUnit.getContents(), compilationResult); - if (name != null) { - pkgName = CharOperation.toString(name); - } - return pkgName; - }; - switch (strategy) { - case Named: - if (this.moduleLocations != null) { - Classpath location = this.moduleLocations.get(moduleNameString); - if (location != null) - return checkCUs ? location.hasCUDeclaringPackage(qPackageName, pkgNameExtractor) - : location.hasCompilationUnit(qPackageName, moduleNameString); - } - return false; - default: - for (int i = 0; i < this.classpaths.length; i++) { - Classpath location = this.classpaths[i]; - if (strategy.matches(location, Classpath::hasModule)) - if (location.hasCompilationUnit(qPackageName, moduleNameString)) - return true; - } - return false; - } -} - -@Override -public IModule getModule(char[] name) { - if (this.module != null && CharOperation.equals(name, this.module.name())) { - return this.module; - } - if (this.moduleLocations.containsKey(new String(name))) { - for (Classpath classpath : this.classpaths) { - IModule mod = classpath.getModule(name); - if (mod != null) { - return mod; - } - } - } - return null; -} -public IModule getModuleFromEnvironment(char[] name) { - if (this.module != null && CharOperation.equals(name, this.module.name())) { - return this.module; - } - for (Classpath classpath : this.classpaths) { - IModule mod = classpath.getModule(name); - if (mod != null) { - return mod; - } - } - return null; -} - -@Override -public char[][] getAllAutomaticModules() { - Set set = new HashSet<>(); - for (int i = 0, l = this.classpaths.length; i < l; i++) { - if (this.classpaths[i].isAutomaticModule()) { - set.add(this.classpaths[i].getModule().name()); - } - } - return set.toArray(new char[set.size()][]); -} - -@Override -public char[][] listPackages(char[] moduleName) { - switch (LookupStrategy.get(moduleName)) { - case Named: - Classpath classpath = this.moduleLocations.get(new String(moduleName)); - if (classpath != null) - return classpath.listPackages(); - return CharOperation.NO_CHAR_CHAR; - default: - throw new UnsupportedOperationException("can list packages only of a named module"); //$NON-NLS-1$ - } -} - -void addModuleUpdate(String moduleName, Consumer update, UpdateKind kind) { - UpdatesByKind updates = this.moduleUpdates.get(moduleName); - if (updates == null) { - this.moduleUpdates.put(moduleName, updates = new UpdatesByKind()); - } - updates.getList(kind, true).add(update); -} -@Override -public void applyModuleUpdates(IUpdatableModule compilerModule, IUpdatableModule.UpdateKind kind) { - char[] name = compilerModule.name(); - if (name != ModuleBinding.UNNAMED) { // can't update the unnamed module - UpdatesByKind updates = this.moduleUpdates.get(String.valueOf(name)); - if (updates != null) { - for (Consumer update : updates.getList(kind, false)) - update.accept(compilerModule); - } - } -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/Main.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/Main.java deleted file mode 100644 index 61a0c00..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/Main.java +++ /dev/null @@ -1,5597 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2023 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - * Tom Tromey - Contribution for bug 125961 - * Tom Tromey - Contribution for bug 159641 - * 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" - * bug 365208 - [compiler][batch] command line options for annotation based null analysis - * bug 374605 - Unreasonable warning for enum-based switch statements - * bug 375366 - ECJ ignores unusedParameterIncludeDocCommentReference unless enableJavadoc option is set - * bug 388281 - [compiler][null] inheritance of null annotations as an option - * bug 381443 - [compiler][null] Allow parameter widening from @NonNull to unannotated - * Bug 440477 - [null] Infrastructure for feeding external annotations into compilation - * Bug 440687 - [compiler][batch][null] improve command line option for external annotations - * Bug 408815 - [batch][null] Add CLI option for COMPILER_PB_SYNTACTIC_NULL_ANALYSIS_FOR_FIELDS - * Jesper S Moller - Contributions for - * bug 407297 - [1.8][compiler] Control generation of parameter names by option - * Mat Booth - Contribution for bug 405176 - * Frits Jalvingh - fix for bug 533830. - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.LineNumberReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.DateFormat; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.MissingResourceException; -import java.util.Properties; -import java.util.ResourceBundle; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.function.Function; -import java.util.stream.IntStream; - -import org.eclipse.jdt.core.compiler.CategorizedProblem; -import org.eclipse.jdt.core.compiler.CharOperation; -import org.eclipse.jdt.core.compiler.CompilationProgress; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.core.compiler.batch.BatchCompiler; -import org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager; -import org.eclipse.jdt.internal.compiler.ClassFile; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.Compiler; -import org.eclipse.jdt.internal.compiler.ICompilerRequestor; -import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; -import org.eclipse.jdt.internal.compiler.IProblemFactory; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.batch.ModuleFinder.AddExport; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.classfmt.ExternalAnnotationProvider; -import org.eclipse.jdt.internal.compiler.env.AccessRestriction; -import org.eclipse.jdt.internal.compiler.env.AccessRule; -import org.eclipse.jdt.internal.compiler.env.AccessRuleSet; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.env.IModule.IPackageExport; -import org.eclipse.jdt.internal.compiler.env.IUpdatableModule.UpdateKind; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.impl.CompilerStats; -import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; -import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding; -import org.eclipse.jdt.internal.compiler.lookup.PackageBinding; -import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; -import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; -import org.eclipse.jdt.internal.compiler.parser.Parser; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblem; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; -import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; -import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities; -import org.eclipse.jdt.internal.compiler.util.GenericXMLWriter; -import org.eclipse.jdt.internal.compiler.util.HashtableOfInt; -import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; -import org.eclipse.jdt.internal.compiler.util.Messages; -import org.eclipse.jdt.internal.compiler.util.SuffixConstants; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class Main implements ProblemSeverities, SuffixConstants { - - public static class Logger { - private final PrintWriter err; - private PrintWriter log; - private final Main main; - private final PrintWriter out; - int tagBits; - private static final String CLASS = "class"; //$NON-NLS-1$ - private static final String CLASS_FILE = "classfile"; //$NON-NLS-1$ - private static final String CLASSPATH = "classpath"; //$NON-NLS-1$ - private static final String CLASSPATH_FILE = "FILE"; //$NON-NLS-1$ - private static final String CLASSPATH_FOLDER = "FOLDER"; //$NON-NLS-1$ - private static final String CLASSPATH_ID = "id"; //$NON-NLS-1$ - private static final String CLASSPATH_JAR = "JAR"; //$NON-NLS-1$ - private static final String CLASSPATHS = "classpaths"; //$NON-NLS-1$ - private static final String COMMAND_LINE_ARGUMENT = "argument"; //$NON-NLS-1$ - private static final String COMMAND_LINE_ARGUMENTS = "command_line"; //$NON-NLS-1$ - private static final String COMPILER = "compiler"; //$NON-NLS-1$ - private static final String COMPILER_COPYRIGHT = "copyright"; //$NON-NLS-1$ - private static final String COMPILER_NAME = "name"; //$NON-NLS-1$ - private static final String COMPILER_VERSION = "version"; //$NON-NLS-1$ - public static final int EMACS = 2; - private static final String ERROR = "ERROR"; //$NON-NLS-1$ - private static final String ERROR_TAG = "error"; //$NON-NLS-1$ - private static final String WARNING_TAG = "warning"; //$NON-NLS-1$ - private static final String EXCEPTION = "exception"; //$NON-NLS-1$ - private static final String EXTRA_PROBLEM_TAG = "extra_problem"; //$NON-NLS-1$ - private static final String EXTRA_PROBLEMS = "extra_problems"; //$NON-NLS-1$ - private static final HashtableOfInt FIELD_TABLE = new HashtableOfInt(); - private static final String KEY = "key"; //$NON-NLS-1$ - private static final String MESSAGE = "message"; //$NON-NLS-1$ - private static final String NUMBER_OF_CLASSFILES = "number_of_classfiles"; //$NON-NLS-1$ - private static final String NUMBER_OF_ERRORS = "errors"; //$NON-NLS-1$ - private static final String NUMBER_OF_LINES = "number_of_lines"; //$NON-NLS-1$ - private static final String NUMBER_OF_PROBLEMS = "problems"; //$NON-NLS-1$ - private static final String NUMBER_OF_TASKS = "tasks"; //$NON-NLS-1$ - private static final String NUMBER_OF_WARNINGS = "warnings"; //$NON-NLS-1$ - private static final String NUMBER_OF_INFOS = "infos"; //$NON-NLS-1$ - private static final String OPTION = "option"; //$NON-NLS-1$ - private static final String OPTIONS = "options"; //$NON-NLS-1$ - private static final String OUTPUT = "output"; //$NON-NLS-1$ - private static final String PACKAGE = "package"; //$NON-NLS-1$ - private static final String PATH = "path"; //$NON-NLS-1$ - private static final String PROBLEM_ARGUMENT = "argument"; //$NON-NLS-1$ - private static final String PROBLEM_ARGUMENT_VALUE = "value"; //$NON-NLS-1$ - private static final String PROBLEM_ARGUMENTS = "arguments"; //$NON-NLS-1$ - private static final String PROBLEM_CATEGORY_ID = "categoryID"; //$NON-NLS-1$ - private static final String ID = "id"; //$NON-NLS-1$ - private static final String PROBLEM_ID = "problemID"; //$NON-NLS-1$ - private static final String PROBLEM_LINE = "line"; //$NON-NLS-1$ - private static final String PROBLEM_OPTION_KEY = "optionKey"; //$NON-NLS-1$ - private static final String PROBLEM_MESSAGE = "message"; //$NON-NLS-1$ - private static final String PROBLEM_SEVERITY = "severity"; //$NON-NLS-1$ - private static final String PROBLEM_SOURCE_END = "charEnd"; //$NON-NLS-1$ - private static final String PROBLEM_SOURCE_START = "charStart"; //$NON-NLS-1$ - private static final String PROBLEM_SUMMARY = "problem_summary"; //$NON-NLS-1$ - private static final String PROBLEM_TAG = "problem"; //$NON-NLS-1$ - private static final String PROBLEMS = "problems"; //$NON-NLS-1$ - private static final String SOURCE = "source"; //$NON-NLS-1$ - private static final String SOURCE_CONTEXT = "source_context"; //$NON-NLS-1$ - private static final String SOURCE_END = "sourceEnd"; //$NON-NLS-1$ - private static final String SOURCE_START = "sourceStart"; //$NON-NLS-1$ - private static final String SOURCES = "sources"; //$NON-NLS-1$ - - private static final String STATS = "stats"; //$NON-NLS-1$ - - private static final String TASK = "task"; //$NON-NLS-1$ - private static final String TASKS = "tasks"; //$NON-NLS-1$ - private static final String TIME = "time"; //$NON-NLS-1$ - private static final String VALUE = "value"; //$NON-NLS-1$ - private static final String WARNING = "WARNING"; //$NON-NLS-1$ - private static final String INFO = "INFO"; //$NON-NLS-1$ - - public static final int XML = 1; - private static final String XML_DTD_DECLARATION = ""; //$NON-NLS-1$ - static { - try { - Class c = IProblem.class; - Field[] fields = c.getFields(); - for (int i = 0, max = fields.length; i < max; i++) { - Field field = fields[i]; - if (field.getType().equals(Integer.TYPE)) { - Integer value = (Integer) field.get(null); - int key2 = value.intValue() & IProblem.IgnoreCategoriesMask; - if (key2 == 0) { - key2 = Integer.MAX_VALUE; - } - Logger.FIELD_TABLE.put(key2, field.getName()); - } - } - } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); - } - } - public Logger(Main main, PrintWriter out, PrintWriter err) { - this.out = out; - this.err = err; - this.main = main; - } - - public String buildFileName( - String outputPath, - String relativeFileName) { - char fileSeparatorChar = File.separatorChar; - String fileSeparator = File.separator; - - outputPath = outputPath.replace('/', fileSeparatorChar); - // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name - StringBuilder outDir = new StringBuilder(outputPath); - if (!outputPath.endsWith(fileSeparator)) { - outDir.append(fileSeparator); - } - StringTokenizer tokenizer = - new StringTokenizer(relativeFileName, fileSeparator); - String token = tokenizer.nextToken(); - while (tokenizer.hasMoreTokens()) { - outDir.append(token).append(fileSeparator); - token = tokenizer.nextToken(); - } - // token contains the last one - return outDir.append(token).toString(); - } - - public void close() { - if (this.log != null) { - if ((this.tagBits & Logger.XML) != 0) { - endTag(Logger.COMPILER); - flush(); - } - this.log.close(); - } - } - - public void compiling() { - printlnOut(this.main.bind("progress.compiling")); //$NON-NLS-1$ - } - private void endLoggingExtraProblems() { - endTag(Logger.EXTRA_PROBLEMS); - } - /** - * Used to stop logging problems. - * Only use in xml mode. - */ - private void endLoggingProblems() { - endTag(Logger.PROBLEMS); - } - public void endLoggingSource() { - if ((this.tagBits & Logger.XML) != 0) { - endTag(Logger.SOURCE); - } - } - - public void endLoggingSources() { - if ((this.tagBits & Logger.XML) != 0) { - endTag(Logger.SOURCES); - } - } - - public void endLoggingTasks() { - if ((this.tagBits & Logger.XML) != 0) { - endTag(Logger.TASKS); - } - } - private void endTag(String name) { - if (this.log != null) { - ((GenericXMLWriter) this.log).endTag(name, true, true); - } - } - private String errorReportSource(CategorizedProblem problem, char[] unitSource, int bits) { - //extra from the source the innacurate token - //and "highlight" it using some underneath ^^^^^ - //put some context around too. - - //this code assumes that the font used in the console is fixed size - - //sanity ..... - int startPosition = problem.getSourceStart(); - int endPosition = problem.getSourceEnd(); - if (unitSource == null) { - if (problem.getOriginatingFileName() != null) { - try { - unitSource = Util.getFileCharContent(new File(new String(problem.getOriginatingFileName())), null); - } catch (IOException e) { - // ignore; - } - } - } - int length; - if ((startPosition > endPosition) - || ((startPosition < 0) && (endPosition < 0)) - || (unitSource == null) - || (length = unitSource.length) == 0) - return Messages.problem_noSourceInformation; - - StringBuilder errorBuffer = new StringBuilder(); - if ((bits & Main.Logger.EMACS) == 0) { - errorBuffer.append(' ').append(Messages.bind(Messages.problem_atLine, String.valueOf(problem.getSourceLineNumber()))); - errorBuffer.append(Util.LINE_SEPARATOR); - } - errorBuffer.append('\t'); - - char c; - final char SPACE = '\u0020'; - final char MARK = '^'; - final char TAB = '\t'; - //the next code tries to underline the token..... - //it assumes (for a good display) that token source does not - //contain any \r \n. This is false on statements ! - //(the code still works but the display is not optimal !) - - // expand to line limits - int begin; - int end; - for (begin = startPosition >= length ? length - 1 : startPosition; begin > 0; begin--) { - if ((c = unitSource[begin - 1]) == '\n' || c == '\r') break; - } - for (end = endPosition >= length ? length - 1 : endPosition ; end+1 < length; end++) { - if ((c = unitSource[end + 1]) == '\r' || c == '\n') break; - } - - // trim left and right spaces/tabs - while ((c = unitSource[begin]) == ' ' || c == '\t') begin++; - //while ((c = unitSource[end]) == ' ' || c == '\t') end--; TODO (philippe) should also trim right, but all tests are to be updated - - // copy source - errorBuffer.append(unitSource, begin, end-begin+1); - errorBuffer.append(Util.LINE_SEPARATOR).append("\t"); //$NON-NLS-1$ - - // compute underline - for (int i = begin; i = length ? length - 1 : endPosition); i++) { - errorBuffer.append(MARK); - } - return errorBuffer.toString(); - } - - private void extractContext(CategorizedProblem problem, char[] unitSource) { - //sanity ..... - int startPosition = problem.getSourceStart(); - int endPosition = problem.getSourceEnd(); - if (unitSource == null) { - if (problem.getOriginatingFileName() != null) { - try { - unitSource = Util.getFileCharContent(new File(new String(problem.getOriginatingFileName())), null); - } catch(IOException e) { - // ignore - } - } - } - int length; - if ((startPosition > endPosition) - || ((startPosition < 0) && (endPosition < 0)) - || (unitSource == null) - || ((length = unitSource.length) <= 0) - || (endPosition > length)) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.VALUE, Messages.problem_noSourceInformation); - parameters.put(Logger.SOURCE_START, "-1"); //$NON-NLS-1$ - parameters.put(Logger.SOURCE_END, "-1"); //$NON-NLS-1$ - printTag(Logger.SOURCE_CONTEXT, parameters, true, true); - return; - } - - char c; - //the next code tries to underline the token..... - //it assumes (for a good display) that token source does not - //contain any \r \n. This is false on statements ! - //(the code still works but the display is not optimal !) - - // expand to line limits - int begin, end; - for (begin = startPosition >= length ? length - 1 : startPosition; begin > 0; begin--) { - if ((c = unitSource[begin - 1]) == '\n' || c == '\r') break; - } - for (end = endPosition >= length ? length - 1 : endPosition ; end+1 < length; end++) { - if ((c = unitSource[end + 1]) == '\r' || c == '\n') break; - } - - // trim left and right spaces/tabs - while ((c = unitSource[begin]) == ' ' || c == '\t') begin++; - while ((c = unitSource[end]) == ' ' || c == '\t') end--; - - // copy source - StringBuilder buffer = new StringBuilder(); - buffer.append(unitSource, begin, end - begin + 1); - HashMap parameters = new HashMap<>(); - parameters.put(Logger.VALUE, String.valueOf(buffer)); - parameters.put(Logger.SOURCE_START, Integer.toString(startPosition - begin)); - parameters.put(Logger.SOURCE_END, Integer.toString(endPosition - begin)); - printTag(Logger.SOURCE_CONTEXT, parameters, true, true); - } - public void flush() { - this.out.flush(); - this.err.flush(); - if (this.log != null) { - this.log.flush(); - } - } - - private String getFieldName(int id) { - int key2 = id & IProblem.IgnoreCategoriesMask; - if (key2 == 0) { - key2 = Integer.MAX_VALUE; - } - return (String) Logger.FIELD_TABLE.get(key2); - } - - // find out an option name controlling a given problemID - private String getProblemOptionKey(int problemID) { - int irritant = ProblemReporter.getIrritant(problemID); - return CompilerOptions.optionKeyFromIrritant(irritant); - } - - public void logAverage() { - Arrays.sort(this.main.compilerStats); - long lineCount = this.main.compilerStats[0].lineCount; - final int length = this.main.maxRepetition; - long sum = 0; - long parseSum = 0, resolveSum = 0, analyzeSum = 0, generateSum = 0; - for (int i = 1, max = length - 1; i < max; i++) { - CompilerStats stats = this.main.compilerStats[i]; - sum += stats.elapsedTime(); - parseSum += stats.parseTime; - resolveSum += stats.resolveTime; - analyzeSum += stats.analyzeTime; - generateSum += stats.generateTime; - } - long time = sum / (length - 2); - long parseTime = parseSum/(length - 2); - long resolveTime = resolveSum/(length - 2); - long analyzeTime = analyzeSum/(length - 2); - long generateTime = generateSum/(length - 2); - printlnOut(this.main.bind( - "compile.averageTime", //$NON-NLS-1$ - new String[] { - String.valueOf(lineCount), - String.valueOf(time), - String.valueOf(((int) (lineCount * 10000.0 / time)) / 10.0), - })); - if ((this.main.timing & Main.TIMING_DETAILED) != 0) { - printlnOut( - this.main.bind("compile.detailedTime", //$NON-NLS-1$ - new String[] { - String.valueOf(parseTime), - String.valueOf(((int) (parseTime * 1000.0 / time)) / 10.0), - String.valueOf(resolveTime), - String.valueOf(((int) (resolveTime * 1000.0 / time)) / 10.0), - String.valueOf(analyzeTime), - String.valueOf(((int) (analyzeTime * 1000.0 / time)) / 10.0), - String.valueOf(generateTime), - String.valueOf(((int) (generateTime * 1000.0 / time)) / 10.0), - })); - } - } - public void logClassFile(boolean generatePackagesStructure, String outputPath, String relativeFileName) { - if ((this.tagBits & Logger.XML) != 0) { - String fileName = null; - if (generatePackagesStructure) { - fileName = buildFileName(outputPath, relativeFileName); - } else { - char fileSeparatorChar = File.separatorChar; - String fileSeparator = File.separator; - // First we ensure that the outputPath exists - outputPath = outputPath.replace('/', fileSeparatorChar); - // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name - int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar); - if (indexOfPackageSeparator == -1) { - if (outputPath.endsWith(fileSeparator)) { - fileName = outputPath + relativeFileName; - } else { - fileName = outputPath + fileSeparator + relativeFileName; - } - } else { - int length = relativeFileName.length(); - if (outputPath.endsWith(fileSeparator)) { - fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length); - } else { - fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length); - } - } - } - File f = new File(fileName); - try { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.PATH, f.getCanonicalPath()); - printTag(Logger.CLASS_FILE, parameters, true, true); - } catch (IOException e) { - logNoClassFileCreated(outputPath, relativeFileName, e); - } - } - } - public void logClasspath(FileSystem.Classpath[] classpaths) { - if (classpaths == null) return; - if ((this.tagBits & Logger.XML) != 0) { - final int length = classpaths.length; - if (length != 0) { - // generate xml output - printTag(Logger.CLASSPATHS, new HashMap<>(), true, false); - HashMap parameters = new HashMap<>(); - for (int i = 0; i < length; i++) { - String classpath = classpaths[i].getPath(); - parameters.put(Logger.PATH, classpath); - File f = new File(classpath); - String id = null; - if (f.isFile()) { - int kind = Util.archiveFormat(classpath); - switch (kind) { - case Util.ZIP_FILE: - id = Logger.CLASSPATH_JAR; - break; - default: - id = Logger.CLASSPATH_FILE; - break; - } - } else if (f.isDirectory()) { - id = Logger.CLASSPATH_FOLDER; - } - if (id != null) { - parameters.put(Logger.CLASSPATH_ID, id); - printTag(Logger.CLASSPATH, parameters, true, true); - } - } - endTag(Logger.CLASSPATHS); - } - } - - } - - public void logCommandLineArguments(String[] commandLineArguments) { - if (commandLineArguments == null) return; - if ((this.tagBits & Logger.XML) != 0) { - final int length = commandLineArguments.length; - if (length != 0) { - // generate xml output - printTag(Logger.COMMAND_LINE_ARGUMENTS, new HashMap<>(), true, false); - for (int i = 0; i < length; i++) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.VALUE, commandLineArguments[i]); - printTag(Logger.COMMAND_LINE_ARGUMENT, parameters, true, true); - } - endTag(Logger.COMMAND_LINE_ARGUMENTS); - } - } - } - - /** - * @param e the given exception to log - */ - public void logException(Exception e) { - final String stackTrace = Util.getStackTrace(e).toString(); - if ((this.tagBits & Logger.XML) != 0) { - StringBuilder buffer = new StringBuilder(); - String message = e.getMessage(); - try (LineNumberReader reader = new LineNumberReader(new StringReader(stackTrace))) { - String line; - int i = 0; - if (message != null) { - buffer.append(message).append(Util.LINE_SEPARATOR); - } - while ((line = reader.readLine()) != null && i < 4) { - buffer.append(line).append(Util.LINE_SEPARATOR); - i++; - } - } catch (IOException e1) { - // ignore - } - message = buffer.toString(); - HashMap parameters = new HashMap<>(); - parameters.put(Logger.MESSAGE, message); - parameters.put(Logger.CLASS, e.getClass()); - printTag(Logger.EXCEPTION, parameters, true, true); - } - String message = e.getMessage(); - if (message == null) { - this.printlnErr(stackTrace); - } else { - this.printlnErr(message); - } - } - - private void logExtraProblem(CategorizedProblem problem, int localErrorCount, int globalErrorCount) { - char[] originatingFileName = problem.getOriginatingFileName(); - if (originatingFileName == null) { - // simplified message output - String severity = problem.isError() ? "requestor.extraerror" //$NON-NLS-1$ - : problem.isInfo() ? "requestor.extrainfo" : "requestor.extrawarning"; //$NON-NLS-1$ //$NON-NLS-2$ - printErr(this.main.bind( - severity, - Integer.toString(globalErrorCount))); - printErr(" "); //$NON-NLS-1$ - this.printlnErr(problem.getMessage()); - } else { - String fileName = new String(originatingFileName); - if ((this.tagBits & Logger.EMACS) != 0) { - String severity = problem.isError() ? "output.emacs.error" : //$NON-NLS-1$ - problem.isInfo() ? "output.emacs.info" //$NON-NLS-1$ - : "output.emacs.warning"; //$NON-NLS-1$ - String result = fileName - + ":" //$NON-NLS-1$ - + problem.getSourceLineNumber() - + ": " //$NON-NLS-1$ - + this.main.bind(severity) - + ": " //$NON-NLS-1$ - + problem.getMessage(); - this.printlnErr(result); - final String errorReportSource = errorReportSource(problem, null, this.tagBits); - this.printlnErr(errorReportSource); - } else { - if (localErrorCount == 0) { - this.printlnErr("----------"); //$NON-NLS-1$ - } - String severity = problem.isError() ? "requestor.error" //$NON-NLS-1$ - : problem.isInfo() ? "requestor.info" : "requestor.warning"; //$NON-NLS-1$ //$NON-NLS-2$ - printErr(this.main.bind( - severity, - Integer.toString(globalErrorCount), - fileName)); - final String errorReportSource = errorReportSource(problem, null, 0); - this.printlnErr(errorReportSource); - this.printlnErr(problem.getMessage()); - this.printlnErr("----------"); //$NON-NLS-1$ - } - } - } - - public void loggingExtraProblems(Main currentMain) { - ArrayList problems = currentMain.extraProblems; - final int count = problems.size(); - int localProblemCount = 0; - if (count != 0) { - int errors = 0; - int warnings = 0; - int infos = 0; - for (int i = 0; i < count; i++) { - CategorizedProblem problem = problems.get(i); - if (!this.main.isIgnored(problem)) { - currentMain.globalProblemsCount++; - logExtraProblem(problem, localProblemCount, currentMain.globalProblemsCount); - localProblemCount++; - if (problem.isError()) { - errors++; - currentMain.globalErrorsCount++; - } else if (problem.isInfo()) { - currentMain.globalInfoCount++; - infos++; - } else { - currentMain.globalWarningsCount++; - warnings++; - } - } - } - if ((this.tagBits & Logger.XML) != 0) { - if ((errors + warnings + infos) != 0) { - startLoggingExtraProblems(count); - for (int i = 0; i < count; i++) { - CategorizedProblem problem = problems.get(i); - if (!this.main.isIgnored(problem)) { - if (problem.getID() != IProblem.Task) { - logXmlExtraProblem(problem, localProblemCount, currentMain.globalProblemsCount); - } - } - } - endLoggingExtraProblems(); - } - } - } - } - - public void logUnavaibleAPT(String className) { - if ((this.tagBits & Logger.XML) != 0) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.MESSAGE, this.main.bind("configure.unavailableAPT", className)); //$NON-NLS-1$ - printTag(Logger.ERROR_TAG, parameters, true, true); - } - this.printlnErr(this.main.bind("configure.unavailableAPT", className)); //$NON-NLS-1$ - } - - public void logIncorrectVMVersionForAnnotationProcessing() { - if ((this.tagBits & Logger.XML) != 0) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.MESSAGE, this.main.bind("configure.incorrectVMVersionforAPT")); //$NON-NLS-1$ - printTag(Logger.ERROR_TAG, parameters, true, true); - } - this.printlnErr(this.main.bind("configure.incorrectVMVersionforAPT")); //$NON-NLS-1$ - } - - public void logNoClassFileCreated(String outputDir, String relativeFileName, IOException e) { - if ((this.tagBits & Logger.XML) != 0) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.MESSAGE, this.main.bind("output.noClassFileCreated", //$NON-NLS-1$ - new String[] { - outputDir, - relativeFileName, - e.getMessage() - })); - printTag(Logger.ERROR_TAG, parameters, true, true); - } - this.printlnErr(this.main.bind("output.noClassFileCreated", //$NON-NLS-1$ - new String[] { - outputDir, - relativeFileName, - e.getMessage() - })); - } - - public void logNumberOfClassFilesGenerated(int exportedClassFilesCounter) { - if ((this.tagBits & Logger.XML) != 0) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.VALUE, Integer.valueOf(exportedClassFilesCounter)); - printTag(Logger.NUMBER_OF_CLASSFILES, parameters, true, true); - } - if (exportedClassFilesCounter == 1) { - printlnOut(this.main.bind("compile.oneClassFileGenerated")); //$NON-NLS-1$ - } else { - printlnOut(this.main.bind("compile.severalClassFilesGenerated", //$NON-NLS-1$ - String.valueOf(exportedClassFilesCounter))); - } - } - - /** - * @param options the given compiler options - */ - public void logOptions(Map options) { - if ((this.tagBits & Logger.XML) != 0) { - printTag(Logger.OPTIONS, new HashMap<>(), true, false); - final Set> entriesSet = options.entrySet(); - Map.Entry[] entries = entriesSet.toArray(new Map.Entry[entriesSet.size()]); - Arrays.sort(entries, new Comparator>() { - @Override - public int compare(Map.Entry o1, Map.Entry o2) { - Map.Entry entry1 = o1; - Map.Entry entry2 = o2; - return entry1.getKey().compareTo(entry2.getKey()); - } - }); - HashMap parameters = new HashMap<>(); - for (int i = 0, max = entries.length; i < max; i++) { - Map.Entry entry = entries[i]; - String key = entry.getKey(); - parameters.put(Logger.KEY, key); - parameters.put(Logger.VALUE, entry.getValue()); - printTag(Logger.OPTION, parameters, true, true); - } - endTag(Logger.OPTIONS); - } - } - - /** - * @param error the given error - */ - public void logPendingError(String error) { - if ((this.tagBits & Logger.XML) != 0) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.MESSAGE, error); - printTag(Logger.ERROR_TAG, parameters, true, true); - } - this.printlnErr(error); - } - - /** - * @param message the given message - */ - public void logWarning(String message) { - if ((this.tagBits & Logger.XML) != 0) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.MESSAGE, message); - printTag(Logger.WARNING_TAG, parameters, true, true); - } - this.printlnOut(message); - } - - private void logProblem(CategorizedProblem problem, int localErrorCount, - int globalErrorCount, char[] unitSource) { - if(problem instanceof DefaultProblem) { - ((DefaultProblem) problem).reportError(); - } - if ((this.tagBits & Logger.EMACS) != 0) { - String severity = problem.isError() ? "output.emacs.error" : //$NON-NLS-1$ - problem.isInfo() ? "output.emacs.info" //$NON-NLS-1$ - : "output.emacs.warning"; //$NON-NLS-1$ - String result = (new String(problem.getOriginatingFileName()) - + ":" //$NON-NLS-1$ - + problem.getSourceLineNumber() - + ": " //$NON-NLS-1$ - + (this.main.bind(severity)) - + ": " //$NON-NLS-1$ - + problem.getMessage()); - this.printlnErr(result); - final String errorReportSource = errorReportSource(problem, unitSource, this.tagBits); - if (errorReportSource.length() != 0) this.printlnErr(errorReportSource); - } else { - if (localErrorCount == 0) { - this.printlnErr("----------"); //$NON-NLS-1$ - } - String severity = problem.isError() ? "requestor.error" : problem.isInfo() ? "requestor.info" : "requestor.warning"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - printErr(this.main.bind(severity, - Integer.toString(globalErrorCount), - new String(problem.getOriginatingFileName()))); - try { - final String errorReportSource = errorReportSource(problem, unitSource, 0); - this.printlnErr(errorReportSource); - this.printlnErr(problem.getMessage()); - } catch (Exception e) { - this.printlnErr(this.main.bind( - "requestor.notRetrieveErrorMessage", problem.toString())); //$NON-NLS-1$ - } - this.printlnErr("----------"); //$NON-NLS-1$ - } - } - - public int logProblems(CategorizedProblem[] problems, char[] unitSource, Main currentMain) { - final int count = problems.length; - int localErrorCount = 0; - int localProblemCount = 0; - if (count != 0) { - int errors = 0; - int warnings = 0; - int infos = 0; - int tasks = 0; - for (int i = 0; i < count; i++) { - CategorizedProblem problem = problems[i]; - if (problem != null) { - currentMain.globalProblemsCount++; - logProblem(problem, localProblemCount, currentMain.globalProblemsCount, unitSource); - localProblemCount++; - if (problem.isError()) { - localErrorCount++; - errors++; - currentMain.globalErrorsCount++; - } else if (problem.getID() == IProblem.Task) { - currentMain.globalTasksCount++; - tasks++; - } else if (problem.isInfo()) { - currentMain.globalInfoCount++; - infos++; - } else { - currentMain.globalWarningsCount++; - warnings++; - } - } - } - if ((this.tagBits & Logger.XML) != 0) { - if ((errors + warnings + infos) != 0) { - startLoggingProblems(errors, warnings, infos); - for (int i = 0; i < count; i++) { - CategorizedProblem problem = problems[i]; - if (problem!= null) { - if (problem.getID() != IProblem.Task) { - logXmlProblem(problem, unitSource); - } - } - } - endLoggingProblems(); - } - if (tasks != 0) { - startLoggingTasks(tasks); - for (int i = 0; i < count; i++) { - CategorizedProblem problem = problems[i]; - if (problem!= null) { - if (problem.getID() == IProblem.Task) { - logXmlTask(problem, unitSource); - } - } - } - endLoggingTasks(); - } - } - } - return localErrorCount; - } - - public void logProblemsSummary(int globalProblemsCount, - int globalErrorsCount, int globalWarningsCount, int globalInfoCount, int globalTasksCount) { - if ((this.tagBits & Logger.XML) != 0) { - // generate xml - HashMap parameters = new HashMap<>(); - parameters.put(Logger.NUMBER_OF_PROBLEMS, Integer.valueOf(globalProblemsCount)); - parameters.put(Logger.NUMBER_OF_ERRORS, Integer.valueOf(globalErrorsCount)); - parameters.put(Logger.NUMBER_OF_WARNINGS, Integer.valueOf(globalWarningsCount)); - parameters.put(Logger.NUMBER_OF_INFOS, Integer.valueOf(globalInfoCount)); - parameters.put(Logger.NUMBER_OF_TASKS, Integer.valueOf(globalTasksCount)); - printTag(Logger.PROBLEM_SUMMARY, parameters, true, true); - } - if (globalProblemsCount == 1) { - String message = null; - if (globalErrorsCount == 1) { - message = this.main.bind("compile.oneError"); //$NON-NLS-1$ - } else if (globalInfoCount == 1) { - message = this.main.bind("compile.oneInfo"); //$NON-NLS-1$ - } else { - message = this.main.bind("compile.oneWarning"); //$NON-NLS-1$ - } - printErr(this.main.bind("compile.oneProblem", message)); //$NON-NLS-1$ - } else { - String errorMessage = null; - String warningMessage = null; - String infoMessage = null; - if (globalErrorsCount > 0) { - if (globalErrorsCount == 1) { - errorMessage = this.main.bind("compile.oneError"); //$NON-NLS-1$ - } else { - errorMessage = this.main.bind("compile.severalErrors", String.valueOf(globalErrorsCount)); //$NON-NLS-1$ - } - } - int warningsNumber = globalWarningsCount + globalTasksCount; - if (warningsNumber > 0) { - if (warningsNumber == 1) { - warningMessage = this.main.bind("compile.oneWarning"); //$NON-NLS-1$ - } else { - warningMessage = this.main.bind("compile.severalWarnings", String.valueOf(warningsNumber)); //$NON-NLS-1$ - } - } - if (globalInfoCount == 1) { - infoMessage = this.main.bind("compile.oneInfo"); //$NON-NLS-1$ - } else if (globalInfoCount > 1) { - infoMessage = this.main.bind("compile.severalInfos", String.valueOf(globalInfoCount)); //$NON-NLS-1$ - } - if (globalProblemsCount == globalInfoCount || globalProblemsCount == globalErrorsCount || globalProblemsCount == globalWarningsCount) { - String msg = errorMessage != null ? errorMessage : warningMessage != null ? warningMessage : infoMessage; - printErr(this.main.bind( - "compile.severalProblemsErrorsOrWarnings", //$NON-NLS-1$ - String.valueOf(globalProblemsCount), - msg)); - } else { - if (globalInfoCount == 0) { - printErr(this.main.bind( - "compile.severalProblemsErrorsAndWarnings", //$NON-NLS-1$ - new String[] { - String.valueOf(globalProblemsCount), - errorMessage, - warningMessage - })); - } else { - if (errorMessage == null) { - errorMessage = this.main.bind("compile.severalErrors", String.valueOf(globalErrorsCount)); //$NON-NLS-1$ - } - if (warningMessage == null) { - warningMessage = this.main.bind("compile.severalWarnings", String.valueOf(warningsNumber)); //$NON-NLS-1$ - } - printErr(this.main.bind( - "compile.severalProblems", //$NON-NLS-1$ - new String[] { - String.valueOf(globalProblemsCount), - errorMessage, - warningMessage, - infoMessage - })); - } - } - } - if (this.main.failOnWarning && globalWarningsCount > 0) { - printErr("\n"); //$NON-NLS-1$ - printErr(this.main.bind("compile.failOnWarning")); //$NON-NLS-1$ - } - if ((this.tagBits & Logger.XML) == 0) { - this.printlnErr(); - } - } - - public void logProgress() { - printOut('.'); - } - - /** - * @param i - * the current repetition number - * @param repetitions - * the given number of repetitions - */ - public void logRepetition(int i, int repetitions) { - printlnOut(this.main.bind("compile.repetition", //$NON-NLS-1$ - String.valueOf(i + 1), String.valueOf(repetitions))); - } - public void logTiming(CompilerStats compilerStats) { - long time = compilerStats.elapsedTime(); - long lineCount = compilerStats.lineCount; - if ((this.tagBits & Logger.XML) != 0) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.VALUE, Long.valueOf(time)); - printTag(Logger.TIME, parameters, true, true); - parameters.put(Logger.VALUE, Long.valueOf(lineCount)); - printTag(Logger.NUMBER_OF_LINES, parameters, true, true); - } - if (lineCount != 0) { - printlnOut( - this.main.bind("compile.instantTime", //$NON-NLS-1$ - new String[] { - String.valueOf(lineCount), - String.valueOf(time), - String.valueOf(((int) (lineCount * 10000.0 / time)) / 10.0), - })); - } else { - printlnOut( - this.main.bind("compile.totalTime", //$NON-NLS-1$ - new String[] { - String.valueOf(time), - })); - } - if ((this.main.timing & Main.TIMING_DETAILED) != 0) { - printlnOut( - this.main.bind("compile.detailedTime", //$NON-NLS-1$ - new String[] { - String.valueOf(compilerStats.parseTime), - String.valueOf(((int) (compilerStats.parseTime * 1000.0 / time)) / 10.0), - String.valueOf(compilerStats.resolveTime), - String.valueOf(((int) (compilerStats.resolveTime * 1000.0 / time)) / 10.0), - String.valueOf(compilerStats.analyzeTime), - String.valueOf(((int) (compilerStats.analyzeTime * 1000.0 / time)) / 10.0), - String.valueOf(compilerStats.generateTime), - String.valueOf(((int) (compilerStats.generateTime * 1000.0 / time)) / 10.0), - })); - } - } - - /** - * Print the usage of the compiler - */ - public void logUsage(String usage) { - printlnOut(usage); - } - - /** - * Print the version of the compiler in the log and/or the out field - */ - public void logVersion(final boolean printToOut) { - if (this.log != null && (this.tagBits & Logger.XML) == 0) { - final String version = this.main.bind("misc.version", //$NON-NLS-1$ - new String[] { - this.main.bind("compiler.name"), //$NON-NLS-1$ - this.main.bind("compiler.version"), //$NON-NLS-1$ - this.main.bind("compiler.copyright") //$NON-NLS-1$ - } - ); - this.log.println("# " + version); //$NON-NLS-1$ - if (printToOut) { - this.out.println(version); - this.out.flush(); - } - } else if (printToOut) { - final String version = this.main.bind("misc.version", //$NON-NLS-1$ - new String[] { - this.main.bind("compiler.name"), //$NON-NLS-1$ - this.main.bind("compiler.version"), //$NON-NLS-1$ - this.main.bind("compiler.copyright") //$NON-NLS-1$ - } - ); - this.out.println(version); - this.out.flush(); - } - } - - /** - * Print the usage of wrong JDK - */ - public void logWrongJDK() { - if ((this.tagBits & Logger.XML) != 0) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.MESSAGE, this.main.bind("configure.requiresJDK1.2orAbove")); //$NON-NLS-1$ - printTag(Logger.ERROR, parameters, true, true); - } - this.printlnErr(this.main.bind("configure.requiresJDK1.2orAbove")); //$NON-NLS-1$ - } - - private void logXmlExtraProblem(CategorizedProblem problem, int globalErrorCount, int localErrorCount) { - final int sourceStart = problem.getSourceStart(); - final int sourceEnd = problem.getSourceEnd(); - boolean isError = problem.isError(); - HashMap parameters = new HashMap<>(); - parameters.put(Logger.PROBLEM_SEVERITY, isError ? Logger.ERROR : (problem.isInfo() ? Logger.INFO : Logger.WARNING)); - parameters.put(Logger.PROBLEM_LINE, Integer.valueOf(problem.getSourceLineNumber())); - parameters.put(Logger.PROBLEM_SOURCE_START, Integer.valueOf(sourceStart)); - parameters.put(Logger.PROBLEM_SOURCE_END, Integer.valueOf(sourceEnd)); - printTag(Logger.EXTRA_PROBLEM_TAG, parameters, true, false); - parameters.put(Logger.VALUE, problem.getMessage()); - printTag(Logger.PROBLEM_MESSAGE, parameters, true, true); - extractContext(problem, null); - endTag(Logger.EXTRA_PROBLEM_TAG); - } - /** - * @param problem - * the given problem to log - * @param unitSource - * the given unit source - */ - private void logXmlProblem(CategorizedProblem problem, char[] unitSource) { - final int sourceStart = problem.getSourceStart(); - final int sourceEnd = problem.getSourceEnd(); - final int id = problem.getID(); - HashMap parameters = new HashMap<>(); - parameters.put(Logger.ID, getFieldName(id)); // ID as field name - parameters.put(Logger.PROBLEM_ID, Integer.valueOf(id)); // ID as numeric value - boolean isError = problem.isError(); - int severity = isError ? ProblemSeverities.Error : ProblemSeverities.Warning; - parameters.put(Logger.PROBLEM_SEVERITY, isError ? Logger.ERROR : (problem.isInfo() ? Logger.INFO : Logger.WARNING)); - parameters.put(Logger.PROBLEM_LINE, Integer.valueOf(problem.getSourceLineNumber())); - parameters.put(Logger.PROBLEM_SOURCE_START, Integer.valueOf(sourceStart)); - parameters.put(Logger.PROBLEM_SOURCE_END, Integer.valueOf(sourceEnd)); - String problemOptionKey = getProblemOptionKey(id); - if (problemOptionKey != null) { - parameters.put(Logger.PROBLEM_OPTION_KEY, problemOptionKey); - } - int categoryID = ProblemReporter.getProblemCategory(severity, id); - parameters.put(Logger.PROBLEM_CATEGORY_ID, Integer.valueOf(categoryID)); - printTag(Logger.PROBLEM_TAG, parameters, true, false); - parameters.put(Logger.VALUE, problem.getMessage()); - printTag(Logger.PROBLEM_MESSAGE, parameters, true, true); - extractContext(problem, unitSource); - String[] arguments = problem.getArguments(); - final int length = arguments.length; - if (length != 0) { - parameters = new HashMap<>(); - printTag(Logger.PROBLEM_ARGUMENTS, parameters, true, false); - for (int i = 0; i < length; i++) { - parameters = new HashMap<>(); - parameters.put(Logger.PROBLEM_ARGUMENT_VALUE, arguments[i]); - printTag(Logger.PROBLEM_ARGUMENT, parameters, true, true); - } - endTag(Logger.PROBLEM_ARGUMENTS); - } - endTag(Logger.PROBLEM_TAG); - } - /** - * @param problem - * the given problem to log - * @param unitSource - * the given unit source - */ - private void logXmlTask(CategorizedProblem problem, char[] unitSource) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.PROBLEM_LINE, Integer.valueOf(problem.getSourceLineNumber())); - parameters.put(Logger.PROBLEM_SOURCE_START, Integer.valueOf(problem.getSourceStart())); - parameters.put(Logger.PROBLEM_SOURCE_END, Integer.valueOf(problem.getSourceEnd())); - String problemOptionKey = getProblemOptionKey(problem.getID()); - if (problemOptionKey != null) { - parameters.put(Logger.PROBLEM_OPTION_KEY, problemOptionKey); - } - printTag(Logger.TASK, parameters, true, false); - parameters.put(Logger.VALUE, problem.getMessage()); - printTag(Logger.PROBLEM_MESSAGE, parameters, true, true); - extractContext(problem, unitSource); - endTag(Logger.TASK); - } - - private void printErr(String s) { - this.err.print(s); - if ((this.tagBits & Logger.XML) == 0 && this.log != null) { - this.log.print(s); - } - } - - private void printlnErr() { - this.err.println(); - if ((this.tagBits & Logger.XML) == 0 && this.log != null) { - this.log.println(); - } - } - - private void printlnErr(String s) { - this.err.println(s); - if ((this.tagBits & Logger.XML) == 0 && this.log != null) { - this.log.println(s); - } - } - - private void printlnOut(String s) { - this.out.println(s); - if ((this.tagBits & Logger.XML) == 0 && this.log != null) { - this.log.println(s); - } - } - - public void printNewLine() { - this.out.println(); - } - - private void printOut(char c) { - this.out.print(c); - } - - public void printStats() { - final boolean isTimed = (this.main.timing & TIMING_ENABLED) != 0; - if ((this.tagBits & Logger.XML) != 0) { - printTag(Logger.STATS, new HashMap<>(), true, false); - } - if (isTimed) { - CompilerStats compilerStats = this.main.batchCompiler.stats; - compilerStats.startTime = this.main.startTime; // also include batch initialization times - compilerStats.endTime = System.currentTimeMillis(); // also include batch output times - logTiming(compilerStats); - } - if (this.main.globalProblemsCount > 0) { - logProblemsSummary(this.main.globalProblemsCount, this.main.globalErrorsCount, this.main.globalWarningsCount, - this.main.globalInfoCount, this.main.globalTasksCount); - } - if (this.main.exportedClassFilesCounter != 0 - && (this.main.showProgress || isTimed || this.main.verbose)) { - logNumberOfClassFilesGenerated(this.main.exportedClassFilesCounter); - } - if ((this.tagBits & Logger.XML) != 0) { - endTag(Logger.STATS); - } - } - - private void printTag(String name, HashMap params, boolean insertNewLine, boolean closeTag) { - if (this.log != null) { - ((GenericXMLWriter) this.log).printTag(name, params, true, insertNewLine, closeTag); - } - if (params != null) params.clear(); - } - - public void setEmacs() { - this.tagBits |= Logger.EMACS; - } - public void setLog(String logFileName) { - final Date date = new Date(); - final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.getDefault()); - try { - int index = logFileName.lastIndexOf('.'); - if (index != -1) { - if (logFileName.substring(index).equalsIgnoreCase(".xml")) { //$NON-NLS-1$ - this.log = new GenericXMLWriter(new OutputStreamWriter(new FileOutputStream(logFileName, false), Util.UTF_8), Util.LINE_SEPARATOR, true); - this.tagBits |= Logger.XML; - // insert time stamp as comment - this.log.println("");//$NON-NLS-1$//$NON-NLS-2$ - this.log.println(Logger.XML_DTD_DECLARATION); - HashMap parameters = new HashMap<>(); - parameters.put(Logger.COMPILER_NAME, this.main.bind("compiler.name")); //$NON-NLS-1$ - parameters.put(Logger.COMPILER_VERSION, this.main.bind("compiler.version")); //$NON-NLS-1$ - parameters.put(Logger.COMPILER_COPYRIGHT, this.main.bind("compiler.copyright")); //$NON-NLS-1$ - printTag(Logger.COMPILER, parameters, true, false); - } else { - this.log = new PrintWriter(new FileOutputStream(logFileName, false)); - this.log.println("# " + dateFormat.format(date));//$NON-NLS-1$ - } - } else { - this.log = new PrintWriter(new FileOutputStream(logFileName, false)); - this.log.println("# " + dateFormat.format(date));//$NON-NLS-1$ - } - } catch (FileNotFoundException e) { - throw new IllegalArgumentException(this.main.bind("configure.cannotOpenLog", logFileName), e); //$NON-NLS-1$ - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException(this.main.bind("configure.cannotOpenLogInvalidEncoding", logFileName), e); //$NON-NLS-1$ - } - } - private void startLoggingExtraProblems(int count) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.NUMBER_OF_PROBLEMS, Integer.valueOf(count)); - printTag(Logger.EXTRA_PROBLEMS, parameters, true, false); - } - - /** - * Used to start logging problems. - * Only use in xml mode. - */ - private void startLoggingProblems(int errors, int warnings, int infos) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.NUMBER_OF_PROBLEMS, Integer.valueOf(errors + warnings)); - parameters.put(Logger.NUMBER_OF_ERRORS, Integer.valueOf(errors)); - parameters.put(Logger.NUMBER_OF_WARNINGS, Integer.valueOf(warnings)); - parameters.put(Logger.NUMBER_OF_INFOS, Integer.valueOf(infos)); - printTag(Logger.PROBLEMS, parameters, true, false); - } - - public void startLoggingSource(CompilationResult compilationResult) { - if ((this.tagBits & Logger.XML) != 0) { - ICompilationUnit compilationUnit = compilationResult.compilationUnit; - HashMap parameters = new HashMap<>(); - if (compilationUnit != null) { - char[] fileName = compilationUnit.getFileName(); - File f = new File(new String(fileName)); - if (fileName != null) { - parameters.put(Logger.PATH, f.getAbsolutePath()); - } - char[][] packageName = compilationResult.packageName; - if (packageName != null) { - parameters.put( - Logger.PACKAGE, - new String(CharOperation.concatWith(packageName, File.separatorChar))); - } - CompilationUnit unit = (CompilationUnit) compilationUnit; - String destinationPath = unit.destinationPath; - if (destinationPath == null) { - destinationPath = this.main.destinationPath; - } - if (destinationPath != null && destinationPath != NONE) { - if (File.separatorChar == '/') { - parameters.put(Logger.OUTPUT, destinationPath); - } else { - parameters.put(Logger.OUTPUT, destinationPath.replace('/', File.separatorChar)); - } - } - } - printTag(Logger.SOURCE, parameters, true, false); - } - } - - public void startLoggingSources() { - if ((this.tagBits & Logger.XML) != 0) { - printTag(Logger.SOURCES, new HashMap<>(), true, false); - } - } - - public void startLoggingTasks(int tasks) { - if ((this.tagBits & Logger.XML) != 0) { - HashMap parameters = new HashMap<>(); - parameters.put(Logger.NUMBER_OF_TASKS, Integer.valueOf(tasks)); - printTag(Logger.TASKS, parameters, true, false); - } - } - } - - /** - * Resource bundle factory to share bundles for the same locale - */ - public static class ResourceBundleFactory { - private static HashMap Cache = new HashMap<>(); - public static synchronized ResourceBundle getBundle(Locale locale) { - ResourceBundle bundle = Cache.get(locale); - if (bundle == null) { - bundle = ResourceBundle.getBundle(Main.bundleName, locale); - Cache.put(locale, bundle); - } - return bundle; - } - } - - // used with -annotationpath to declare that annotations should be read from the classpath: - private static final String ANNOTATION_SOURCE_CLASSPATH = "CLASSPATH"; //$NON-NLS-1$ - - // javadoc analysis tuning - boolean enableJavadocOn; - - boolean warnJavadocOn; - boolean warnAllJavadocOn; - - public Compiler batchCompiler; - /* Bundle containing messages */ - public ResourceBundle bundle; - protected FileSystem.Classpath[] checkedClasspaths; - // For single module mode - protected IModule module; - private String moduleVersion; - // paths to external annotations: - protected List annotationPaths; - protected boolean annotationsFromClasspath; - - private List addonExports = Collections.EMPTY_LIST; - private List addonReads = Collections.EMPTY_LIST; - public Set rootModules = Collections.EMPTY_SET; - public Set limitedModules; - - public Locale compilerLocale; - public CompilerOptions compilerOptions; // read-only - public CompilationProgress progress; - public String destinationPath; - public String[] destinationPaths; - // destination path for compilation units that get no more specific - // one (through directory arguments or various classpath options); - // coding is: - // == null: unspecified, write class files close to their respective - // source files; - // == Main.NONE: absorbent element, do not output class files; - // else: use as the path of the directory into which class files must - // be written. - protected boolean enablePreview; - protected String releaseVersion; - private boolean didSpecifySource; - private boolean didSpecifyTarget; - public String[] encodings; - public int exportedClassFilesCounter; - public String[] filenames; - public String[] modNames; - public String[] classNames; - // overrides of destinationPath on a directory argument basis - public int globalErrorsCount; - public int globalProblemsCount; - public int globalTasksCount; - public int globalWarningsCount; - public int globalInfoCount; - - private File javaHomeCache; - - private boolean javaHomeChecked = false; - private boolean primaryNullAnnotationsSeen = false; - public long lineCount0; - - public String log; - - public Logger logger; - public int maxProblems; - public Map options; - protected long complianceLevel; - public char[][] ignoreOptionalProblemsFromFolders; - protected PrintWriter out; - public boolean proceed = true; - public boolean proceedOnError = false; - public boolean failOnWarning = false; - public boolean produceRefInfo = false; - public int currentRepetition, maxRepetition; - public boolean showProgress = false; - public long startTime; - public ArrayList pendingErrors; - public boolean systemExitWhenFinished = true; - - public static final int TIMING_DISABLED = 0; - public static final int TIMING_ENABLED = 1; - public static final int TIMING_DETAILED = 2; - - public int timing = TIMING_DISABLED; - public CompilerStats[] compilerStats; - public boolean verbose = false; - private String[] expandedCommandLine; - - private PrintWriter err; - - protected ArrayList extraProblems; - - public final static String bundleName = "org.eclipse.jdt.internal.compiler.batch.messages"; //$NON-NLS-1$ - // two uses: recognize 'none' in options; code the singleton none - // for the '-d none' option (wherever it may be found) - public static final int DEFAULT_SIZE_CLASSPATH = 4; - - public static final String NONE = "none"; //$NON-NLS-1$ - -/** - * @deprecated - use {@link BatchCompiler#compile(String, PrintWriter, PrintWriter, CompilationProgress)} instead - * e.g. BatchCompiler.compile(commandLine, new PrintWriter(System.out), new PrintWriter(System.err), null); - */ -public static boolean compile(String commandLine) { - return new Main(new PrintWriter(System.out), new PrintWriter(System.err), false /* systemExit */, null /* options */, null /* progress */).compile(tokenize(commandLine)); -} - -/** - * @deprecated - use {@link BatchCompiler#compile(String, PrintWriter, PrintWriter, CompilationProgress)} instead - * e.g. BatchCompiler.compile(commandLine, outWriter, errWriter, null); - */ -public static boolean compile(String commandLine, PrintWriter outWriter, PrintWriter errWriter) { - return new Main(outWriter, errWriter, false /* systemExit */, null /* options */, null /* progress */).compile(tokenize(commandLine)); -} - -/* - * Internal API for public API BatchCompiler#compile(String[], PrintWriter, PrintWriter, CompilationProgress) - */ -public static boolean compile(String[] commandLineArguments, PrintWriter outWriter, PrintWriter errWriter, CompilationProgress progress) { - return new Main(outWriter, errWriter, false /* systemExit */, null /* options */, progress).compile(commandLineArguments); -} -public static File[][] getLibrariesFiles(File[] files) { - FilenameFilter filter = new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return Util.archiveFormat(name) > -1; - } - }; - final int filesLength = files.length; - File[][] result = new File[filesLength][]; - for (int i = 0; i < filesLength; i++) { - File currentFile = files[i]; - if (currentFile.exists() && currentFile.isDirectory()) { - result[i] = currentFile.listFiles(filter); - } - } - return result; -} - -public static void main(String[] argv) { - new Main(new PrintWriter(System.out), new PrintWriter(System.err), true/*systemExit*/, null/*options*/, null/*progress*/).compile(argv); -} - -public static String[] tokenize(String commandLine) { - - int count = 0; - String[] arguments = new String[10]; - StringTokenizer tokenizer = new StringTokenizer(commandLine, " \"", true); //$NON-NLS-1$ - String token = Util.EMPTY_STRING; - boolean insideQuotes = false; - boolean startNewToken = true; - - // take care to quotes on the command line - // 'xxx "aaa bbb";ccc yyy' ---> {"xxx", "aaa bbb;ccc", "yyy" } - // 'xxx "aaa bbb;ccc" yyy' ---> {"xxx", "aaa bbb;ccc", "yyy" } - // 'xxx "aaa bbb";"ccc" yyy' ---> {"xxx", "aaa bbb;ccc", "yyy" } - // 'xxx/"aaa bbb";"ccc" yyy' ---> {"xxx/aaa bbb;ccc", "yyy" } - while (tokenizer.hasMoreTokens()) { - token = tokenizer.nextToken(); - - if (token.equals(" ")) { //$NON-NLS-1$ - if (insideQuotes) { - arguments[count - 1] += token; - startNewToken = false; - } else { - startNewToken = true; - } - } else if (token.equals("\"")) { //$NON-NLS-1$ - if (!insideQuotes && startNewToken) { - if (count == arguments.length) - System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count); - arguments[count++] = Util.EMPTY_STRING; - } - insideQuotes = !insideQuotes; - startNewToken = false; - } else { - if (insideQuotes) { - arguments[count - 1] += token; - } else { - if (token.length() > 0 && !startNewToken) { - arguments[count - 1] += token; - } else { - if (count == arguments.length) - System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count); - String trimmedToken = token.trim(); - if (trimmedToken.length() != 0) { - arguments[count++] = trimmedToken; - } - } - } - startNewToken = false; - } - } - System.arraycopy(arguments, 0, arguments = new String[count], 0, count); - return arguments; -} - -/** - * @deprecated - use {@link #Main(PrintWriter, PrintWriter, boolean, Map, CompilationProgress)} instead - * e.g. Main(outWriter, errWriter, systemExitWhenFinished, null, null) - */ -public Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished) { - this(outWriter, errWriter, systemExitWhenFinished, null /* options */, null /* progress */); -} - -/** - * @deprecated - use {@link #Main(PrintWriter, PrintWriter, boolean, Map, CompilationProgress)} instead - * e.g. Main(outWriter, errWriter, systemExitWhenFinished, customDefaultOptions, null) - */ -public Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished, Map customDefaultOptions) { - this(outWriter, errWriter, systemExitWhenFinished, customDefaultOptions, null /* progress */); -} - -public Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished, Map customDefaultOptions, CompilationProgress compilationProgress) { - this.initialize(outWriter, errWriter, systemExitWhenFinished, customDefaultOptions, compilationProgress); - this.relocalize(); -} - -public void addExtraProblems(CategorizedProblem problem) { - if (this.extraProblems == null) { - this.extraProblems = new ArrayList<>(); - } - this.extraProblems.add(problem); -} -protected void addNewEntry(ArrayList paths, String currentClasspathName, - ArrayList currentRuleSpecs, String customEncoding, - String destPath, boolean isSourceOnly, - boolean rejectDestinationPathOnJars) { - - int rulesSpecsSize = currentRuleSpecs.size(); - AccessRuleSet accessRuleSet = null; - if (rulesSpecsSize != 0) { - AccessRule[] accessRules = new AccessRule[currentRuleSpecs.size()]; - boolean rulesOK = true; - Iterator i = currentRuleSpecs.iterator(); - int j = 0; - while (i.hasNext()) { - String ruleSpec = i.next(); - char key = ruleSpec.charAt(0); - String pattern = ruleSpec.substring(1); - if (pattern.length() > 0) { - switch (key) { - case '+': - accessRules[j++] = new AccessRule(pattern - .toCharArray(), 0); - break; - case '~': - accessRules[j++] = new AccessRule(pattern - .toCharArray(), - IProblem.DiscouragedReference); - break; - case '-': - accessRules[j++] = new AccessRule(pattern - .toCharArray(), - IProblem.ForbiddenReference); - break; - case '?': - accessRules[j++] = new AccessRule(pattern - .toCharArray(), - IProblem.ForbiddenReference, true/*keep looking for accessible type*/); - break; - default: - rulesOK = false; - } - } else { - rulesOK = false; - } - } - if (rulesOK) { - accessRuleSet = new AccessRuleSet(accessRules, AccessRestriction.COMMAND_LINE, currentClasspathName); - } else { - if (currentClasspathName.length() != 0) { - // we go on anyway - addPendingErrors(this.bind("configure.incorrectClasspath", currentClasspathName));//$NON-NLS-1$ - } - return; - } - } - if (NONE.equals(destPath)) { - destPath = NONE; // keep == comparison valid - } - - if (rejectDestinationPathOnJars && destPath != null && - Util.archiveFormat(currentClasspathName) > -1) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedDestinationPathEntryFile", //$NON-NLS-1$ - currentClasspathName)); - } - FileSystem.Classpath currentClasspath = FileSystem.getClasspath( - currentClasspathName, - customEncoding, - isSourceOnly, - accessRuleSet, - destPath, - this.options, - this.releaseVersion); - if (currentClasspath != null) { - paths.add(currentClasspath); - } else if (currentClasspathName.length() != 0) { - // we go on anyway - addPendingErrors(this.bind("configure.incorrectClasspath", currentClasspathName));//$NON-NLS-1$ - } -} -void addPendingErrors(String message) { - if (this.pendingErrors == null) { - this.pendingErrors = new ArrayList<>(); - } - this.pendingErrors.add(message); -} -/* - * Lookup the message with the given ID in this catalog - */ -public String bind(String id) { - return bind(id, (String[]) null); -} -/* - * Lookup the message with the given ID in this catalog and bind its - * substitution locations with the given string. - */ -public String bind(String id, String binding) { - return bind(id, new String[] { binding }); -} - -/* - * Lookup the message with the given ID in this catalog and bind its - * substitution locations with the given strings. - */ -public String bind(String id, String binding1, String binding2) { - return bind(id, new String[] { binding1, binding2 }); -} - -/* - * Lookup the message with the given ID in this catalog and bind its - * substitution locations with the given string values. - */ -public String bind(String id, String[] arguments) { - if (id == null) - return "No message available"; //$NON-NLS-1$ - String message = null; - try { - message = this.bundle.getString(id); - } catch (MissingResourceException e) { - // If we got an exception looking for the message, fail gracefully by just returning - // the id we were looking for. In most cases this is semi-informative so is not too bad. - return "Missing message: " + id + " in: " + Main.bundleName; //$NON-NLS-2$ //$NON-NLS-1$ - } - return MessageFormat.format(message, (Object[]) arguments); -} -/** - * Return true if and only if the running VM supports the given minimal version. - * - *

    This only checks the major version, since the minor version is always 0 (at least for the useful cases).

    - *

    The given minimalSupportedVersion is one of the constants:

    - *
      - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_1
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_2
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_3
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_4
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_5
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_6
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_7
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_8
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK9
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK10
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK11
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK12
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK13
    • - *
    • org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK14
    • - * - *
    - * @param minimalSupportedVersion the given minimal version - * @return true if and only if the running VM supports the given minimal version, false otherwise - */ -private boolean checkVMVersion(long minimalSupportedVersion) { - // the format of this property is supposed to be xx.x where x are digits. - String classFileVersion = System.getProperty("java.class.version"); //$NON-NLS-1$ - if (classFileVersion == null) { - // by default we don't support a class file version we cannot recognize - return false; - } - int index = classFileVersion.indexOf('.'); - if (index == -1) { - // by default we don't support a class file version we cannot recognize - return false; - } - int majorVersion; - try { - majorVersion = Integer.parseInt(classFileVersion.substring(0, index)); - } catch (NumberFormatException e) { - // by default we don't support a class file version we cannot recognize - return false; - } - return ClassFileConstants.getComplianceLevelForJavaVersion(majorVersion) >=minimalSupportedVersion; -} -/* - * Low-level API performing the actual compilation - */ -public boolean compile(String[] argv) { - // decode command line arguments - try { - configure(argv); - if (this.progress != null) - this.progress.begin(this.filenames == null ? 0 : this.filenames.length * this.maxRepetition); - if (this.proceed) { -// if (this.verbose) { -// System.out.println(new CompilerOptions(this.options)); -// } - if (this.showProgress) this.logger.compiling(); - for (this.currentRepetition = 0; this.currentRepetition < this.maxRepetition; this.currentRepetition++) { - this.globalProblemsCount = 0; - this.globalErrorsCount = 0; - this.globalWarningsCount = 0; - this.globalInfoCount = 0; - this.globalTasksCount = 0; - this.exportedClassFilesCounter = 0; - - if (this.maxRepetition > 1) { - this.logger.flush(); - this.logger.logRepetition(this.currentRepetition, this.maxRepetition); - } - // request compilation - performCompilation(); - } - if (this.compilerStats != null) { - this.logger.logAverage(); - } - if (this.showProgress) this.logger.printNewLine(); - } - if (this.systemExitWhenFinished) { - this.logger.flush(); - this.logger.close(); - if (this.failOnWarning && this.globalWarningsCount > 0) { - System.exit(-1); - } - System.exit(this.globalErrorsCount > 0 ? -1 : 0); - } - } catch (Exception e) { // internal compiler failure - this.logger.logException(e); - if (this.systemExitWhenFinished) { - this.logger.flush(); - this.logger.close(); - System.exit(-1); - } - return false; - } finally { - this.logger.flush(); - this.logger.close(); - if (this.progress != null) - this.progress.done(); - } - if (this.progress == null || !this.progress.isCanceled()) { - if (this.failOnWarning && (this.globalWarningsCount > 0)) - return false; - if (this.globalErrorsCount == 0) - return true; - } - - return false; -} - -/* -Decode the command line arguments - */ -public void configure(String[] argv) { - - if ((argv == null) || (argv.length == 0)) { - printUsage(); - return; - } - - final int INSIDE_CLASSPATH_start = 1; - final int INSIDE_DESTINATION_PATH = 3; - final int INSIDE_TARGET = 4; - final int INSIDE_LOG = 5; - final int INSIDE_REPETITION = 6; - final int INSIDE_SOURCE = 7; - final int INSIDE_DEFAULT_ENCODING = 8; - final int INSIDE_BOOTCLASSPATH_start = 9; - final int INSIDE_MAX_PROBLEMS = 11; - final int INSIDE_EXT_DIRS = 12; - final int INSIDE_SOURCE_PATH_start = 13; - final int INSIDE_ENDORSED_DIRS = 15; - final int INSIDE_SOURCE_DIRECTORY_DESTINATION_PATH = 16; - final int INSIDE_PROCESSOR_PATH_start = 17; - final int INSIDE_PROCESSOR_start = 18; - final int INSIDE_S_start = 19; - final int INSIDE_CLASS_NAMES = 20; - final int INSIDE_WARNINGS_PROPERTIES = 21; - final int INSIDE_ANNOTATIONPATH_start = 22; - final int INSIDE_MODULEPATH_start = 23; - final int INSIDE_MODULESOURCEPATH_start = 24; - final int INSIDE_ADD_EXPORTS = 25; - final int INSIDE_ADD_READS = 26; - final int INSIDE_SYSTEM = 27; - final int INSIDE_PROCESSOR_MODULE_PATH_start = 28; - final int INSIDE_ADD_MODULES = 29; - final int INSIDE_RELEASE = 30; - final int INSIDE_LIMIT_MODULES = 31; - final int INSIDE_MODULE_VERSION = 32; - - final int DEFAULT = 0; - ArrayList bootclasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); - String sourcepathClasspathArg = null; - String modulepathArg = null; - String moduleSourcepathArg = null; - ArrayList sourcepathClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); - ArrayList classpaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); - ArrayList extdirsClasspaths = null; - ArrayList endorsedDirClasspaths = null; - this.annotationPaths = null; - this.annotationsFromClasspath = false; - - int index = -1; - int filesCount = 0; - int classCount = 0; - int argCount = argv.length; - int mode = DEFAULT; - this.maxRepetition = 0; - boolean printUsageRequired = false; - String usageSection = null; - boolean printVersionRequired = false; - - boolean didSpecifyDeprecation = false; - boolean didSpecifyCompliance = false; - boolean didSpecifyDisabledAnnotationProcessing = false; - - String customEncoding = null; - String customDestinationPath = null; - String currentSourceDirectory = null; - String currentArg = Util.EMPTY_STRING; - - Set specifiedEncodings = null; - - // expand the command line if necessary - boolean needExpansion = false; - loop: for (int i = 0; i < argCount; i++) { - if (argv[i].startsWith("@")) { //$NON-NLS-1$ - needExpansion = true; - break loop; - } - } - - String[] newCommandLineArgs = null; - if (needExpansion) { - newCommandLineArgs = new String[argCount]; - index = 0; - for (int i = 0; i < argCount; i++) { - String[] newArgs = null; - String arg = argv[i].trim(); - if (arg.startsWith("@")) { //$NON-NLS-1$ - try { - LineNumberReader reader = new LineNumberReader(new StringReader(new String(Util.getFileCharContent(new File(arg.substring(1)), null)))); - StringBuilder buffer = new StringBuilder(); - String line; - while((line = reader.readLine()) != null) { - line = line.trim(); - if (!line.startsWith("#")) { //$NON-NLS-1$ - buffer.append(line).append(" "); //$NON-NLS-1$ - } - } - newArgs = tokenize(buffer.toString()); - } catch(IOException e) { - throw new IllegalArgumentException( - this.bind("configure.invalidexpansionargumentname", arg)); //$NON-NLS-1$ - } - } - if (newArgs != null) { - int newCommandLineArgsLength = newCommandLineArgs.length; - int newArgsLength = newArgs.length; - System.arraycopy(newCommandLineArgs, 0, (newCommandLineArgs = new String[newCommandLineArgsLength + newArgsLength - 1]), 0, index); - System.arraycopy(newArgs, 0, newCommandLineArgs, index, newArgsLength); - index += newArgsLength; - } else { - newCommandLineArgs[index++] = arg; - } - } - index = -1; - } else { - newCommandLineArgs = argv; - for (int i = 0; i < argCount; i++) { - newCommandLineArgs[i] = newCommandLineArgs[i].trim(); - } - } - argCount = newCommandLineArgs.length; - this.expandedCommandLine = newCommandLineArgs; - while (++index < argCount) { - - if (customEncoding != null) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedCustomEncoding", currentArg, customEncoding)); //$NON-NLS-1$ - } - - currentArg = newCommandLineArgs[index]; - - switch(mode) { - case DEFAULT : - if (currentArg.startsWith("-nowarn")) { //$NON-NLS-1$ - switch (currentArg.length()) { - case 7: - disableAll(ProblemSeverities.Warning); - break; - case 8: - throw new IllegalArgumentException(this.bind( - "configure.invalidNowarnOption", currentArg)); //$NON-NLS-1$ - default: - int foldersStart = currentArg.indexOf('[') + 1; - int foldersEnd = currentArg.lastIndexOf(']'); - if (foldersStart <= 8 || foldersEnd == -1 || foldersStart > foldersEnd - || foldersEnd < currentArg.length() - 1) { - throw new IllegalArgumentException(this.bind( - "configure.invalidNowarnOption", currentArg)); //$NON-NLS-1$ - } - String folders = currentArg.substring(foldersStart, foldersEnd); - if (folders.length() > 0) { - char[][] currentFolders = decodeIgnoreOptionalProblemsFromFolders(folders); - if (this.ignoreOptionalProblemsFromFolders != null) { - int length = this.ignoreOptionalProblemsFromFolders.length + currentFolders.length; - char[][] tempFolders = new char[length][]; - System.arraycopy(this.ignoreOptionalProblemsFromFolders, 0, tempFolders, 0, this.ignoreOptionalProblemsFromFolders.length); - System.arraycopy(currentFolders, 0, tempFolders, this.ignoreOptionalProblemsFromFolders.length, currentFolders.length); - this.ignoreOptionalProblemsFromFolders = tempFolders; - } else { - this.ignoreOptionalProblemsFromFolders = currentFolders; - } - } else { - throw new IllegalArgumentException(this.bind( - "configure.invalidNowarnOption", currentArg)); //$NON-NLS-1$ - } - } - mode = DEFAULT; - continue; - } - if (currentArg.startsWith("[")) { //$NON-NLS-1$ - throw new IllegalArgumentException( - this.bind("configure.unexpectedBracket", //$NON-NLS-1$ - currentArg)); - } - - if (currentArg.endsWith("]")) { //$NON-NLS-1$ - // look for encoding specification - int encodingStart = currentArg.indexOf('[') + 1; - if (encodingStart <= 1) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedBracket", currentArg)); //$NON-NLS-1$ - } - int encodingEnd = currentArg.length() - 1; - if (encodingStart >= 1) { - if (encodingStart < encodingEnd) { - customEncoding = currentArg.substring(encodingStart, encodingEnd); - try { // ensure encoding is supported - new InputStreamReader(new ByteArrayInputStream(new byte[0]), customEncoding); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException( - this.bind("configure.unsupportedEncoding", customEncoding), e); //$NON-NLS-1$ - } - } - currentArg = currentArg.substring(0, encodingStart - 1); - } - } - - if (currentArg.endsWith(SuffixConstants.SUFFIX_STRING_java)) { - if (this.filenames == null) { - this.filenames = new String[argCount - index]; - this.encodings = new String[argCount - index]; - this.destinationPaths = new String[argCount - index]; - } else if (filesCount == this.filenames.length) { - int length = this.filenames.length; - System.arraycopy( - this.filenames, - 0, - (this.filenames = new String[length + argCount - index]), - 0, - length); - System.arraycopy( - this.encodings, - 0, - (this.encodings = new String[length + argCount - index]), - 0, - length); - System.arraycopy( - this.destinationPaths, - 0, - (this.destinationPaths = new String[length + argCount - index]), - 0, - length); - } - this.filenames[filesCount] = currentArg; - this.encodings[filesCount++] = customEncoding; - // destination path cannot be specified upon an individual file - customEncoding = null; - mode = DEFAULT; - continue; - } - if (currentArg.equals("-log")) { //$NON-NLS-1$ - if (this.log != null) - throw new IllegalArgumentException( - this.bind("configure.duplicateLog", currentArg)); //$NON-NLS-1$ - mode = INSIDE_LOG; - continue; - } - if (currentArg.equals("-repeat")) { //$NON-NLS-1$ - if (this.maxRepetition > 0) - throw new IllegalArgumentException( - this.bind("configure.duplicateRepeat", currentArg)); //$NON-NLS-1$ - mode = INSIDE_REPETITION; - continue; - } - if (currentArg.equals("-maxProblems")) { //$NON-NLS-1$ - if (this.maxProblems > 0) - throw new IllegalArgumentException( - this.bind("configure.duplicateMaxProblems", currentArg)); //$NON-NLS-1$ - mode = INSIDE_MAX_PROBLEMS; - continue; - } - if (currentArg.equals("--release")) { //$NON-NLS-1$ - mode = INSIDE_RELEASE; - continue; - } - if (currentArg.equals("-source")) { //$NON-NLS-1$ - mode = INSIDE_SOURCE; - continue; - } - if (currentArg.equals("-encoding")) { //$NON-NLS-1$ - mode = INSIDE_DEFAULT_ENCODING; - continue; - } - if (currentArg.startsWith("-")) { //$NON-NLS-1$ - String version = optionStringToVersion(currentArg.substring(1)); - if (version != null) { - if (didSpecifyCompliance) { - throw new IllegalArgumentException( - this.bind("configure.duplicateCompliance", currentArg));//$NON-NLS-1$ - } - didSpecifyCompliance = true; - this.options.put(CompilerOptions.OPTION_Compliance, version); - mode = DEFAULT; - continue; - } - } - if (currentArg.equals("-d")) { //$NON-NLS-1$ - if (this.destinationPath != null) { - StringBuilder errorMessage = new StringBuilder(); - errorMessage.append(currentArg); - if ((index + 1) < argCount) { - errorMessage.append(' '); - errorMessage.append(newCommandLineArgs[index + 1]); - } - throw new IllegalArgumentException( - this.bind("configure.duplicateOutputPath", errorMessage.toString())); //$NON-NLS-1$ - } - mode = INSIDE_DESTINATION_PATH; - continue; - } - if (currentArg.equals("-classpath") //$NON-NLS-1$ - || currentArg.equals("-cp")) { //$NON-NLS-1$ - mode = INSIDE_CLASSPATH_start; - continue; - } - if (currentArg.equals("-bootclasspath")) {//$NON-NLS-1$ - if (bootclasspaths.size() > 0) { - StringBuilder errorMessage = new StringBuilder(); - errorMessage.append(currentArg); - if ((index + 1) < argCount) { - errorMessage.append(' '); - errorMessage.append(newCommandLineArgs[index + 1]); - } - throw new IllegalArgumentException( - this.bind("configure.duplicateBootClasspath", errorMessage.toString())); //$NON-NLS-1$ - } - mode = INSIDE_BOOTCLASSPATH_start; - continue; - } - if (currentArg.equals("--enable-preview")) { //$NON-NLS-1$ - this.enablePreview = true; - mode = DEFAULT; - continue; - } - if (currentArg.equals("--system")) { //$NON-NLS-1$ - mode = INSIDE_SYSTEM; - continue; - } - if (currentArg.equals("--module-path") || currentArg.equals("-p")) { //$NON-NLS-1$ //$NON-NLS-2$ - mode = INSIDE_MODULEPATH_start; - continue; - } - if (currentArg.equals("--module-source-path")) { //$NON-NLS-1$ - if (sourcepathClasspathArg != null) { - throw new IllegalArgumentException(this.bind("configure.OneOfModuleOrSourcePath")); //$NON-NLS-1$ - } - mode = INSIDE_MODULESOURCEPATH_start; - continue; - } - if (currentArg.equals("--add-exports")) { //$NON-NLS-1$ - mode = INSIDE_ADD_EXPORTS; - continue; - } - if (currentArg.equals("--add-reads")) { //$NON-NLS-1$ - mode = INSIDE_ADD_READS; - continue; - } - if (currentArg.equals("--add-modules")) { //$NON-NLS-1$ - mode = INSIDE_ADD_MODULES; - continue; - } - if (currentArg.equals("--limit-modules")) { //$NON-NLS-1$ - mode = INSIDE_LIMIT_MODULES; - continue; - } - if (currentArg.equals("--module-version")) { //$NON-NLS-1$ - mode = INSIDE_MODULE_VERSION; - continue; - } - if (currentArg.equals("-sourcepath")) {//$NON-NLS-1$ - if (sourcepathClasspathArg != null) { - StringBuilder errorMessage = new StringBuilder(); - errorMessage.append(currentArg); - if ((index + 1) < argCount) { - errorMessage.append(' '); - errorMessage.append(newCommandLineArgs[index + 1]); - } - throw new IllegalArgumentException( - this.bind("configure.duplicateSourcepath", errorMessage.toString())); //$NON-NLS-1$ - } - if (moduleSourcepathArg != null) { - throw new IllegalArgumentException(this.bind("configure.OneOfModuleOrSourcePath")); //$NON-NLS-1$ - } - mode = INSIDE_SOURCE_PATH_start; - continue; - } - if (currentArg.equals("-extdirs")) {//$NON-NLS-1$ - if (extdirsClasspaths != null) { - StringBuilder errorMessage = new StringBuilder(); - errorMessage.append(currentArg); - if ((index + 1) < argCount) { - errorMessage.append(' '); - errorMessage.append(newCommandLineArgs[index + 1]); - } - throw new IllegalArgumentException( - this.bind("configure.duplicateExtDirs", errorMessage.toString())); //$NON-NLS-1$ - } - mode = INSIDE_EXT_DIRS; - continue; - } - if (currentArg.equals("-endorseddirs")) { //$NON-NLS-1$ - if (endorsedDirClasspaths != null) { - StringBuilder errorMessage = new StringBuilder(); - errorMessage.append(currentArg); - if ((index + 1) < argCount) { - errorMessage.append(' '); - errorMessage.append(newCommandLineArgs[index + 1]); - } - throw new IllegalArgumentException( - this.bind("configure.duplicateEndorsedDirs", errorMessage.toString())); //$NON-NLS-1$ - } - mode = INSIDE_ENDORSED_DIRS; - continue; - } - if (currentArg.equals("-progress")) { //$NON-NLS-1$ - mode = DEFAULT; - this.showProgress = true; - continue; - } - if (currentArg.startsWith("-proceedOnError")) { //$NON-NLS-1$ - mode = DEFAULT; - int length = currentArg.length(); - if (length > 15) { - if (currentArg.equals("-proceedOnError:Fatal")) { //$NON-NLS-1$ - this.options.put(CompilerOptions.OPTION_FatalOptionalError, CompilerOptions.ENABLED); - } else { - throw new IllegalArgumentException( - this.bind("configure.invalidWarningConfiguration", currentArg)); //$NON-NLS-1$ - } - } else { - this.options.put(CompilerOptions.OPTION_FatalOptionalError, CompilerOptions.DISABLED); - } - this.proceedOnError = true; - continue; - } - if (currentArg.equals("-failOnWarning")) { //$NON-NLS-1$ - mode = DEFAULT; - this.failOnWarning = true; - continue; - } - if (currentArg.equals("-time")) { //$NON-NLS-1$ - mode = DEFAULT; - this.timing = TIMING_ENABLED; - continue; - } - if (currentArg.equals("-time:detail")) { //$NON-NLS-1$ - mode = DEFAULT; - this.timing = TIMING_ENABLED|TIMING_DETAILED; - continue; - } - if (currentArg.equals("-version") //$NON-NLS-1$ - || currentArg.equals("-v")) { //$NON-NLS-1$ - this.logger.logVersion(true); - this.proceed = false; - return; - } - if (currentArg.equals("-showversion")) { //$NON-NLS-1$ - printVersionRequired = true; - mode = DEFAULT; - continue; - } - if ("-deprecation".equals(currentArg)) { //$NON-NLS-1$ - didSpecifyDeprecation = true; - this.options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING); - mode = DEFAULT; - continue; - } - if (currentArg.equals("-help") || currentArg.equals("-?")) { //$NON-NLS-1$ //$NON-NLS-2$ - printUsageRequired = true; - mode = DEFAULT; - continue; - } - if (currentArg.equals("-help:warn") || //$NON-NLS-1$ - currentArg.equals("-?:warn")) { //$NON-NLS-1$ - printUsageRequired = true; - usageSection = "misc.usage.warn"; //$NON-NLS-1$ - continue; - } - if (currentArg.equals("-noExit")) { //$NON-NLS-1$ - this.systemExitWhenFinished = false; - mode = DEFAULT; - continue; - } - if (currentArg.equals("-verbose")) { //$NON-NLS-1$ - this.verbose = true; - mode = DEFAULT; - continue; - } - if (currentArg.equals("-referenceInfo")) { //$NON-NLS-1$ - this.produceRefInfo = true; - mode = DEFAULT; - continue; - } - if (currentArg.equals("-inlineJSR")) { //$NON-NLS-1$ - mode = DEFAULT; - this.options.put( - CompilerOptions.OPTION_InlineJsr, - CompilerOptions.ENABLED); - continue; - } - if (currentArg.equals("-parameters")) { //$NON-NLS-1$ - mode = DEFAULT; - this.options.put( - CompilerOptions.OPTION_MethodParametersAttribute, - CompilerOptions.GENERATE); - continue; - } - if (currentArg.equals("-genericsignature")) { //$NON-NLS-1$ - mode = DEFAULT; - this.options.put( - CompilerOptions.OPTION_LambdaGenericSignature, - CompilerOptions.GENERATE); - continue; - } - if (currentArg.startsWith("-g")) { //$NON-NLS-1$ - mode = DEFAULT; - String debugOption = currentArg; - int length = currentArg.length(); - if (length == 2) { - this.options.put( - CompilerOptions.OPTION_LocalVariableAttribute, - CompilerOptions.GENERATE); - this.options.put( - CompilerOptions.OPTION_LineNumberAttribute, - CompilerOptions.GENERATE); - this.options.put( - CompilerOptions.OPTION_SourceFileAttribute, - CompilerOptions.GENERATE); - continue; - } - if (length > 3) { - this.options.put( - CompilerOptions.OPTION_LocalVariableAttribute, - CompilerOptions.DO_NOT_GENERATE); - this.options.put( - CompilerOptions.OPTION_LineNumberAttribute, - CompilerOptions.DO_NOT_GENERATE); - this.options.put( - CompilerOptions.OPTION_SourceFileAttribute, - CompilerOptions.DO_NOT_GENERATE); - if (length == 7 && debugOption.equals("-g:" + NONE)) //$NON-NLS-1$ - continue; - StringTokenizer tokenizer = - new StringTokenizer(debugOption.substring(3, debugOption.length()), ","); //$NON-NLS-1$ - while (tokenizer.hasMoreTokens()) { - String token = tokenizer.nextToken(); - if (token.equals("vars")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_LocalVariableAttribute, - CompilerOptions.GENERATE); - } else if (token.equals("lines")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_LineNumberAttribute, - CompilerOptions.GENERATE); - } else if (token.equals("source")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_SourceFileAttribute, - CompilerOptions.GENERATE); - } else { - throw new IllegalArgumentException( - this.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$ - } - } - continue; - } - throw new IllegalArgumentException( - this.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$ - } - if (currentArg.startsWith("-info")) { //$NON-NLS-1$ - mode = DEFAULT; - String infoOption = currentArg; - int length = currentArg.length(); - if (length == 10 && infoOption.equals("-info:" + NONE)) { //$NON-NLS-1$ - disableAll(ProblemSeverities.Info); - continue; - } - if (length <= 6) { - throw new IllegalArgumentException( - this.bind("configure.invalidInfoConfiguration", infoOption)); //$NON-NLS-1$ - } - int infoTokenStart; - boolean isEnabling; - switch (infoOption.charAt(6)) { - case '+' : - infoTokenStart = 7; - isEnabling = true; - break; - case '-' : - infoTokenStart = 7; - isEnabling = false; // specified warnings are disabled - break; - default: - disableAll(ProblemSeverities.Info); - infoTokenStart = 6; - isEnabling = true; - } - - StringTokenizer tokenizer = - new StringTokenizer(infoOption.substring(infoTokenStart, infoOption.length()), ","); //$NON-NLS-1$ - int tokenCounter = 0; - - while (tokenizer.hasMoreTokens()) { - String token = tokenizer.nextToken(); - tokenCounter++; - switch(token.charAt(0)) { - case '+' : - isEnabling = true; - token = token.substring(1); - break; - case '-' : - isEnabling = false; - token = token.substring(1); - } - handleInfoToken(token, isEnabling); - } - if (tokenCounter == 0) { - throw new IllegalArgumentException( - this.bind("configure.invalidInfoOption", currentArg)); //$NON-NLS-1$ - } - continue; - } - if (currentArg.startsWith("-warn")) { //$NON-NLS-1$ - mode = DEFAULT; - String warningOption = currentArg; - int length = currentArg.length(); - if (length == 10 && warningOption.equals("-warn:" + NONE)) { //$NON-NLS-1$ - disableAll(ProblemSeverities.Warning); - continue; - } - if (length <= 6) { - throw new IllegalArgumentException( - this.bind("configure.invalidWarningConfiguration", warningOption)); //$NON-NLS-1$ - } - int warnTokenStart; - boolean isEnabling; - switch (warningOption.charAt(6)) { - case '+' : - warnTokenStart = 7; - isEnabling = true; - break; - case '-' : - warnTokenStart = 7; - isEnabling = false; // specified warnings are disabled - break; - default: - disableAll(ProblemSeverities.Warning); - warnTokenStart = 6; - isEnabling = true; - } - - StringTokenizer tokenizer = - new StringTokenizer(warningOption.substring(warnTokenStart, warningOption.length()), ","); //$NON-NLS-1$ - int tokenCounter = 0; - - if (didSpecifyDeprecation) { // deprecation could have also been set through -deprecation option - this.options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING); - } - - while (tokenizer.hasMoreTokens()) { - String token = tokenizer.nextToken(); - tokenCounter++; - switch(token.charAt(0)) { - case '+' : - isEnabling = true; - token = token.substring(1); - break; - case '-' : - isEnabling = false; - token = token.substring(1); - } - handleWarningToken(token, isEnabling); - } - if (tokenCounter == 0) { - throw new IllegalArgumentException( - this.bind("configure.invalidWarningOption", currentArg)); //$NON-NLS-1$ - } - continue; - } - if (currentArg.startsWith("-err")) { //$NON-NLS-1$ - mode = DEFAULT; - String errorOption = currentArg; - int length = currentArg.length(); - if (length <= 5) { - throw new IllegalArgumentException( - this.bind("configure.invalidErrorConfiguration", errorOption)); //$NON-NLS-1$ - } - int errorTokenStart; - boolean isEnabling; - switch (errorOption.charAt(5)) { - case '+' : - errorTokenStart = 6; - isEnabling = true; - break; - case '-' : - errorTokenStart = 6; - isEnabling = false; // specified errors are disabled - break; - default: - disableAll(ProblemSeverities.Error); - errorTokenStart = 5; - isEnabling = true; - } - - StringTokenizer tokenizer = - new StringTokenizer(errorOption.substring(errorTokenStart, errorOption.length()), ","); //$NON-NLS-1$ - int tokenCounter = 0; - - while (tokenizer.hasMoreTokens()) { - String token = tokenizer.nextToken(); - tokenCounter++; - switch(token.charAt(0)) { - case '+' : - isEnabling = true; - token = token.substring(1); - break; - case '-' : - isEnabling = false; - token = token.substring(1); - break; - } - handleErrorToken(token, isEnabling); - } - if (tokenCounter == 0) { - throw new IllegalArgumentException( - this.bind("configure.invalidErrorOption", currentArg)); //$NON-NLS-1$ - } - continue; - } - if (currentArg.equals("-target")) { //$NON-NLS-1$ - mode = INSIDE_TARGET; - continue; - } - if (currentArg.equals("-preserveAllLocals")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_PreserveUnusedLocal, - CompilerOptions.PRESERVE); - mode = DEFAULT; - continue; - } - if (currentArg.equals("-enableJavadoc")) {//$NON-NLS-1$ - mode = DEFAULT; - this.enableJavadocOn = true; - continue; - } - if (currentArg.equals("-Xemacs")) { //$NON-NLS-1$ - mode = DEFAULT; - this.logger.setEmacs(); - continue; - } - // annotation processing - if (currentArg.startsWith("-A")) { //$NON-NLS-1$ - mode = DEFAULT; - continue; - } - if (currentArg.equals("-processorpath")) { //$NON-NLS-1$ - mode = INSIDE_PROCESSOR_PATH_start; - continue; - } - if (currentArg.equals("-processor")) { //$NON-NLS-1$ - mode = INSIDE_PROCESSOR_start; - continue; - } - if (currentArg.equals("--processor-module-path")) { //$NON-NLS-1$ - mode = INSIDE_PROCESSOR_MODULE_PATH_start; - continue; - } - if (currentArg.equals("-proc:only")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_GenerateClassFiles, - CompilerOptions.DISABLED); - mode = DEFAULT; - continue; - } - if (currentArg.equals("-proc:none")) { //$NON-NLS-1$ - didSpecifyDisabledAnnotationProcessing = true; - this.options.put( - CompilerOptions.OPTION_Process_Annotations, - CompilerOptions.DISABLED); - mode = DEFAULT; - continue; - } - if (currentArg.equals("-s")) { //$NON-NLS-1$ - mode = INSIDE_S_start; - continue; - } - if (currentArg.equals("-XprintProcessorInfo") //$NON-NLS-1$ - || currentArg.equals("-XprintRounds")) { //$NON-NLS-1$ - mode = DEFAULT; - continue; - } - // tolerated javac options - quietly filtered out - if (currentArg.startsWith("-X")) { //$NON-NLS-1$ - mode = DEFAULT; - continue; - } - if (currentArg.startsWith("-J")) { //$NON-NLS-1$ - mode = DEFAULT; - continue; - } - if (currentArg.equals("-O")) { //$NON-NLS-1$ - mode = DEFAULT; - continue; - } - if (currentArg.equals("-classNames")) { //$NON-NLS-1$ - mode = INSIDE_CLASS_NAMES; - continue; - } - if (currentArg.equals("-properties")) { //$NON-NLS-1$ - mode = INSIDE_WARNINGS_PROPERTIES; - continue; - } - if (currentArg.equals("-missingNullDefault")) { //$NON-NLS-1$ - this.options.put(CompilerOptions.OPTION_ReportMissingNonNullByDefaultAnnotation, CompilerOptions.WARNING); - continue; - } - if (currentArg.equals("-annotationpath")) { //$NON-NLS-1$ - mode = INSIDE_ANNOTATIONPATH_start; - continue; - } - break; - case INSIDE_TARGET : - if (this.didSpecifyTarget) { - throw new IllegalArgumentException( - this.bind("configure.duplicateTarget", currentArg));//$NON-NLS-1$ - } - if (this.releaseVersion != null) { - throw new IllegalArgumentException( - this.bind("configure.unsupportedWithRelease", "-target"));//$NON-NLS-1$ //$NON-NLS-2$ - } - this.didSpecifyTarget = true; - if (currentArg.equals("1.1")) { //$NON-NLS-1$ - this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1); - } else if (currentArg.equals("1.2")) { //$NON-NLS-1$ - this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2); - } else if (currentArg.equals("jsr14")) { //$NON-NLS-1$ - this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_JSR14); - } else if (currentArg.equals("cldc1.1")) { //$NON-NLS-1$ - this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_CLDC1_1); - this.options.put(CompilerOptions.OPTION_InlineJsr, CompilerOptions.ENABLED); - } else { - String version = optionStringToVersion(currentArg); - if (version != null) { - this.options.put(CompilerOptions.OPTION_TargetPlatform, version); - } else { - throw new IllegalArgumentException(this.bind("configure.targetJDK", currentArg)); //$NON-NLS-1$ - } - } - mode = DEFAULT; - continue; - case INSIDE_LOG : - this.log = currentArg; - mode = DEFAULT; - continue; - case INSIDE_REPETITION : - try { - this.maxRepetition = Integer.parseInt(currentArg); - if (this.maxRepetition <= 0) { - throw new IllegalArgumentException(this.bind("configure.repetition", currentArg)); //$NON-NLS-1$ - } - } catch (NumberFormatException e) { - throw new IllegalArgumentException(this.bind("configure.repetition", currentArg), e); //$NON-NLS-1$ - } - mode = DEFAULT; - continue; - case INSIDE_MAX_PROBLEMS : - try { - this.maxProblems = Integer.parseInt(currentArg); - if (this.maxProblems <= 0) { - throw new IllegalArgumentException(this.bind("configure.maxProblems", currentArg)); //$NON-NLS-1$ - } - this.options.put(CompilerOptions.OPTION_MaxProblemPerUnit, currentArg); - } catch (NumberFormatException e) { - throw new IllegalArgumentException(this.bind("configure.maxProblems", currentArg), e); //$NON-NLS-1$ - } - mode = DEFAULT; - continue; - case INSIDE_RELEASE: - // If release is < 9, the following are disallowed: - // bootclasspath, -Xbootclasspath, -Xbootclasspath/a:, -Xbootclasspath/p:, - // -endorseddirs, -Djava.endorsed.dirs, -extdirs, -Djava.ext.dirs - - // If release >= 9, the following are disallowed - // --system and --upgrade-module-path - - // -source and -target are disallowed for any --release - this.releaseVersion = currentArg; - long releaseToJDKLevel = CompilerOptions.releaseToJDKLevel(currentArg); - if (releaseToJDKLevel == 0) { - throw new IllegalArgumentException( - this.bind("configure.unsupportedReleaseVersion", currentArg)); //$NON-NLS-1$ - } - // Let's treat it as regular compliance mode - this.complianceLevel = releaseToJDKLevel; - String versionAsString = CompilerOptions.versionFromJdkLevel(releaseToJDKLevel); - this.options.put(CompilerOptions.OPTION_Compliance, versionAsString); - this.options.put(CompilerOptions.OPTION_Source, versionAsString); - this.options.put(CompilerOptions.OPTION_TargetPlatform, versionAsString); - mode = DEFAULT; - continue; - case INSIDE_SOURCE : - if (this.didSpecifySource) { - throw new IllegalArgumentException( - this.bind("configure.duplicateSource", currentArg));//$NON-NLS-1$ - } - if (this.releaseVersion != null) { - throw new IllegalArgumentException( - this.bind("configure.unsupportedWithRelease", "-source"));//$NON-NLS-1$ //$NON-NLS-2$ - } - this.didSpecifySource = true; - String version = optionStringToVersion(currentArg); - if (version != null) { - this.options.put(CompilerOptions.OPTION_Source, version); - } else { - throw new IllegalArgumentException(this.bind("configure.source", currentArg)); //$NON-NLS-1$ - } - mode = DEFAULT; - continue; - case INSIDE_DEFAULT_ENCODING : - if (specifiedEncodings != null) { - // check already defined encoding - if (!specifiedEncodings.contains(currentArg)) { - if (specifiedEncodings.size() > 1) { - this.logger.logWarning( - this.bind("configure.differentencodings", //$NON-NLS-1$ - currentArg, - getAllEncodings(specifiedEncodings))); - } else { - this.logger.logWarning( - this.bind("configure.differentencoding", //$NON-NLS-1$ - currentArg, - getAllEncodings(specifiedEncodings))); - } - } - } else { - specifiedEncodings = new HashSet<>(); - } - try { // ensure encoding is supported - new InputStreamReader(new ByteArrayInputStream(new byte[0]), currentArg); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException( - this.bind("configure.unsupportedEncoding", currentArg), e); //$NON-NLS-1$ - } - specifiedEncodings.add(currentArg); - this.options.put(CompilerOptions.OPTION_Encoding, currentArg); - mode = DEFAULT; - continue; - case INSIDE_DESTINATION_PATH : - setDestinationPath(currentArg.equals(NONE) ? NONE : currentArg); - mode = DEFAULT; - continue; - case INSIDE_SYSTEM: - mode = DEFAULT; - setJavaHome(currentArg); - continue; - case INSIDE_MODULEPATH_start: - mode = DEFAULT; - String[] modulepaths = new String[1]; - index += processPaths(newCommandLineArgs, index, currentArg, modulepaths); - modulepathArg = modulepaths[0]; - continue; - case INSIDE_MODULESOURCEPATH_start: - mode = DEFAULT; - String[] moduleSourcepaths = new String[1]; - index += processPaths(newCommandLineArgs, index, currentArg, moduleSourcepaths); - moduleSourcepathArg = moduleSourcepaths[0]; - continue; - case INSIDE_ADD_EXPORTS: - mode = DEFAULT; - // TODO: better to validate the option before processing it further? - if (this.addonExports == Collections.EMPTY_LIST) { - this.addonExports = new ArrayList<>(); - } - this.addonExports.add(currentArg); - continue; - case INSIDE_ADD_READS: - mode = DEFAULT; - if (this.addonReads == Collections.EMPTY_LIST) { - this.addonReads = new ArrayList<>(); - } - this.addonReads.add(currentArg); - continue; - case INSIDE_ADD_MODULES: - mode = DEFAULT; - if (this.rootModules == Collections.EMPTY_SET) { - this.rootModules = new HashSet<>(); - } - StringTokenizer tokenizer = new StringTokenizer(currentArg, ","); //$NON-NLS-1$ - while (tokenizer.hasMoreTokens()) { - this.rootModules.add(tokenizer.nextToken().trim()); - } - continue; - case INSIDE_LIMIT_MODULES: - mode = DEFAULT; - tokenizer = new StringTokenizer(currentArg, ","); //$NON-NLS-1$ - while (tokenizer.hasMoreTokens()) { - if (this.limitedModules == null) { - this.limitedModules = new HashSet<>(); - } - this.limitedModules.add(tokenizer.nextToken().trim()); - } - continue; - case INSIDE_MODULE_VERSION: - mode = DEFAULT; - this.moduleVersion = validateModuleVersion(currentArg); - continue; - case INSIDE_CLASSPATH_start: - mode = DEFAULT; - index += processPaths(newCommandLineArgs, index, currentArg, classpaths); - continue; - case INSIDE_BOOTCLASSPATH_start: - mode = DEFAULT; - index += processPaths(newCommandLineArgs, index, currentArg, bootclasspaths); - continue; - case INSIDE_SOURCE_PATH_start: - mode = DEFAULT; - String[] sourcePaths = new String[1]; - index += processPaths(newCommandLineArgs, index, currentArg, sourcePaths); - sourcepathClasspathArg = sourcePaths[0]; - continue; - case INSIDE_EXT_DIRS: - if (currentArg.indexOf("[-d") != -1) { //$NON-NLS-1$ - throw new IllegalArgumentException( - this.bind("configure.unexpectedDestinationPathEntry", //$NON-NLS-1$ - "-extdir")); //$NON-NLS-1$ - } - tokenizer = new StringTokenizer(currentArg, File.pathSeparator, false); - extdirsClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); - while (tokenizer.hasMoreTokens()) - extdirsClasspaths.add(tokenizer.nextToken()); - mode = DEFAULT; - continue; - case INSIDE_ENDORSED_DIRS: - if (currentArg.indexOf("[-d") != -1) { //$NON-NLS-1$ - throw new IllegalArgumentException( - this.bind("configure.unexpectedDestinationPathEntry", //$NON-NLS-1$ - "-endorseddirs")); //$NON-NLS-1$ - } tokenizer = new StringTokenizer(currentArg, File.pathSeparator, false); - endorsedDirClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); - while (tokenizer.hasMoreTokens()) - endorsedDirClasspaths.add(tokenizer.nextToken()); - mode = DEFAULT; - continue; - case INSIDE_SOURCE_DIRECTORY_DESTINATION_PATH: - if (currentArg.endsWith("]")) { //$NON-NLS-1$ - customDestinationPath = currentArg.substring(0, - currentArg.length() - 1); - } else { - throw new IllegalArgumentException( - this.bind("configure.incorrectDestinationPathEntry", //$NON-NLS-1$ - "[-d " + currentArg)); //$NON-NLS-1$ - } - break; - case INSIDE_PROCESSOR_PATH_start : - // nothing to do here. This is consumed again by the AnnotationProcessorManager - mode = DEFAULT; - continue; - case INSIDE_PROCESSOR_start : - // nothing to do here. This is consumed again by the AnnotationProcessorManager - mode = DEFAULT; - continue; - case INSIDE_PROCESSOR_MODULE_PATH_start : - mode = DEFAULT; - continue; - case INSIDE_S_start : - // nothing to do here. This is consumed again by the AnnotationProcessorManager - mode = DEFAULT; - continue; - case INSIDE_CLASS_NAMES : - tokenizer = new StringTokenizer(currentArg, ","); //$NON-NLS-1$ - if (this.classNames == null) { - this.classNames = new String[DEFAULT_SIZE_CLASSPATH]; - } - while (tokenizer.hasMoreTokens()) { - if (this.classNames.length == classCount) { - // resize - System.arraycopy( - this.classNames, - 0, - (this.classNames = new String[classCount * 2]), - 0, - classCount); - } - this.classNames[classCount++] = tokenizer.nextToken(); - } - mode = DEFAULT; - continue; - case INSIDE_WARNINGS_PROPERTIES : - initializeWarnings(currentArg); - mode = DEFAULT; - continue; - case INSIDE_ANNOTATIONPATH_start: - mode = DEFAULT; - if (currentArg.isEmpty() || currentArg.charAt(0) == '-') - throw new IllegalArgumentException(this.bind("configure.missingAnnotationPath", currentArg)); //$NON-NLS-1$ - if (ANNOTATION_SOURCE_CLASSPATH.equals(currentArg)) { - this.annotationsFromClasspath = true; - } else { - if (this.annotationPaths == null) - this.annotationPaths = new ArrayList<>(); - StringTokenizer tokens = new StringTokenizer(currentArg, File.pathSeparator); - while (tokens.hasMoreTokens()) - this.annotationPaths.add(tokens.nextToken()); - } - continue; - } - - // default is input directory, if no custom destination path exists - if (customDestinationPath == null) { - if (File.separatorChar != '/') { - currentArg = currentArg.replace('/', File.separatorChar); - } - if (currentArg.endsWith("[-d")) { //$NON-NLS-1$ - currentSourceDirectory = currentArg.substring(0, - currentArg.length() - 3); - mode = INSIDE_SOURCE_DIRECTORY_DESTINATION_PATH; - continue; - } - currentSourceDirectory = currentArg; - } - File dir = new File(currentSourceDirectory); - if (!dir.isDirectory()) { - throw new IllegalArgumentException( - this.bind("configure.unrecognizedOption", currentSourceDirectory)); //$NON-NLS-1$ - } - String[] result = FileFinder.find(dir, SuffixConstants.SUFFIX_STRING_java); - if (NONE.equals(customDestinationPath)) { - customDestinationPath = NONE; // ensure == comparison - } - if (this.filenames != null) { - // some source files were specified explicitly - int length = result.length; - System.arraycopy( - this.filenames, - 0, - (this.filenames = new String[length + filesCount]), - 0, - filesCount); - System.arraycopy( - this.encodings, - 0, - (this.encodings = new String[length + filesCount]), - 0, - filesCount); - System.arraycopy( - this.destinationPaths, - 0, - (this.destinationPaths = new String[length + filesCount]), - 0, - filesCount); - System.arraycopy(result, 0, this.filenames, filesCount, length); - for (int i = 0; i < length; i++) { - this.encodings[filesCount + i] = customEncoding; - this.destinationPaths[filesCount + i] = customDestinationPath; - } - filesCount += length; - customEncoding = null; - customDestinationPath = null; - currentSourceDirectory = null; - } else { - this.filenames = result; - filesCount = this.filenames.length; - this.encodings = new String[filesCount]; - this.destinationPaths = new String[filesCount]; - for (int i = 0; i < filesCount; i++) { - this.encodings[i] = customEncoding; - this.destinationPaths[i] = customDestinationPath; - } - customEncoding = null; - customDestinationPath = null; - currentSourceDirectory = null; - } - mode = DEFAULT; - continue; - } - if (this.enablePreview) { - this.options.put( - CompilerOptions.OPTION_EnablePreviews, - CompilerOptions.ENABLED); - } - - // set DocCommentSupport, with appropriate side effects on defaults if - // javadoc is not enabled - if (this.enableJavadocOn) { - this.options.put( - CompilerOptions.OPTION_DocCommentSupport, - CompilerOptions.ENABLED); - } else if (this.warnJavadocOn || this.warnAllJavadocOn) { - this.options.put( - CompilerOptions.OPTION_DocCommentSupport, - CompilerOptions.ENABLED); - // override defaults: references that are embedded in javadoc are ignored - // from the perspective of parameters and thrown exceptions usage - this.options.put( - CompilerOptions.OPTION_ReportUnusedParameterIncludeDocCommentReference, - CompilerOptions.DISABLED); - this.options.put( - CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionIncludeDocCommentReference, - CompilerOptions.DISABLED); - } - // configure warnings for javadoc contents - if (this.warnJavadocOn) { - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTags, - CompilerOptions.ENABLED); - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTagsDeprecatedRef, - CompilerOptions.ENABLED); - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTagsNotVisibleRef, - CompilerOptions.ENABLED); - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocTagsVisibility, - CompilerOptions.PRIVATE); - } - if (printUsageRequired || (filesCount == 0 && classCount == 0)) { - if (usageSection == null) { - printUsage(); // default - } else { - printUsage(usageSection); - } - this.proceed = false; - return; - } - - if (this.log != null) { - this.logger.setLog(this.log); - } else { - this.showProgress = false; - } - this.logger.logVersion(printVersionRequired); - - validateOptions(didSpecifyCompliance); - - // Enable annotation processing by default in batch mode when compliance is at least 1.6 - // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=185768 - if (!didSpecifyDisabledAnnotationProcessing - && CompilerOptions.versionToJdkLevel(this.options.get(CompilerOptions.OPTION_Compliance)) >= ClassFileConstants.JDK1_6) { - this.options.put(CompilerOptions.OPTION_Process_Annotations, CompilerOptions.ENABLED); - } - - this.logger.logCommandLineArguments(newCommandLineArgs); - this.logger.logOptions(this.options); - - if (this.maxRepetition == 0) { - this.maxRepetition = 1; - } - if (this.maxRepetition >= 3 && (this.timing & TIMING_ENABLED) != 0) { - this.compilerStats = new CompilerStats[this.maxRepetition]; - } - - if (filesCount != 0) { - System.arraycopy( - this.filenames, - 0, - (this.filenames = new String[filesCount]), - 0, - filesCount); - - this.modNames = new String[filesCount]; - } - - if (classCount != 0) { - System.arraycopy( - this.classNames, - 0, - (this.classNames = new String[classCount]), - 0, - classCount); - } - - if (moduleSourcepathArg == null) { - handleSingleModuleCompilation(); - } - - setPaths(bootclasspaths, - sourcepathClasspathArg, - sourcepathClasspaths, - classpaths, - modulepathArg, - moduleSourcepathArg, - extdirsClasspaths, - endorsedDirClasspaths, - customEncoding); - - if (specifiedEncodings != null && specifiedEncodings.size() > 1) { - this.logger.logWarning(this.bind("configure.multipleencodings", //$NON-NLS-1$ - this.options.get(CompilerOptions.OPTION_Encoding), - getAllEncodings(specifiedEncodings))); - } - if (this.pendingErrors != null) { - for (Iterator iterator = this.pendingErrors.iterator(); iterator.hasNext(); ) { - String message = iterator.next(); - this.logger.logPendingError(message); - } - this.pendingErrors = null; - } -} -/** Translates any supported standard version starting at 1.3 up-to latest into the corresponding constant from CompilerOptions */ -private String optionStringToVersion(String currentArg) { - switch (currentArg) { - case "1.3": return CompilerOptions.VERSION_1_3; //$NON-NLS-1$ - case "1.4": return CompilerOptions.VERSION_1_4; //$NON-NLS-1$ - case "1.5": //$NON-NLS-1$ - case "5": //$NON-NLS-1$ - case "5.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_1_5; - case "1.6": //$NON-NLS-1$ - case "6": //$NON-NLS-1$ - case "6.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_1_6; - case "1.7": //$NON-NLS-1$ - case "7": //$NON-NLS-1$ - case "7.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_1_7; - case "1.8": //$NON-NLS-1$ - case "8": //$NON-NLS-1$ - case "8.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_1_8; - case "1.9": //$NON-NLS-1$ - case "9": //$NON-NLS-1$ - case "9.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_9; - case "10": //$NON-NLS-1$ - case "10.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_10; - case "11": //$NON-NLS-1$ - case "11.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_11; - case "12": //$NON-NLS-1$ - case "12.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_12; - case "13": //$NON-NLS-1$ - case "13.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_13; - case "14": //$NON-NLS-1$ - case "14.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_14; - case "15": //$NON-NLS-1$ - case "15.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_15; - case "16": //$NON-NLS-1$ - case "16.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_16; - case "17": //$NON-NLS-1$ - case "17.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_17; - case "18": //$NON-NLS-1$ - case "18.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_18; - case "19": //$NON-NLS-1$ - case "19.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_19; - case "20": //$NON-NLS-1$ - case "20.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_20; - case "21": //$NON-NLS-1$ - case "21.0": //$NON-NLS-1$ - return CompilerOptions.VERSION_21; - default: - return null; - } -} -private String validateModuleVersion(String versionString) { - try { - Class versionClass = Class.forName("java.lang.module.ModuleDescriptor$Version"); //$NON-NLS-1$ - Method method = versionClass.getMethod("parse", String.class); //$NON-NLS-1$ - try { - method.invoke(null, versionString); - } catch (InvocationTargetException e) { - if (e.getCause() instanceof IllegalArgumentException) - throw (IllegalArgumentException) e.getCause(); - } - } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException e) { - this.logger.logWarning(this.bind("configure.no.ModuleDescriptorVersionparse")); //$NON-NLS-1$ - } - return versionString; -} - -private Parser getNewParser() { - return new Parser(new ProblemReporter(getHandlingPolicy(), - new CompilerOptions(this.options), getProblemFactory()), false); -} -private IModule extractModuleDesc(String fileName) { - IModule mod = null; - if (fileName.toLowerCase().endsWith(IModule.MODULE_INFO_JAVA)) { - // this.options may not be completely populated yet, and definitely not - // validated. Make sure the source level is set for the parser - Map opts = new HashMap<>(this.options); - opts.put(CompilerOptions.OPTION_Source, this.options.get(CompilerOptions.OPTION_Compliance)); - Parser parser = new Parser(new ProblemReporter(getHandlingPolicy(), - new CompilerOptions(opts), getProblemFactory()), false); - - ICompilationUnit cu = new CompilationUnit(null, fileName, null); - CompilationResult compilationResult = new CompilationResult(cu, 0, 1, 10); - CompilationUnitDeclaration unit = parser.parse(cu, compilationResult); - if (unit.isModuleInfo() && unit.moduleDeclaration != null) { - mod = new BasicModule(unit.moduleDeclaration, null); - } - } else if (fileName.toLowerCase().endsWith(IModule.MODULE_INFO_CLASS)) { - try { - ClassFileReader reader = ClassFileReader.read(fileName); // Check the absolute path? - mod = reader.getModuleDeclaration(); - } catch (ClassFormatException | IOException e) { - e.printStackTrace(); - throw new IllegalArgumentException( - this.bind("configure.invalidModuleDescriptor", fileName)); //$NON-NLS-1$ - } - } - return mod; -} - -private static char[][] decodeIgnoreOptionalProblemsFromFolders(String folders) { - StringTokenizer tokenizer = new StringTokenizer(folders, File.pathSeparator); - char[][] result = new char[2 * tokenizer.countTokens()][]; - int count = 0; - while (tokenizer.hasMoreTokens()) { - String fileName = tokenizer.nextToken(); - // relative folder names are created relative to the current user dir - File file = new File(fileName); - if (file.exists()) { - String absolutePath = file.getAbsolutePath(); - result[count++] = absolutePath.toCharArray(); - // if the file exists, we should try to use its canonical path - try { - String canonicalPath = file.getCanonicalPath(); - if (!absolutePath.equals(canonicalPath)) { - result[count++] = canonicalPath.toCharArray(); - } - } catch (IOException e) { - // ignore - } - } else { - // if the file does not exist, use the name that was specified - result[count++] = fileName.toCharArray(); - } - } - if (count < result.length) { - char[][] shortened = new char[count][]; - System.arraycopy(result, 0, shortened, 0, count); - result = shortened; - } - return result; -} - -private static String getAllEncodings(Set encodings) { - int size = encodings.size(); - String[] allEncodings = new String[size]; - encodings.toArray(allEncodings); - Arrays.sort(allEncodings); - StringBuilder buffer = new StringBuilder(); - for (int i = 0; i < size; i++) { - if (i > 0) { - buffer.append(", "); //$NON-NLS-1$ - } - buffer.append(allEncodings[i]); - } - return String.valueOf(buffer); -} -@SuppressWarnings("rawtypes") -private void initializeWarnings(String propertiesFile) { - File file = new File(propertiesFile); - if (!file.exists()) { - throw new IllegalArgumentException(this.bind("configure.missingwarningspropertiesfile", propertiesFile)); //$NON-NLS-1$ - } - Properties properties = null; - try (BufferedInputStream stream = new BufferedInputStream(new FileInputStream(propertiesFile))) { - properties = new Properties(); - properties.load(stream); - } catch(IOException e) { - e.printStackTrace(); - throw new IllegalArgumentException(this.bind("configure.ioexceptionwarningspropertiesfile", propertiesFile)); //$NON-NLS-1$ - } - for(Iterator iterator = properties.entrySet().iterator(); iterator.hasNext(); ) { - Map.Entry entry = (Map.Entry) iterator.next(); - final String key = entry.getKey().toString(); - if (key.startsWith("org.eclipse.jdt.core.compiler.")) { //$NON-NLS-1$ - this.options.put(key, entry.getValue().toString()); - } - } - // when using a properties file mimic relevant defaults from JavaCorePreferenceInitializer: - if (!properties.containsKey(CompilerOptions.OPTION_LocalVariableAttribute)) { - this.options.put(CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); - } - if (!properties.containsKey(CompilerOptions.OPTION_PreserveUnusedLocal)) { - this.options.put(CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.PRESERVE); - } - if (!properties.containsKey(CompilerOptions.OPTION_DocCommentSupport)) { - this.options.put(CompilerOptions.OPTION_DocCommentSupport, CompilerOptions.ENABLED); - } - if (!properties.containsKey(CompilerOptions.OPTION_ReportForbiddenReference)) { - this.options.put(CompilerOptions.OPTION_ReportForbiddenReference, CompilerOptions.ERROR); - } -} -protected void enableAll(int severity) { - String newValue = null; - switch(severity) { - case ProblemSeverities.Error : - newValue = CompilerOptions.ERROR; - break; - case ProblemSeverities.Warning : - newValue = CompilerOptions.WARNING; - break; - } - Map.Entry[] entries = this.options.entrySet().toArray(new Map.Entry[this.options.size()]); - for (int i = 0, max = entries.length; i < max; i++) { - Map.Entry entry = entries[i]; - if (entry.getValue().equals(CompilerOptions.IGNORE)) { - this.options.put(entry.getKey(), newValue); - } - } - this.options.put(CompilerOptions.OPTION_TaskTags, Util.EMPTY_STRING); - if (newValue != null) { - this.options.remove(newValue); - } -} -protected void disableAll(int severity) { - String checkedValue = null; - switch(severity) { - case ProblemSeverities.Error : - checkedValue = CompilerOptions.ERROR; - break; - case ProblemSeverities.Warning : - checkedValue = CompilerOptions.WARNING; - break; - case ProblemSeverities.Info : - checkedValue = CompilerOptions.INFO; - break; - } - Set> entrySet = this.options.entrySet(); - for (Entry entry : entrySet) { - if (entry.getValue().equals(checkedValue)) { - this.options.put(entry.getKey(), CompilerOptions.IGNORE); - } - } - if (checkedValue != null) { - this.options.put(checkedValue, CompilerOptions.IGNORE); - } - if (severity == ProblemSeverities.Warning) { - disableAll(ProblemSeverities.Info); - } -} -public String extractDestinationPathFromSourceFile(CompilationResult result) { - ICompilationUnit compilationUnit = result.compilationUnit; - if (compilationUnit != null) { - char[] fileName = compilationUnit.getFileName(); - int lastIndex = CharOperation.lastIndexOf(java.io.File.separatorChar, fileName); - if (lastIndex != -1) { - final String outputPathName = new String(fileName, 0, lastIndex); - final File output = new File(outputPathName); - if (output.exists() && output.isDirectory()) { - return outputPathName; - } - } - } - return System.getProperty("user.dir"); //$NON-NLS-1$ -} -/* - * Answer the component to which will be handed back compilation results from the compiler - */ -public ICompilerRequestor getBatchRequestor() { - return new BatchCompilerRequestor(this); -} -/* - * Build the set of compilation source units - */ -public CompilationUnit[] getCompilationUnits() { - int fileCount = this.filenames.length; - CompilationUnit[] units = new CompilationUnit[fileCount]; - HashtableOfObject knownFileNames = new HashtableOfObject(fileCount); - - String defaultEncoding = this.options.get(CompilerOptions.OPTION_Encoding); - if (Util.EMPTY_STRING.equals(defaultEncoding)) - defaultEncoding = null; - // sort index by file names so we have a consistent order of compiling / handling them - // this is important as the order can influence the way for example lamda numbers are generated - int[] orderedIndex = IntStream.range(0, fileCount).boxed().sorted((i1, i2) -> { - return this.filenames[i1].compareTo(this.filenames[i2]); - }).mapToInt(i -> i).toArray(); - for (int round = 0; round < 2; round++) { - for (int i : orderedIndex) { - char[] charName = this.filenames[i].toCharArray(); - boolean isModuleInfo = CharOperation.endsWith(charName, TypeConstants.MODULE_INFO_FILE_NAME); - if (isModuleInfo == (round==0)) { // 1st round: modules, 2nd round others (to ensure populating pathToModCU well in time) - if (knownFileNames.get(charName) != null) - throw new IllegalArgumentException(this.bind("unit.more", this.filenames[i])); //$NON-NLS-1$ - knownFileNames.put(charName, charName); - File file = new File(this.filenames[i]); - if (!file.exists()) - throw new IllegalArgumentException(this.bind("unit.missing", this.filenames[i])); //$NON-NLS-1$ - String encoding = this.encodings[i]; - if (encoding == null) - encoding = defaultEncoding; - String fileName; - try { - fileName = file.getCanonicalPath(); - } catch (IOException e) { - // if we got exception during canonicalization, fall back to the name that was specified - fileName = this.filenames[i]; - } - Function annotationPathProvider = null; - if (this.annotationsFromClasspath) { - annotationPathProvider = (String qualifiedTypeName) -> { - for (Classpath classpathEntry : this.checkedClasspaths) { - if (classpathEntry.hasAnnotationFileFor(qualifiedTypeName.replace('.', '/'))) - return classpathEntry.getPath(); - } - return null; - }; - } else if (this.annotationPaths != null) { - annotationPathProvider = (String qualifiedTypeName) -> { - String eeaFileName = '/'+qualifiedTypeName.replace('.', '/')+ExternalAnnotationProvider.ANNOTATION_FILE_SUFFIX; - for (String annotationPath : this.annotationPaths) { - if (new File(annotationPath+eeaFileName).exists()) - return annotationPath; - } - return null; - }; - } - units[i] = new CompilationUnit(null, fileName, encoding, this.destinationPaths[i], - shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, fileName.toCharArray()), - this.modNames[i], annotationPathProvider); - } - } - } - return units; -} - -/* - * Low-level API performing the actual compilation - */ -public IErrorHandlingPolicy getHandlingPolicy() { - - // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match) - return new IErrorHandlingPolicy() { - @Override - public boolean proceedOnErrors() { - return Main.this.proceedOnError; // stop if there are some errors - } - @Override - public boolean stopOnFirstError() { - return false; - } - @Override - public boolean ignoreAllErrors() { - return false; - } - }; -} -private void setJavaHome(String javaHome) { - File release = new File(javaHome, "release"); //$NON-NLS-1$ - Properties prop = new Properties(); - try (FileReader reader = new FileReader(release)) { - prop.load(reader); - String ver = prop.getProperty("JAVA_VERSION"); //$NON-NLS-1$ - if (ver != null) - ver = ver.replace("\"", ""); //$NON-NLS-1$//$NON-NLS-2$ - this.javaHomeCache = new File(javaHome); - this.javaHomeChecked = true; - } catch (IOException e) { - throw new IllegalArgumentException(this.bind("configure.invalidSystem", javaHome)); //$NON-NLS-1$ - } -} -/* - * External API - */ -public File getJavaHome() { - if (!this.javaHomeChecked) { - this.javaHomeChecked = true; - this.javaHomeCache = Util.getJavaHome(); - } - return this.javaHomeCache; -} - -public FileSystem getLibraryAccess() { - FileSystem nameEnvironment = new FileSystem(this.checkedClasspaths, this.filenames, - this.annotationsFromClasspath && CompilerOptions.ENABLED.equals(this.options.get(CompilerOptions.OPTION_AnnotationBasedNullAnalysis)), - this.limitedModules); - nameEnvironment.module = this.module; - processAddonModuleOptions(nameEnvironment); - return nameEnvironment; -} - -/* - * Low-level API performing the actual compilation - */ -public IProblemFactory getProblemFactory() { - return new DefaultProblemFactory(this.compilerLocale); -} - -/* - * External API - */ -protected ArrayList handleBootclasspath(ArrayList bootclasspaths, String customEncoding) { - final int bootclasspathsSize; - ArrayList result = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); - if ((bootclasspaths != null) - && ((bootclasspathsSize = bootclasspaths.size()) != 0)) { - result = new ArrayList<>(bootclasspathsSize); - for (String path : bootclasspaths) { - processPathEntries(DEFAULT_SIZE_CLASSPATH, result, path, customEncoding, false, true); - } - } else { - try { - Util.collectVMBootclasspath(result, this.javaHomeCache); - } catch(IllegalStateException e) { - throw new IllegalArgumentException(this.bind("configure.invalidSystem", this.javaHomeCache.toString())); //$NON-NLS-1$ - } - } - return result; -} -private void processAddonModuleOptions(FileSystem env) { - Map exports = new HashMap<>(); - for (String option : this.addonExports) { - AddExport addExport = ModuleFinder.extractAddonExport(option); - if (addExport != null) { - String modName = addExport.sourceModuleName; - for (Classpath classpath : this.checkedClasspaths) { - if (classpath.forbidsExportFrom(modName)) { - throw new IllegalArgumentException(this.bind("configure.illegalExportFromSystemModule", modName)); //$NON-NLS-1$ - } - } - IPackageExport export = addExport.export; - IPackageExport[] existing = exports.get(modName); - if (existing == null) { - existing = new IPackageExport[1]; - existing[0] = export; - exports.put(modName, existing); - } else { - for (IPackageExport iPackageExport : existing) { - if (CharOperation.equals(iPackageExport.name(), export.name())) { - throw new IllegalArgumentException(this.bind("configure.duplicateExport")); //$NON-NLS-1$ - } - } - IPackageExport[] updated = new IPackageExport[existing.length + 1]; - System.arraycopy(existing, 0, updated, 0, existing.length); - updated[existing.length] = export; - exports.put(modName, updated); - } - env.addModuleUpdate(modName, m -> m.addExports(export.name(), export.targets()), UpdateKind.PACKAGE); - } else { - throw new IllegalArgumentException(this.bind("configure.invalidModuleOption", "--add-exports " + option)); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - for (String option : this.addonReads) { - String[] result = ModuleFinder.extractAddonRead(option); - if (result != null && result.length == 2) { - env.addModuleUpdate(result[0], m -> m.addReads(result[1].toCharArray()), UpdateKind.MODULE); - } else { - throw new IllegalArgumentException(this.bind("configure.invalidModuleOption", "--add-reads " + option)); //$NON-NLS-1$ //$NON-NLS-2$ - } - } -} -protected ArrayList handleModulepath(String arg) { - ArrayList modulePaths = processModulePathEntries(arg); - ArrayList result = new ArrayList<>(); - if ((modulePaths != null && modulePaths.size() > 0)) { - for (String path : modulePaths) { - File file = new File(path); - if (file.isDirectory()) { - result.addAll( - ModuleFinder.findModules(file, null, getNewParser(), this.options, true, this.releaseVersion)); - } else { - Classpath modulePath = ModuleFinder.findModule(file, null, getNewParser(), this.options, true, this.releaseVersion); - if (modulePath != null) - result.add(modulePath); - } - } - } - // TODO: What about chained jars from MANIFEST.MF? Check with spec - return result; -} -protected ArrayList handleModuleSourcepath(String arg) { - ArrayList modulePaths = processModulePathEntries(arg); - ArrayList result = new ArrayList<>(); - if ((modulePaths != null) - && (modulePaths.size() != 0)) { - if (this.destinationPath == null) { - addPendingErrors(this.bind("configure.missingDestinationPath"));//$NON-NLS-1$ - } - String[] paths = new String[modulePaths.size()]; - modulePaths.toArray(paths); - for (int i = 0; i < paths.length; i++) { - File dir = new File(paths[i]); - if (dir.isDirectory()) { - // 1. Create FileSystem.Classpath for each module - // 2. Iterator each module in case of directory for source files and add to this.fileNames - - List modules = ModuleFinder.findModules(dir, this.destinationPath, getNewParser(), this.options, false, this.releaseVersion); - for (Classpath classpath : modules) { - result.add(classpath); - Path modLocation = Paths.get(classpath.getPath()).toAbsolutePath(); - String destPath = classpath.getDestinationPath(); - IModule mod = classpath.getModule(); - String moduleName = mod == null ? null : new String(mod.name()); - for(int j = 0; j < this.filenames.length; j++) { - Path filePath; - try { - // Get canonical path just as the classpath location is stored with the same. - // To avoid mismatch of /USER_JAY and /USE~1 in windows systems. - filePath = new File(this.filenames[j]).getCanonicalFile().toPath(); - if (filePath.startsWith(modLocation)) { - this.modNames[j] = moduleName; - this.destinationPaths[j] = destPath; - } - } catch (IOException e) { - // Files doesn't exist and perhaps doesn't belong in a module, move on to other files - // Use empty module name to distinguish from missing module case - this.modNames[j] = ""; //$NON-NLS-1$ - } - } - } - } - } - for(int j = 0; j < this.filenames.length; j++) { - if (this.modNames[j] == null) { - throw new IllegalArgumentException(this.bind("configure.notOnModuleSourcePath", new String[] {this.filenames[j]})); //$NON-NLS-1$ - } - } - } - return result; -} -private void handleSingleModuleCompilation() { - if (this.filenames == null) { - return; - } - IModule singleMod = null; - for (String filename : this.filenames) { - IModule mod = extractModuleDesc(filename); - if (mod != null) { - if (singleMod == null) { - singleMod = mod; - } else { - addPendingErrors(this.bind("configure.duplicateModuleInfo", filename)); //$NON-NLS-1$ - } - } - } - if (singleMod != null) { - String moduleName = new String(singleMod.name()); - for (int i = 0; i < this.modNames.length; i++) { - this.modNames[i] = moduleName; - } - this.module = singleMod; - } -} -/* - * External API - */ -protected ArrayList handleClasspath(ArrayList classpaths, String customEncoding) { - ArrayList initial = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); - if (classpaths != null && classpaths.size() > 0) { - for (String path : classpaths) { - processPathEntries(DEFAULT_SIZE_CLASSPATH, initial, path, customEncoding, false, true); - } - } else { - // no user classpath specified. - String classProp = System.getProperty("java.class.path"); //$NON-NLS-1$ - if ((classProp == null) || (classProp.length() == 0)) { - addPendingErrors(this.bind("configure.noClasspath")); //$NON-NLS-1$ - final Classpath classpath = FileSystem.getClasspath(System.getProperty("user.dir"), customEncoding, null, this.options, this.releaseVersion);//$NON-NLS-1$ - if (classpath != null) { - initial.add(classpath); - } - } else { - StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator); - String token; - while (tokenizer.hasMoreTokens()) { - token = tokenizer.nextToken(); - FileSystem.Classpath currentClasspath = FileSystem - .getClasspath(token, customEncoding, null, this.options, this.releaseVersion); - if (currentClasspath != null) { - initial.add(currentClasspath); - } else if (token.length() != 0) { - addPendingErrors(this.bind("configure.incorrectClasspath", token));//$NON-NLS-1$ - } - } - } - } - ArrayList result = new ArrayList<>(); - HashMap knownNames = new HashMap<>(); - FileSystem.ClasspathSectionProblemReporter problemReporter = - new FileSystem.ClasspathSectionProblemReporter() { - @Override - public void invalidClasspathSection(String jarFilePath) { - addPendingErrors(bind("configure.invalidClasspathSection", jarFilePath)); //$NON-NLS-1$ - } - @Override - public void multipleClasspathSections(String jarFilePath) { - addPendingErrors(bind("configure.multipleClasspathSections", jarFilePath)); //$NON-NLS-1$ - } - }; - while (! initial.isEmpty()) { - Classpath current = initial.remove(0); - String currentPath = current.getPath(); - if (knownNames.get(currentPath) == null) { - knownNames.put(currentPath, current); - result.add(current); - List linkedJars = current.fetchLinkedJars(problemReporter); - if (linkedJars != null) { - initial.addAll(0, linkedJars); - } - } - } - return result; -} -/* - * External API - */ -protected ArrayList handleEndorseddirs(ArrayList endorsedDirClasspaths) { - final File javaHome = getJavaHome(); - /* - * Feed endorsedDirClasspath according to: - * - -endorseddirs first if present; - * - else java.endorsed.dirs if defined; - * - else default extensions directory for the platform. (/lib/endorsed) - */ - if (endorsedDirClasspaths == null) { - endorsedDirClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); - String endorsedDirsStr = System.getProperty("java.endorsed.dirs"); //$NON-NLS-1$ - if (endorsedDirsStr == null) { - if (javaHome != null) { - endorsedDirClasspaths.add(javaHome.getAbsolutePath() + "/lib/endorsed"); //$NON-NLS-1$ - } - } else { - StringTokenizer tokenizer = new StringTokenizer(endorsedDirsStr, File.pathSeparator); - while (tokenizer.hasMoreTokens()) { - endorsedDirClasspaths.add(tokenizer.nextToken()); - } - } - } - - /* - * Feed extdirsClasspath with the entries found into the directories listed by - * extdirsNames. - */ - if (endorsedDirClasspaths.size() != 0) { - ArrayList result = new ArrayList<>(); - File[] directoriesToCheck = new File[endorsedDirClasspaths.size()]; - for (int i = 0; i < directoriesToCheck.length; i++) - directoriesToCheck[i] = new File(endorsedDirClasspaths.get(i)); - File[][] endorsedDirsJars = getLibrariesFiles(directoriesToCheck); - if (endorsedDirsJars != null) { - for (int i = 0, max = endorsedDirsJars.length; i < max; i++) { - File[] current = endorsedDirsJars[i]; - if (current != null) { - for (int j = 0, max2 = current.length; j < max2; j++) { - FileSystem.Classpath classpath = - FileSystem.getClasspath( - current[j].getAbsolutePath(), - null, null, this.options, this.releaseVersion); - if (classpath != null) { - result.add(classpath); - } - } - } else if (directoriesToCheck[i].isFile()) { - addPendingErrors( - this.bind( - "configure.incorrectEndorsedDirsEntry", //$NON-NLS-1$ - directoriesToCheck[i].getAbsolutePath())); - } - } - } - return result; - } - return FileSystem.EMPTY_CLASSPATH; -} - -/* - * External API - * Handle extdirs processing - */ -protected ArrayList handleExtdirs(ArrayList extdirsClasspaths) { - final File javaHome = getJavaHome(); - - /* - * Feed extDirClasspath according to: - * - -extdirs first if present; - * - else java.ext.dirs if defined; - * - else default extensions directory for the platform. - */ - if (extdirsClasspaths == null) { - extdirsClasspaths = new ArrayList<>(DEFAULT_SIZE_CLASSPATH); - String extdirsStr = System.getProperty("java.ext.dirs"); //$NON-NLS-1$ - if (extdirsStr == null) { - extdirsClasspaths.add(javaHome.getAbsolutePath() + "/lib/ext"); //$NON-NLS-1$ - } else { - StringTokenizer tokenizer = new StringTokenizer(extdirsStr, File.pathSeparator); - while (tokenizer.hasMoreTokens()) - extdirsClasspaths.add(tokenizer.nextToken()); - } - } - - /* - * Feed extdirsClasspath with the entries found into the directories listed by - * extdirsNames. - */ - if (extdirsClasspaths.size() != 0) { - ArrayList result = new ArrayList<>(); - File[] directoriesToCheck = new File[extdirsClasspaths.size()]; - for (int i = 0; i < directoriesToCheck.length; i++) - directoriesToCheck[i] = new File(extdirsClasspaths.get(i)); - File[][] extdirsJars = getLibrariesFiles(directoriesToCheck); - if (extdirsJars != null) { - for (int i = 0, max = extdirsJars.length; i < max; i++) { - File[] current = extdirsJars[i]; - if (current != null) { - for (int j = 0, max2 = current.length; j < max2; j++) { - FileSystem.Classpath classpath = - FileSystem.getClasspath( - current[j].getAbsolutePath(), - null, null, this.options, this.releaseVersion); - if (classpath != null) { - result.add(classpath); - } - } - } else if (directoriesToCheck[i].isFile()) { - addPendingErrors(this.bind( - "configure.incorrectExtDirsEntry", //$NON-NLS-1$ - directoriesToCheck[i].getAbsolutePath())); - } - } - } - return result; - } - - return FileSystem.EMPTY_CLASSPATH; -} - -protected boolean isIgnored(IProblem problem) { - if (problem == null) { - return true; - } - if (problem.isError()) { - return false; - } - String key = problem.isInfo() ? CompilerOptions.INFO : CompilerOptions.WARNING; - if (CompilerOptions.IGNORE.equals(this.options.get(key))) { - return true; - } - if (this.ignoreOptionalProblemsFromFolders != null) { - char[] fileName = problem.getOriginatingFileName(); - if (fileName != null) { - return shouldIgnoreOptionalProblems(this.ignoreOptionalProblemsFromFolders, fileName); - } - } - return false; -} - -/* - * External API - * Handle a single warning token. -*/ -protected void handleInfoToken(String token, boolean isEnabling) { - handleErrorOrWarningToken(token, isEnabling, ProblemSeverities.Info); -} -protected void handleWarningToken(String token, boolean isEnabling) { - handleErrorOrWarningToken(token, isEnabling, ProblemSeverities.Warning); -} -protected void handleErrorToken(String token, boolean isEnabling) { - handleErrorOrWarningToken(token, isEnabling, ProblemSeverities.Error); -} -protected void setSeverity(String compilerOptions, int severity, boolean isEnabling) { - if (isEnabling) { - switch(severity) { - case ProblemSeverities.Error : - this.options.put(compilerOptions, CompilerOptions.ERROR); - break; - case ProblemSeverities.Warning : - this.options.put(compilerOptions, CompilerOptions.WARNING); - break; - case ProblemSeverities.Info : - this.options.put(compilerOptions, CompilerOptions.INFO); - break; - default: - this.options.put(compilerOptions, CompilerOptions.IGNORE); - } - } else { - switch(severity) { - case ProblemSeverities.Error : - String currentValue = this.options.get(compilerOptions); - if (CompilerOptions.ERROR.equals(currentValue)) { - this.options.put(compilerOptions, CompilerOptions.IGNORE); - } - break; - case ProblemSeverities.Warning : - currentValue = this.options.get(compilerOptions); - if (CompilerOptions.WARNING.equals(currentValue)) { - this.options.put(compilerOptions, CompilerOptions.IGNORE); - } - break; - case ProblemSeverities.Info : - currentValue = this.options.get(compilerOptions); - if (CompilerOptions.INFO.equals(currentValue)) { - this.options.put(compilerOptions, CompilerOptions.IGNORE); - } - break; - default: - this.options.put(compilerOptions, CompilerOptions.IGNORE); - } - } -} -private void handleErrorOrWarningToken(String token, boolean isEnabling, int severity) { - if (token.length() == 0) return; - switch(token.charAt(0)) { - case 'a' : - if (token.equals("allDeprecation")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportDeprecation, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportTerminalDeprecation, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - this.options.put( - CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("allJavadoc")) { //$NON-NLS-1$ - this.warnAllJavadocOn = this.warnJavadocOn = isEnabling; - setSeverity(CompilerOptions.OPTION_ReportInvalidJavadoc, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportMissingJavadocTags, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportMissingJavadocComments, severity, isEnabling); - return; - } else if (token.equals("assertIdentifier")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportAssertIdentifier, severity, isEnabling); - return; - } else if (token.equals("allDeadCode")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportDeadCode, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportDeadCodeInTrivialIfStatement, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("allOver-ann")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingOverrideAnnotation, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportMissingOverrideAnnotationForInterfaceMethodImplementation, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("all-static-method")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMethodCanBeStatic, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportMethodCanBePotentiallyStatic, severity, isEnabling); - return; - } else if (token.equals("all")) { //$NON-NLS-1$ - if (isEnabling) { - enableAll(severity); - } else { - disableAll(severity); - } - return; - } - break; - case 'b' : - if (token.equals("boxing")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportAutoboxing, severity, isEnabling); - return; - } - break; - case 'c' : - if (token.equals("constructorName")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMethodWithConstructorName, severity, isEnabling); - return; - } else if (token.equals("conditionAssign")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportPossibleAccidentalBooleanAssignment, severity, isEnabling); - return; - } else if (token.equals("compareIdentical")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportComparingIdentical, severity, isEnabling); - return; - } else if (token.equals("charConcat") /*|| token.equals("noImplicitStringConversion")/*backward compatible*/) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNoImplicitStringConversion, severity, isEnabling); - return; - } - break; - case 'd' : - if (token.equals("deprecation")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportDeprecation, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode, - CompilerOptions.DISABLED); - this.options.put( - CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod, - CompilerOptions.DISABLED); - return; - } else if (token.equals("dep-ann")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingDeprecatedAnnotation, severity, isEnabling); - return; - } else if (token.equals("discouraged")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportDiscouragedReference, severity, isEnabling); - return; - } else if (token.equals("deadCode")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportDeadCode, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportDeadCodeInTrivialIfStatement, - CompilerOptions.DISABLED); - return; - } - break; - case 'e' : - if (token.equals("enumSwitch")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, severity, isEnabling); - return; - } else if (token.equals("enumSwitchPedantic")) { //$NON-NLS-1$ - if (isEnabling) { - switch (severity) { - case ProblemSeverities.Error: - setSeverity(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, severity, isEnabling); - break; - case ProblemSeverities.Warning: - if (CompilerOptions.IGNORE.equals(this.options.get(CompilerOptions.OPTION_ReportIncompleteEnumSwitch))) { - setSeverity(CompilerOptions.OPTION_ReportIncompleteEnumSwitch, severity, isEnabling); - } - break; - default: // no severity update - } - } - this.options.put(CompilerOptions.OPTION_ReportMissingEnumCaseDespiteDefault, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("emptyBlock")) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUndocumentedEmptyBlock, severity, isEnabling); - return; - } else if (token.equals("enumIdentifier")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportEnumIdentifier, severity, isEnabling); - return; - } else if (token.equals("exports")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportAPILeak, severity, isEnabling); - return; - } - break; - case 'f' : - if (token.equals("fieldHiding")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportFieldHiding, severity, isEnabling); - return; - } else if (token.equals("finalBound")) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportFinalParameterBound, severity, isEnabling); - return; - } else if (token.equals("finally")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportFinallyBlockNotCompletingNormally, severity, isEnabling); - return; - } else if (token.equals("forbidden")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportForbiddenReference, severity, isEnabling); - return; - } else if (token.equals("fallthrough")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportFallthroughCase, severity, isEnabling); - return; - } - break; - case 'h' : - if (token.equals("hiding")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportHiddenCatchBlock, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportLocalVariableHiding, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportFieldHiding, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportTypeParameterHiding, severity, isEnabling); - return; - } else if (token.equals("hashCode")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingHashCodeMethod, severity, isEnabling); - return; - } - break; - case 'i' : - if (token.equals("indirectStatic")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportIndirectStaticAccess, severity, isEnabling); - return; - } else if (token.equals("inheritNullAnnot")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_InheritNullAnnotations, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("intfNonInherited") || token.equals("interfaceNonInherited")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$ - setSeverity(CompilerOptions.OPTION_ReportIncompatibleNonInheritedInterfaceMethod, severity, isEnabling); - return; - } else if (token.equals("intfAnnotation")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportAnnotationSuperInterface, severity, isEnabling); - return; - } else if (token.equals("intfRedundant") /*|| token.equals("redundantSuperinterface")*/) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportRedundantSuperinterface, severity, isEnabling); - return; - } else if (token.equals("includeAssertNull")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_IncludeNullInfoFromAsserts, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("invalidJavadoc")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportInvalidJavadoc, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTags, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTagsDeprecatedRef, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTagsNotVisibleRef, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - if (isEnabling) { - this.options.put( - CompilerOptions.OPTION_DocCommentSupport, - CompilerOptions.ENABLED); - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTagsVisibility, - CompilerOptions.PRIVATE); - } - return; - } else if (token.equals("invalidJavadocTag")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTags, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("invalidJavadocTagDep")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTagsDeprecatedRef, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("invalidJavadocTagNotVisible")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTagsNotVisibleRef, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.startsWith("invalidJavadocTagVisibility")) { //$NON-NLS-1$ - int start = token.indexOf('('); - int end = token.indexOf(')'); - String visibility = null; - if (isEnabling && start >= 0 && end >= 0 && start < end){ - visibility = token.substring(start+1, end).trim(); - } - if (visibility != null && visibility.equals(CompilerOptions.PUBLIC) - || visibility.equals(CompilerOptions.PRIVATE) - || visibility.equals(CompilerOptions.PROTECTED) - || visibility.equals(CompilerOptions.DEFAULT)) { - this.options.put( - CompilerOptions.OPTION_ReportInvalidJavadocTagsVisibility, - visibility); - return; - } else { - throw new IllegalArgumentException(this.bind("configure.invalidJavadocTagVisibility", token)); //$NON-NLS-1$ - } - } - break; - case 'j' : - if (token.equals("javadoc")) {//$NON-NLS-1$ - this.warnJavadocOn = isEnabling; - setSeverity(CompilerOptions.OPTION_ReportInvalidJavadoc, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportMissingJavadocTags, severity, isEnabling); - return; - } - break; - case 'l' : - if (token.equals("localHiding")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportLocalVariableHiding, severity, isEnabling); - return; - } - break; - case 'm' : - if (token.equals("maskedCatchBlock") || token.equals("maskedCatchBlocks")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$ - setSeverity(CompilerOptions.OPTION_ReportHiddenCatchBlock, severity, isEnabling); - return; - } else if (token.equals("missingJavadocTags")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingJavadocTags, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocTagsOverriding, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocTagsMethodTypeParameters, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - if (isEnabling) { - this.options.put( - CompilerOptions.OPTION_DocCommentSupport, - CompilerOptions.ENABLED); - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocTagsVisibility, - CompilerOptions.PRIVATE); - } - return; - } else if (token.equals("missingJavadocTagsOverriding")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocTagsOverriding, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("missingJavadocTagsMethod")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocTagsMethodTypeParameters, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.startsWith("missingJavadocTagsVisibility")) { //$NON-NLS-1$ - int start = token.indexOf('('); - int end = token.indexOf(')'); - String visibility = null; - if (isEnabling && start >= 0 && end >= 0 && start < end){ - visibility = token.substring(start+1, end).trim(); - } - if (visibility != null && visibility.equals(CompilerOptions.PUBLIC) - || visibility.equals(CompilerOptions.PRIVATE) - || visibility.equals(CompilerOptions.PROTECTED) - || visibility.equals(CompilerOptions.DEFAULT)) { - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocTagsVisibility, - visibility); - return; - } else { - throw new IllegalArgumentException(this.bind("configure.missingJavadocTagsVisibility", token)); //$NON-NLS-1$ - } - } else if (token.equals("missingJavadocComments")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingJavadocComments, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocCommentsOverriding, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - if (isEnabling) { - this.options.put( - CompilerOptions.OPTION_DocCommentSupport, - CompilerOptions.ENABLED); - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocCommentsVisibility, - CompilerOptions.PRIVATE); - } - return; - } else if (token.equals("missingJavadocCommentsOverriding")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingJavadocComments, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocCommentsOverriding, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.startsWith("missingJavadocCommentsVisibility")) { //$NON-NLS-1$ - int start = token.indexOf('('); - int end = token.indexOf(')'); - String visibility = null; - if (isEnabling && start >= 0 && end >= 0 && start < end){ - visibility = token.substring(start+1, end).trim(); - } - if (visibility != null && visibility.equals(CompilerOptions.PUBLIC) - || visibility.equals(CompilerOptions.PRIVATE) - || visibility.equals(CompilerOptions.PROTECTED) - || visibility.equals(CompilerOptions.DEFAULT)) { - this.options.put( - CompilerOptions.OPTION_ReportMissingJavadocCommentsVisibility, - visibility); - return; - } else { - throw new IllegalArgumentException(this.bind("configure.missingJavadocCommentsVisibility", token)); //$NON-NLS-1$ - } - } else if (token.equals("module")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnstableAutoModuleName, severity, isEnabling); - return; - } - break; - case 'n' : - if (token.equals("nls")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNonExternalizedStringLiteral, severity, isEnabling); - return; - } else if (token.equals("noEffectAssign")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNoEffectAssignment, severity, isEnabling); - return; - } else if (/*token.equals("charConcat") ||*/ token.equals("noImplicitStringConversion")/*backward compatible*/) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNoImplicitStringConversion, severity, isEnabling); - return; - } else if (token.equals("null")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNullReference, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportPotentialNullReference, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportRedundantNullCheck, severity, isEnabling); - return; - } else if (token.equals("nullDereference")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNullReference, severity, isEnabling); - if (!isEnabling) { - setSeverity(CompilerOptions.OPTION_ReportPotentialNullReference, ProblemSeverities.Ignore, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportRedundantNullCheck, ProblemSeverities.Ignore, isEnabling); - } - return; - }else if (token.equals("nullAnnotConflict")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNullAnnotationInferenceConflict, severity, isEnabling); - return; - } else if (token.equals("nullAnnotRedundant")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportRedundantNullAnnotation, severity, isEnabling); - return; - } else if (token.startsWith("nullAnnot")) { //$NON-NLS-1$ - String annotationNames = Util.EMPTY_STRING; - int start = token.indexOf('('); - int end = token.indexOf(')'); - String nonNullAnnotName = null, nullableAnnotName = null, nonNullByDefaultAnnotName = null; - if (isEnabling && start >= 0 && end >= 0 && start < end){ - boolean isPrimarySet = !this.primaryNullAnnotationsSeen; - annotationNames = token.substring(start+1, end).trim(); - int separator1 = annotationNames.indexOf('|'); - if (separator1 == -1) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$ - nullableAnnotName = annotationNames.substring(0, separator1).trim(); - if (isPrimarySet && nullableAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$ - int separator2 = annotationNames.indexOf('|', separator1 + 1); - if (separator2 == -1) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$ - nonNullAnnotName = annotationNames.substring(separator1 + 1, separator2).trim(); - if (isPrimarySet && nonNullAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$ - nonNullByDefaultAnnotName = annotationNames.substring(separator2 + 1).trim(); - if (isPrimarySet && nonNullByDefaultAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$ - if (isPrimarySet) { - this.primaryNullAnnotationsSeen = true; - this.options.put(CompilerOptions.OPTION_NullableAnnotationName, nullableAnnotName); - this.options.put(CompilerOptions.OPTION_NonNullAnnotationName, nonNullAnnotName); - this.options.put(CompilerOptions.OPTION_NonNullByDefaultAnnotationName, nonNullByDefaultAnnotName); - } else { - if (nullableAnnotName.length() > 0) { - String nullableList = this.options.get(CompilerOptions.OPTION_NullableAnnotationSecondaryNames); - nullableList = nullableList.isEmpty() ? nullableAnnotName : nullableList + ',' + nullableAnnotName; - this.options.put(CompilerOptions.OPTION_NullableAnnotationSecondaryNames, nullableList); - } - if (nonNullAnnotName.length() > 0) { - String nonnullList = this.options.get(CompilerOptions.OPTION_NonNullAnnotationSecondaryNames); - nonnullList = nonnullList.isEmpty() ? nonNullAnnotName : nonnullList + ',' + nonNullAnnotName; - this.options.put(CompilerOptions.OPTION_NonNullAnnotationSecondaryNames, nonnullList); - } - if (nonNullByDefaultAnnotName.length() > 0) { - String nnbdList = this.options.get(CompilerOptions.OPTION_NonNullByDefaultAnnotationSecondaryNames); - nnbdList = nnbdList.isEmpty() ? nonNullByDefaultAnnotName : nnbdList + ',' + nonNullByDefaultAnnotName; - this.options.put(CompilerOptions.OPTION_NonNullByDefaultAnnotationSecondaryNames, nnbdList); - } - } - } - this.options.put( - CompilerOptions.OPTION_AnnotationBasedNullAnalysis, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - setSeverity(CompilerOptions.OPTION_ReportNullSpecViolation, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportNullAnnotationInferenceConflict, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportNullUncheckedConversion, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportRedundantNullAnnotation, severity, isEnabling); - return; - } else if (token.equals("nullUncheckedConversion")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNullUncheckedConversion, severity, isEnabling); - return; - } else if (token.equals("nonnullNotRepeated")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNonnullParameterAnnotationDropped, severity, isEnabling); - return; - } - - break; - case 'o' : - if (token.equals("over-sync") /*|| token.equals("syncOverride")*/) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingSynchronizedOnInheritedMethod, severity, isEnabling); - return; - } else if (token.equals("over-ann")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingOverrideAnnotation, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportMissingOverrideAnnotationForInterfaceMethodImplementation, - CompilerOptions.DISABLED); - return; - } - break; - case 'p' : - if (token.equals("pkgDefaultMethod") || token.equals("packageDefaultMethod")/*backward compatible*/ ) { //$NON-NLS-1$ //$NON-NLS-2$ - setSeverity(CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod, severity, isEnabling); - return; - } else if (token.equals("paramAssign")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportParameterAssignment, severity, isEnabling); - return; - } - break; - case 'r' : - if (token.equals("raw")) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportRawTypeReference, severity, isEnabling); - return; - } 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; - } else if (token.equals("removal")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportTerminalDeprecation, severity, isEnabling); - this.options.put( - CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode, - CompilerOptions.DISABLED); - this.options.put( - CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod, - CompilerOptions.DISABLED); - return; - } - break; - case 's' : - if (token.equals("specialParamHiding")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportSpecialParameterHidingField, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("syntheticAccess") || token.equals("synthetic-access")) { //$NON-NLS-1$ //$NON-NLS-2$ - setSeverity(CompilerOptions.OPTION_ReportSyntheticAccessEmulation, severity, isEnabling); - return; - } else if (token.equals("staticReceiver")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, severity, isEnabling); - return; - } else if (/*token.equals("over-sync") ||*/ token.equals("syncOverride")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingSynchronizedOnInheritedMethod, severity, isEnabling); - return; - } else if (token.equals("semicolon")) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportEmptyStatement, severity, isEnabling); - return; - } else if (token.equals("serial")) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingSerialVersion, severity, isEnabling); - return; - } else if (token.equals("suppress")) {//$NON-NLS-1$ - switch(severity) { - case ProblemSeverities.Warning : - this.options.put( - CompilerOptions.OPTION_SuppressWarnings, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - this.options.put( - CompilerOptions.OPTION_SuppressOptionalErrors, - CompilerOptions.DISABLED); - break; - case ProblemSeverities.Error : - this.options.put( - CompilerOptions.OPTION_SuppressWarnings, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - this.options.put( - CompilerOptions.OPTION_SuppressOptionalErrors, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - } - return; - } else if (token.equals("static-access")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportNonStaticAccessToStatic, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportIndirectStaticAccess, severity, isEnabling); - return; - } else if (token.equals("super")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportOverridingMethodWithoutSuperInvocation, severity, isEnabling); - return; - } else if (token.equals("static-method")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMethodCanBeStatic, severity, isEnabling); - return; - } else if (token.equals("switchDefault")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportMissingDefaultCase, severity, isEnabling); - return; - } else if (token.equals("syntacticAnalysis")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_SyntacticNullAnalysisForFields, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } - break; - case 't' : - if (token.startsWith("tasks")) { //$NON-NLS-1$ - String taskTags = Util.EMPTY_STRING; - int start = token.indexOf('('); - int end = token.indexOf(')'); - if (start >= 0 && end >= 0 && start < end){ - taskTags = token.substring(start+1, end).trim(); - taskTags = taskTags.replace('|',','); - } - if (taskTags.length() == 0){ - throw new IllegalArgumentException(this.bind("configure.invalidTaskTag", token)); //$NON-NLS-1$ - } - this.options.put( - CompilerOptions.OPTION_TaskTags, - isEnabling ? taskTags : Util.EMPTY_STRING); - - setSeverity(CompilerOptions.OPTION_ReportTasks, severity, isEnabling); - return; - } else if (token.equals("typeHiding")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportTypeParameterHiding, severity, isEnabling); - return; - } - break; - case 'u' : - if (token.equals("unusedLocal") || token.equals("unusedLocals")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$ - setSeverity(CompilerOptions.OPTION_ReportUnusedLocal, severity, isEnabling); - return; - } else if (token.equals("unusedArgument") || token.equals("unusedArguments")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$ - setSeverity(CompilerOptions.OPTION_ReportUnusedParameter, severity, isEnabling); - return; - } else if (token.equals("unusedExceptionParam")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnusedExceptionParameter, severity, isEnabling); - return; - } else if (token.equals("unusedImport") || token.equals("unusedImports")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$ - setSeverity(CompilerOptions.OPTION_ReportUnusedImport, severity, isEnabling); - return; - } else if (token.equals("unusedAllocation")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnusedObjectAllocation, severity, isEnabling); - return; - } else if (token.equals("unusedPrivate")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnusedPrivateMember, severity, isEnabling); - return; - } else if (token.equals("unusedLabel")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnusedLabel, severity, isEnabling); - return; - } else if (token.equals("uselessTypeCheck")) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnnecessaryTypeCheck, severity, isEnabling); - return; - } else if (token.equals("unchecked") || token.equals("unsafe")) {//$NON-NLS-1$ //$NON-NLS-2$ - setSeverity(CompilerOptions.OPTION_ReportUncheckedTypeOperation, severity, isEnabling); - return; - } else if (token.equals("unlikelyCollectionMethodArgumentType")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnlikelyCollectionMethodArgumentType, severity, isEnabling); - return; - } else if (token.equals("unlikelyEqualsArgumentType")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnlikelyEqualsArgumentType, severity, isEnabling); - return; - } else if (token.equals("unnecessaryElse")) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnnecessaryElse, severity, isEnabling); - return; - } else if (token.equals("unusedThrown")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnusedDeclaredThrownException, severity, isEnabling); - return; - } else if (token.equals("unusedThrownWhenOverriding")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionWhenOverriding, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("unusedThrownIncludeDocComment")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionIncludeDocCommentReference, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("unusedThrownExemptExceptionThrowable")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportUnusedDeclaredThrownExceptionExemptExceptionAndThrowable, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("unqualifiedField") || token.equals("unqualified-field-access")) { //$NON-NLS-1$ //$NON-NLS-2$ - setSeverity(CompilerOptions.OPTION_ReportUnqualifiedFieldAccess, severity, isEnabling); - return; - } else if (token.equals("unused")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportDeadCode, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportRedundantSuperinterface, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportRedundantSpecificationOfTypeArguments, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedDeclaredThrownException, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedExceptionParameter, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedImport, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedLabel, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedLocal, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedObjectAllocation, severity,isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedParameter, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedPrivateMember, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedTypeArgumentsForMethodInvocation, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedTypeParameter, severity,isEnabling); - return; - } else if (token.equals("unusedParam")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnusedParameter, severity, isEnabling); - return; - } else if (token.equals("unusedTypeParameter")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnusedTypeParameter, severity, isEnabling); - return; - } else if (token.equals("unusedParamIncludeDoc")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportUnusedParameterIncludeDocCommentReference, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("unusedParamOverriding")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportUnusedParameterWhenOverridingConcrete, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("unusedParamImplementing")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportUnusedParameterWhenImplementingAbstract, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } else if (token.equals("unusedTypeArgs")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnusedTypeArgumentsForMethodInvocation, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportRedundantSpecificationOfTypeArguments, severity, isEnabling); - return; - } else if (token.equals("unavoidableGenericProblems")) { //$NON-NLS-1$ - this.options.put( - CompilerOptions.OPTION_ReportUnavoidableGenericTypeProblems, - isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED); - return; - } - break; - case 'v' : - if (token.equals("varargsCast")) { //$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportVarargsArgumentNeedCast, severity, isEnabling); - return; - } - break; - case 'w' : - if (token.equals("warningToken")) {//$NON-NLS-1$ - setSeverity(CompilerOptions.OPTION_ReportUnhandledWarningToken, severity, isEnabling); - setSeverity(CompilerOptions.OPTION_ReportUnusedWarningToken, severity, isEnabling); - return; - } - break; - } - String message = null; - switch(severity) { - case ProblemSeverities.Info: - message = this.bind("configure.invalidInfo", token); //$NON-NLS-1$ - break; - case ProblemSeverities.Warning : - message = this.bind("configure.invalidWarning", token); //$NON-NLS-1$ - break; - case ProblemSeverities.Error : - message = this.bind("configure.invalidError", token); //$NON-NLS-1$ - } - addPendingErrors(message); -} -/** - * @deprecated - use {@link #initialize(PrintWriter, PrintWriter, boolean, Map, CompilationProgress)} instead - * e.g. initialize(outWriter, errWriter, systemExit, null, null) - */ -protected void initialize(PrintWriter outWriter, PrintWriter errWriter, boolean systemExit) { - this.initialize(outWriter, errWriter, systemExit, null /* options */, null /* progress */); -} -/** - * @deprecated - use {@link #initialize(PrintWriter, PrintWriter, boolean, Map, CompilationProgress)} instead - * e.g. initialize(outWriter, errWriter, systemExit, customDefaultOptions, null) - */ -protected void initialize(PrintWriter outWriter, PrintWriter errWriter, boolean systemExit, Map customDefaultOptions) { - this.initialize(outWriter, errWriter, systemExit, customDefaultOptions, null /* progress */); -} -protected void initialize(PrintWriter outWriter, PrintWriter errWriter, boolean systemExit, Map customDefaultOptions, CompilationProgress compilationProgress) { - this.logger = new Logger(this, outWriter, errWriter); - this.proceed = true; - this.out = outWriter; - this.err = errWriter; - this.systemExitWhenFinished = systemExit; - this.options = new CompilerOptions().getMap(); - this.ignoreOptionalProblemsFromFolders = null; - - this.progress = compilationProgress; - if (customDefaultOptions != null) { - this.didSpecifySource = customDefaultOptions.get(CompilerOptions.OPTION_Source) != null; - this.didSpecifyTarget = customDefaultOptions.get(CompilerOptions.OPTION_TargetPlatform) != null; - for (Iterator> iter = customDefaultOptions.entrySet().iterator(); iter.hasNext();) { - Map.Entry entry = iter.next(); - this.options.put(entry.getKey(), entry.getValue()); - } - } else { - this.didSpecifySource = false; - this.didSpecifyTarget = false; - } - this.classNames = null; -} -protected void initializeAnnotationProcessorManager() { - String className = "org.eclipse.jdt.internal.compiler.apt.dispatch.BatchAnnotationProcessorManager"; //$NON-NLS-1$ - try { - Class c = Class.forName(className); - AbstractAnnotationProcessorManager annotationManager = (AbstractAnnotationProcessorManager) c.getDeclaredConstructor().newInstance(); - annotationManager.configure(this, this.expandedCommandLine); - annotationManager.setErr(this.err); - annotationManager.setOut(this.out); - this.batchCompiler.annotationProcessorManager = annotationManager; - } catch (ClassNotFoundException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { - this.logger.logUnavaibleAPT(className); - throw new org.eclipse.jdt.internal.compiler.problem.AbortCompilation(); - } catch (IllegalAccessException e) { - // should not happen - throw new org.eclipse.jdt.internal.compiler.problem.AbortCompilation(); - } catch(UnsupportedClassVersionError e) { - // report a warning - this.logger.logIncorrectVMVersionForAnnotationProcessing(); - } -} -private static boolean isParentOf(char[] folderName, char[] fileName) { - if (folderName.length >= fileName.length) { - return false; - } - if (fileName[folderName.length] != '\\' && fileName[folderName.length] != '/') { - return false; - } - for (int i = folderName.length - 1; i >= 0; i--) { - if (folderName[i] != fileName[i]) { - return false; - } - } - return true; -} -// Dump classfiles onto disk for all compilation units that where successful -// and do not carry a -d none spec, either directly or inherited from Main. -public void outputClassFiles(CompilationResult unitResult) { - if (!((unitResult == null) || (unitResult.hasErrors() && !this.proceedOnError))) { - ClassFile[] classFiles = unitResult.getClassFiles(); - String currentDestinationPath = null; - boolean generateClasspathStructure = false; - CompilationUnit compilationUnit = - (CompilationUnit) unitResult.compilationUnit; - if (compilationUnit.destinationPath == null) { - if (this.destinationPath == null) { - currentDestinationPath = - extractDestinationPathFromSourceFile(unitResult); - } else if (this.destinationPath != NONE) { - currentDestinationPath = this.destinationPath; - generateClasspathStructure = true; - } // else leave currentDestinationPath null - } else if (compilationUnit.destinationPath != NONE) { - currentDestinationPath = compilationUnit.destinationPath; - generateClasspathStructure = true; - } // else leave currentDestinationPath null - if (currentDestinationPath != null) { - for (int i = 0, fileCount = classFiles.length; i < fileCount; i++) { - // retrieve the key and the corresponding classfile - ClassFile classFile = classFiles[i]; - char[] filename = classFile.fileName(); - int length = filename.length; - char[] relativeName = new char[length + 6]; - System.arraycopy(filename, 0, relativeName, 0, length); - System.arraycopy(SuffixConstants.SUFFIX_class, 0, relativeName, length, 6); - CharOperation.replace(relativeName, '/', File.separatorChar); - String relativeStringName = new String(relativeName); - try { - if (this.compilerOptions.verbose) - this.out.println( - Messages.bind( - Messages.compilation_write, - new String[] { - String.valueOf(this.exportedClassFilesCounter+1), - relativeStringName - })); - Util.writeToDisk( - generateClasspathStructure, - currentDestinationPath, - relativeStringName, - classFile); - this.logger.logClassFile( - generateClasspathStructure, - currentDestinationPath, - relativeStringName); - this.exportedClassFilesCounter++; - } catch (IOException e) { - this.logger.logNoClassFileCreated(currentDestinationPath, relativeStringName, e); - } - } - this.batchCompiler.lookupEnvironment.releaseClassFiles(classFiles); - } - } -} -/* - * Low-level API performing the actual compilation - */ -public void performCompilation() { - this.startTime = System.currentTimeMillis(); - - FileSystem environment = getLibraryAccess(); - try { - this.compilerOptions = new CompilerOptions(this.options); - this.compilerOptions.performMethodsFullRecovery = false; - this.compilerOptions.performStatementsRecovery = false; - this.batchCompiler = - new Compiler( - environment, - getHandlingPolicy(), - this.compilerOptions, - getBatchRequestor(), - getProblemFactory(), - this.out, - this.progress); - this.batchCompiler.remainingIterations = this.maxRepetition-this.currentRepetition/*remaining iterations including this one*/; - // temporary code to allow the compiler to revert to a single thread - String setting = System.getProperty("jdt.compiler.useSingleThread"); //$NON-NLS-1$ - this.batchCompiler.useSingleThread = setting != null && setting.equals("true"); //$NON-NLS-1$ - - if (this.compilerOptions.complianceLevel >= ClassFileConstants.JDK1_6 - && this.compilerOptions.processAnnotations) { - if (checkVMVersion(ClassFileConstants.JDK1_6)) { - initializeAnnotationProcessorManager(); - if (this.classNames != null) { - this.batchCompiler.setBinaryTypes(processClassNames(this.batchCompiler.lookupEnvironment)); - } - } else { - // report a warning - this.logger.logIncorrectVMVersionForAnnotationProcessing(); - } - if (checkVMVersion(ClassFileConstants.JDK9)) { - initRootModules(this.batchCompiler.lookupEnvironment, environment); - } - } - - // set the non-externally configurable options. - this.compilerOptions.verbose = this.verbose; - this.compilerOptions.produceReferenceInfo = this.produceRefInfo; - try { - this.logger.startLoggingSources(); - this.batchCompiler.compile(getCompilationUnits()); - } finally { - this.logger.endLoggingSources(); - } - - if (this.extraProblems != null) { - loggingExtraProblems(); - this.extraProblems = null; - } - if (this.compilerStats != null) { - this.compilerStats[this.currentRepetition] = this.batchCompiler.stats; - } - this.logger.printStats(); - } - finally { - // cleanup - environment.cleanup(); - } -} -protected void loggingExtraProblems() { - this.logger.loggingExtraProblems(this); -} -public void printUsage() { - printUsage("misc.usage"); //$NON-NLS-1$ -} -private void printUsage(String sectionID) { - this.logger.logUsage( - this.bind( - sectionID, - new String[] { - System.getProperty("path.separator"), //$NON-NLS-1$ - this.bind("compiler.name"), //$NON-NLS-1$ - this.bind("compiler.version"), //$NON-NLS-1$ - this.bind("compiler.copyright") //$NON-NLS-1$ - })); - this.logger.flush(); -} -private void initRootModules(LookupEnvironment environment, FileSystem fileSystem) { - Map map = new HashMap<>(); - for (String m : this.rootModules) { - ModuleBinding mod = environment.getModule(m.toCharArray()); - if (mod == null) { - throw new IllegalArgumentException(this.bind("configure.invalidModuleName", m)); //$NON-NLS-1$ - } - PackageBinding[] exports = mod.getExports(); - for (PackageBinding packageBinding : exports) { - String qName = CharOperation.toString(packageBinding.compoundName); - String existing = map.get(qName); - if (existing != null) { - throw new IllegalArgumentException(this.bind("configure.packageConflict", new String[] {qName, existing, m})); //$NON-NLS-1$ - // report an error and bail out - } - map.put(qName, m); - } - } - if (this.limitedModules != null) { - for (String m : this.limitedModules) { - ModuleBinding mod = environment.getModule(m.toCharArray()); - if (mod == null) { - throw new IllegalArgumentException(this.bind("configure.invalidModuleName", m)); //$NON-NLS-1$ - } - } - } - environment.moduleVersion = this.moduleVersion; -} -private ReferenceBinding[] processClassNames(LookupEnvironment environment) { - // check for .class file presence in case of apt processing - int length = this.classNames.length; - ReferenceBinding[] referenceBindings = new ReferenceBinding[length]; - ModuleBinding[] modules = new ModuleBinding[length]; - Set modSet = new HashSet<>(); - String[] typeNames = new String[length]; - if (this.complianceLevel <= ClassFileConstants.JDK1_8) { - typeNames = this.classNames; - } else { - for (int i = 0; i < length; i++) { - String currentName = this.classNames[i]; - int idx = currentName.indexOf('/'); - ModuleBinding mod = null; - if (idx > 0) { - String m = currentName.substring(0, idx); - mod = environment.getModule(m.toCharArray()); - if (mod == null) { - throw new IllegalArgumentException(this.bind("configure.invalidModuleName", m)); //$NON-NLS-1$ - } - modules[i] = mod; - modSet.add(mod); - currentName = currentName.substring(idx + 1); - } - typeNames[i] = currentName; - } - } - - for (int i = 0; i < length; i++) { - char[][] compoundName = null; - String cls = typeNames[i]; - if (cls.indexOf('.') != -1) { - // consider names with '.' as fully qualified names - char[] typeName = cls.toCharArray(); - compoundName = CharOperation.splitOn('.', typeName); - } else { - compoundName = new char[][] { cls.toCharArray() }; - } - ModuleBinding mod = modules[i]; - ReferenceBinding type = mod != null ? environment.getType(compoundName, mod) : environment.getType(compoundName); - if (type != null && type.isValidBinding()) { - if (type.isBinaryBinding()) { - referenceBindings[i] = type; - type.superclass(); - } - } else { - throw new IllegalArgumentException( - this.bind("configure.invalidClassName", this.classNames[i]));//$NON-NLS-1$ - } - } - return referenceBindings; -} -private ArrayList processModulePathEntries(String arg) { - ArrayList paths = new ArrayList<>(); - if (arg == null) - return paths; - StringTokenizer tokenizer = new StringTokenizer(arg, File.pathSeparator, false); - while (tokenizer.hasMoreTokens()) { - paths.add(tokenizer.nextToken()); - } - return paths; -} -/* - * External API - */ -public void processPathEntries(final int defaultSize, final ArrayList paths, - final String currentPath, String customEncoding, boolean isSourceOnly, - boolean rejectDestinationPathOnJars) { - String currentClasspathName = null; - String currentDestinationPath = null; - ArrayList currentRuleSpecs = new ArrayList<>(defaultSize); - StringTokenizer tokenizer = new StringTokenizer(currentPath, - File.pathSeparator + "[]", true); //$NON-NLS-1$ - ArrayList tokens = new ArrayList<>(); - while (tokenizer.hasMoreTokens()) { - tokens.add(tokenizer.nextToken()); - } - // state machine - final int start = 0; - final int readyToClose = 1; - // 'path' 'path1[rule];path2' - final int readyToCloseEndingWithRules = 2; - // 'path[rule]' 'path1;path2[rule]' - final int readyToCloseOrOtherEntry = 3; - // 'path[rule];' 'path;' 'path1;path2;' - final int rulesNeedAnotherRule = 4; - // 'path[rule1;' - final int rulesStart = 5; - // 'path[' 'path1;path2[' - final int rulesReadyToClose = 6; - // 'path[rule' 'path[rule1;rule2' - final int destinationPathReadyToClose = 7; - // 'path[-d bin' - final int readyToCloseEndingWithDestinationPath = 8; - // 'path[-d bin]' 'path[rule][-d bin]' - final int destinationPathStart = 9; - // 'path[rule][' - final int bracketOpened = 10; - // '.*[.*' - final int bracketClosed = 11; - // '.*([.*])+' - - final int error = 99; - int state = start; - String token = null; - int cursor = 0, tokensNb = tokens.size(), bracket = -1; - while (cursor < tokensNb && state != error) { - token = tokens.get(cursor++); - if (token.equals(File.pathSeparator)) { - switch (state) { - case start: - case readyToCloseOrOtherEntry: - case bracketOpened: - break; - case readyToClose: - case readyToCloseEndingWithRules: - case readyToCloseEndingWithDestinationPath: - state = readyToCloseOrOtherEntry; - addNewEntry(paths, currentClasspathName, currentRuleSpecs, - customEncoding, currentDestinationPath, isSourceOnly, - rejectDestinationPathOnJars); - currentRuleSpecs.clear(); - break; - case rulesReadyToClose: - state = rulesNeedAnotherRule; - break; - case destinationPathReadyToClose: - throw new IllegalArgumentException( - this.bind("configure.incorrectDestinationPathEntry", //$NON-NLS-1$ - currentPath)); - case bracketClosed: - cursor = bracket + 1; - state = rulesStart; - break; - default: - state = error; - } - } else if (token.equals("[")) { //$NON-NLS-1$ - switch (state) { - case start: - currentClasspathName = ""; //$NON-NLS-1$ - //$FALL-THROUGH$ - case readyToClose: - bracket = cursor - 1; - //$FALL-THROUGH$ - case bracketClosed: - state = bracketOpened; - break; - case readyToCloseEndingWithRules: - state = destinationPathStart; - break; - case readyToCloseEndingWithDestinationPath: - state = rulesStart; - break; - case bracketOpened: - default: - state = error; - } - } else if (token.equals("]")) { //$NON-NLS-1$ - switch (state) { - case rulesReadyToClose: - state = readyToCloseEndingWithRules; - break; - case destinationPathReadyToClose: - state = readyToCloseEndingWithDestinationPath; - break; - case bracketOpened: - state = bracketClosed; - break; - case bracketClosed: - default: - state = error; - } - } else { - // regular word - switch (state) { - case start: - case readyToCloseOrOtherEntry: - state = readyToClose; - currentClasspathName = token; - break; - case rulesStart: - if (token.startsWith("-d ")) { //$NON-NLS-1$ - if (currentDestinationPath != null) { - throw new IllegalArgumentException( - this.bind("configure.duplicateDestinationPathEntry", //$NON-NLS-1$ - currentPath)); - } - currentDestinationPath = token.substring(3).trim(); - state = destinationPathReadyToClose; - break; - } // else we proceed with a rule - //$FALL-THROUGH$ - case rulesNeedAnotherRule: - if (currentDestinationPath != null) { - throw new IllegalArgumentException( - this.bind("configure.accessRuleAfterDestinationPath", //$NON-NLS-1$ - currentPath)); - } - state = rulesReadyToClose; - currentRuleSpecs.add(token); - break; - case destinationPathStart: - if (!token.startsWith("-d ")) { //$NON-NLS-1$ - state = error; - } else { - currentDestinationPath = token.substring(3).trim(); - state = destinationPathReadyToClose; - } - break; - case bracketClosed: - for (int i = bracket; i < cursor ; i++) { - currentClasspathName += tokens.get(i); - } - state = readyToClose; - break; - case bracketOpened: - break; - default: - state = error; - } - } - if (state == bracketClosed && cursor == tokensNb) { - cursor = bracket + 1; - state = rulesStart; - } - } - switch(state) { - case readyToCloseOrOtherEntry: - break; - case readyToClose: - case readyToCloseEndingWithRules: - case readyToCloseEndingWithDestinationPath: - addNewEntry(paths, currentClasspathName, currentRuleSpecs, - customEncoding, currentDestinationPath, isSourceOnly, - rejectDestinationPathOnJars); - break; - case bracketOpened: - case bracketClosed: - default : - // we go on anyway - if (currentPath.length() != 0) { - addPendingErrors(this.bind("configure.incorrectClasspath", currentPath));//$NON-NLS-1$ - } - } -} - -private int processPaths(String[] args, int index, String currentArg, ArrayList paths) { - int localIndex = index; - int count = 0; - for (int i = 0, max = currentArg.length(); i < max; i++) { - switch(currentArg.charAt(i)) { - case '[' : - count++; - break; - case ']' : - count--; - break; - } - } - if (count == 0) { - paths.add(currentArg); - } else if (count > 1) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedBracket", //$NON-NLS-1$ - currentArg)); - } else { - StringBuilder currentPath = new StringBuilder(currentArg); - while (true) { - if (localIndex >= args.length) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedBracket", //$NON-NLS-1$ - currentArg)); - } - localIndex++; - String nextArg = args[localIndex]; - for (int i = 0, max = nextArg.length(); i < max; i++) { - switch(nextArg.charAt(i)) { - case '[' : - if (count > 1) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedBracket", //$NON-NLS-1$ - nextArg)); - } - count++; - break; - case ']' : - count--; - break; - } - } - if (count == 0) { - currentPath.append(' '); - currentPath.append(nextArg); - paths.add(currentPath.toString()); - return localIndex - index; - } else if (count < 0) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedBracket", //$NON-NLS-1$ - nextArg)); - } else { - currentPath.append(' '); - currentPath.append(nextArg); - } - } - - } - return localIndex - index; -} -private int processPaths(String[] args, int index, String currentArg, String[] paths) { - int localIndex = index; - int count = 0; - for (int i = 0, max = currentArg.length(); i < max; i++) { - switch(currentArg.charAt(i)) { - case '[' : - count++; - break; - case ']' : - count--; - break; - } - } - if (count == 0) { - paths[0] = currentArg; - } else { - StringBuilder currentPath = new StringBuilder(currentArg); - while (true) { - localIndex++; - if (localIndex >= args.length) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedBracket", //$NON-NLS-1$ - currentArg)); - } - String nextArg = args[localIndex]; - for (int i = 0, max = nextArg.length(); i < max; i++) { - switch(nextArg.charAt(i)) { - case '[' : - if (count > 1) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedBracket", //$NON-NLS-1$ - currentArg)); - } - count++; - break; - case ']' : - count--; - break; - } - } - if (count == 0) { - currentPath.append(' '); - currentPath.append(nextArg); - paths[0] = currentPath.toString(); - return localIndex - index; - } else if (count < 0) { - throw new IllegalArgumentException( - this.bind("configure.unexpectedBracket", //$NON-NLS-1$ - currentArg)); - } else { - currentPath.append(' '); - currentPath.append(nextArg); - } - } - - } - return localIndex - index; -} -/** - * Creates a NLS catalog for the given locale. - */ -public void relocalize() { - relocalize(Locale.getDefault()); -} - -private void relocalize(Locale locale) { - this.compilerLocale = locale; - try { - this.bundle = ResourceBundleFactory.getBundle(locale); - } catch(MissingResourceException e) { - System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$ - throw e; - } -} -/* - * External API - */ -public void setDestinationPath(String dest) { - this.destinationPath = dest; -} -/* - * External API - */ -public void setLocale(Locale locale) { - relocalize(locale); -} -/* - * External API - */ -protected void setPaths(ArrayList bootclasspaths, - String sourcepathClasspathArg, - ArrayList sourcepathClasspaths, - ArrayList classpaths, - String modulePath, - String moduleSourcepath, - ArrayList extdirsClasspaths, - ArrayList endorsedDirClasspaths, - String customEncoding) { - - if (this.complianceLevel == 0) { - String version = this.options.get(CompilerOptions.OPTION_Compliance); - this.complianceLevel = CompilerOptions.versionToJdkLevel(version); - } - // process bootclasspath, classpath and sourcepaths - ArrayList allPaths = null; - long jdkLevel = validateClasspathOptions(bootclasspaths, endorsedDirClasspaths, extdirsClasspaths); - - if (this.releaseVersion != null && this.complianceLevel < jdkLevel) { - // TODO: Revisit for access rules - allPaths = new ArrayList<>(); - allPaths.add( - FileSystem.getOlderSystemRelease(this.javaHomeCache.getAbsolutePath(), this.releaseVersion, null)); - } else { - allPaths = handleBootclasspath(bootclasspaths, customEncoding); - } - - List cp = handleClasspath(classpaths, customEncoding); - - List mp = handleModulepath(modulePath); - - List msp = handleModuleSourcepath(moduleSourcepath); - - ArrayList sourcepaths = new ArrayList<>(); - if (sourcepathClasspathArg != null) { - processPathEntries(DEFAULT_SIZE_CLASSPATH, sourcepaths, - sourcepathClasspathArg, customEncoding, true, false); - } - - /* - * Feed endorsedDirClasspath according to: - * - -extdirs first if present; - * - else java.ext.dirs if defined; - * - else default extensions directory for the platform. - */ - List extdirs = handleExtdirs(extdirsClasspaths); - - List endorsed = handleEndorseddirs(endorsedDirClasspaths); - - /* - * Concatenate classpath entries - * We put the bootclasspath at the beginning of the classpath - * entries, followed by the extension libraries, followed by - * the sourcepath followed by the classpath. All classpath - * entries are searched for both sources and binaries except - * the sourcepath entries which are searched for sources only. - */ - allPaths.addAll(0, endorsed); - allPaths.addAll(extdirs); - allPaths.addAll(sourcepaths); - allPaths.addAll(cp); - allPaths.addAll(mp); - allPaths.addAll(msp); - allPaths = FileSystem.ClasspathNormalizer.normalize(allPaths); - this.checkedClasspaths = new FileSystem.Classpath[allPaths.size()]; - allPaths.toArray(this.checkedClasspaths); - this.logger.logClasspath(this.checkedClasspaths); - - if (this.annotationPaths != null && CompilerOptions.ENABLED.equals(this.options.get(CompilerOptions.OPTION_AnnotationBasedNullAnalysis))) { - for (FileSystem.Classpath c : this.checkedClasspaths) { - if (c instanceof ClasspathJar) - ((ClasspathJar) c).annotationPaths = this.annotationPaths; - else if (c instanceof ClasspathJrt) - ((ClasspathJrt) c).annotationPaths = this.annotationPaths; - } - } -} -public final static boolean shouldIgnoreOptionalProblems(char[][] folderNames, char[] fileName) { - if (folderNames == null || fileName == null) { - return false; - } - for (int i = 0, max = folderNames.length; i < max; i++) { - char[] folderName = folderNames[i]; - if (isParentOf(folderName, fileName)) { - return true; - } - } - return false; -} -protected long validateClasspathOptions(ArrayList bootclasspaths, ArrayList endorsedDirClasspaths, ArrayList extdirsClasspaths) { - if (this.complianceLevel > ClassFileConstants.JDK1_8) { - if (bootclasspaths != null && bootclasspaths.size() > 0) - throw new IllegalArgumentException( - this.bind("configure.unsupportedOption", "-bootclasspath")); //$NON-NLS-1$ //$NON-NLS-2$ - if (extdirsClasspaths != null && extdirsClasspaths.size() > 0) - throw new IllegalArgumentException( - this.bind("configure.unsupportedOption", "-extdirs")); //$NON-NLS-1$ //$NON-NLS-2$ - if (endorsedDirClasspaths != null && endorsedDirClasspaths.size() > 0) - throw new IllegalArgumentException( - this.bind("configure.unsupportedOption", "-endorseddirs")); //$NON-NLS-1$ //$NON-NLS-2$ - } - long jdkLevel = Util.getJDKLevel(getJavaHome()); - if (jdkLevel < ClassFileConstants.JDK9 && this.releaseVersion != null) { - throw new IllegalArgumentException( - this.bind("configure.unsupportedReleaseOption")); //$NON-NLS-1$ - } - return jdkLevel; -} -protected void validateOptions(boolean didSpecifyCompliance) { - if (didSpecifyCompliance) { - String version = this.options.get(CompilerOptions.OPTION_Compliance); - if (this.releaseVersion != null) { - throw new IllegalArgumentException( - this.bind("configure.unsupportedWithRelease", version));//$NON-NLS-1$ - } - if (CompilerOptions.VERSION_1_3.equals(version)) { - if (!this.didSpecifySource) this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1); - } else if (CompilerOptions.VERSION_1_4.equals(version)) { - if (this.didSpecifySource) { - Object source = this.options.get(CompilerOptions.OPTION_Source); - if (CompilerOptions.VERSION_1_3.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2); - } else if (CompilerOptions.VERSION_1_4.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); - } - } else { - this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2); - } - } else if (CompilerOptions.VERSION_1_5.equals(version)) { - if (this.didSpecifySource) { - Object source = this.options.get(CompilerOptions.OPTION_Source); - if (CompilerOptions.VERSION_1_3.equals(source) - || CompilerOptions.VERSION_1_4.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); - } else if (CompilerOptions.VERSION_1_5.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5); - } - } else { - this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5); - } - } else if (CompilerOptions.VERSION_1_6.equals(version)) { - if (this.didSpecifySource) { - Object source = this.options.get(CompilerOptions.OPTION_Source); - if (CompilerOptions.VERSION_1_3.equals(source) - || CompilerOptions.VERSION_1_4.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); - } else if (CompilerOptions.VERSION_1_5.equals(source) - || CompilerOptions.VERSION_1_6.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); - } - } else { - this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); - } - } else if (CompilerOptions.VERSION_1_7.equals(version)) { - if (this.didSpecifySource) { - Object source = this.options.get(CompilerOptions.OPTION_Source); - if (CompilerOptions.VERSION_1_3.equals(source) - || CompilerOptions.VERSION_1_4.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); - } else if (CompilerOptions.VERSION_1_5.equals(source) - || CompilerOptions.VERSION_1_6.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); - } else if (CompilerOptions.VERSION_1_7.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7); - } - } else { - this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_7); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7); - } - } else if (CompilerOptions.VERSION_1_8.equals(version)) { - if (this.didSpecifySource) { - Object source = this.options.get(CompilerOptions.OPTION_Source); - if (CompilerOptions.VERSION_1_3.equals(source) - || CompilerOptions.VERSION_1_4.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); - } else if (CompilerOptions.VERSION_1_5.equals(source) - || CompilerOptions.VERSION_1_6.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); - } else if (CompilerOptions.VERSION_1_7.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7); - } else if (CompilerOptions.VERSION_1_8.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8); - } - } else { - this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_8); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8); - } - } else if (CompilerOptions.VERSION_9.equals(version)) { - if (this.didSpecifySource) { - Object source = this.options.get(CompilerOptions.OPTION_Source); - if (CompilerOptions.VERSION_1_3.equals(source) - || CompilerOptions.VERSION_1_4.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); - } else if (CompilerOptions.VERSION_1_5.equals(source) - || CompilerOptions.VERSION_1_6.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); - } else if (CompilerOptions.VERSION_1_7.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7); - } else if (CompilerOptions.VERSION_1_8.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8); - } else if (CompilerOptions.VERSION_9.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9); - } - } else { - this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_9); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9); - } - } else if (CompilerOptions.VERSION_10.equals(version)) { - if (this.didSpecifySource) { - Object source = this.options.get(CompilerOptions.OPTION_Source); - if (CompilerOptions.VERSION_1_3.equals(source) - || CompilerOptions.VERSION_1_4.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); - } else if (CompilerOptions.VERSION_1_5.equals(source) - || CompilerOptions.VERSION_1_6.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); - } else if (CompilerOptions.VERSION_1_7.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7); - } else if (CompilerOptions.VERSION_1_8.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8); - } else if (CompilerOptions.VERSION_9.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9); - } else if (CompilerOptions.VERSION_10.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_10); - } - } else { - this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_10); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_10); - } - } else { - if (!this.didSpecifyTarget) { - if (this.didSpecifySource) { - String source = this.options.get(CompilerOptions.OPTION_Source); - if (CompilerOptions.VERSION_1_3.equals(source) - || CompilerOptions.VERSION_1_4.equals(source)) { - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); - } else if (CompilerOptions.VERSION_1_5.equals(source) - || CompilerOptions.VERSION_1_6.equals(source)) { - this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); - } else { - // 1.3 is the lowest version that can be specified as -source - // The following check will ensure '0' is ignored. - if (CompilerOptions.versionToJdkLevel(source) >= ClassFileConstants.JDK1_7) - this.options.put(CompilerOptions.OPTION_TargetPlatform, source); - } - } else { - if (CompilerOptions.versionToJdkLevel(version) > ClassFileConstants.JDK10) { - this.options.put(CompilerOptions.OPTION_Source, version); - this.options.put(CompilerOptions.OPTION_TargetPlatform, version); - } - } - } - } - - } else if (this.didSpecifySource) { - String version = this.options.get(CompilerOptions.OPTION_Source); - // default is source 1.3 target 1.2 and compliance 1.4 - if (CompilerOptions.VERSION_1_4.equals(version)) { - if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); - } else if (CompilerOptions.VERSION_1_5.equals(version)) { - if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5); - } else if (CompilerOptions.VERSION_1_6.equals(version)) { - if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_6); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6); - } else if (CompilerOptions.VERSION_1_7.equals(version)) { - if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_7); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7); - } else if (CompilerOptions.VERSION_1_8.equals(version)) { - if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_8); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_8); - } else if (CompilerOptions.VERSION_9.equals(version)) { - if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_9); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_9); - } else if (CompilerOptions.VERSION_10.equals(version)) { - if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_10); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_10); - } else { - if (CompilerOptions.versionToJdkLevel(version) > ClassFileConstants.JDK10) { - if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, version); - if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, version); - } - } - } - - final String sourceVersion = this.options.get(CompilerOptions.OPTION_Source); - if (this.complianceLevel == 0) { - final String compliance = this.options.get(CompilerOptions.OPTION_Compliance); - this.complianceLevel = CompilerOptions.versionToJdkLevel(compliance); - } - if (sourceVersion.equals(CompilerOptions.VERSION_10) - && this.complianceLevel < ClassFileConstants.JDK10) { - // compliance must be 10 if source is 10 - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_10)); //$NON-NLS-1$ - } else if (sourceVersion.equals(CompilerOptions.VERSION_9) - && this.complianceLevel < ClassFileConstants.JDK9) { - // compliance must be 9 if source is 9 - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_9)); //$NON-NLS-1$ - } else if (sourceVersion.equals(CompilerOptions.VERSION_1_8) - && this.complianceLevel < ClassFileConstants.JDK1_8) { - // compliance must be 1.8 if source is 1.8 - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_8)); //$NON-NLS-1$ - } else if (sourceVersion.equals(CompilerOptions.VERSION_1_7) - && this.complianceLevel < ClassFileConstants.JDK1_7) { - // compliance must be 1.7 if source is 1.7 - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_7)); //$NON-NLS-1$ - } else if (sourceVersion.equals(CompilerOptions.VERSION_1_6) - && this.complianceLevel < ClassFileConstants.JDK1_6) { - // compliance must be 1.6 if source is 1.6 - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_6)); //$NON-NLS-1$ - } else if (sourceVersion.equals(CompilerOptions.VERSION_1_5) - && this.complianceLevel < ClassFileConstants.JDK1_5) { - // compliance must be 1.5 if source is 1.5 - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_5)); //$NON-NLS-1$ - } else if (sourceVersion.equals(CompilerOptions.VERSION_1_4) - && this.complianceLevel < ClassFileConstants.JDK1_4) { - // compliance must be 1.4 if source is 1.4 - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_4)); //$NON-NLS-1$ - } else { - long ver = CompilerOptions.versionToJdkLevel(sourceVersion); - if(this.complianceLevel < ver) - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForSource", this.options.get(CompilerOptions.OPTION_Compliance), sourceVersion)); //$NON-NLS-1$ - } - if (this.enablePreview && this.complianceLevel != ClassFileConstants.getLatestJDKLevel()) { - throw new IllegalArgumentException(this.bind("configure.unsupportedPreview")); //$NON-NLS-1$ - } - - // check and set compliance/source/target compatibilities - if (this.didSpecifyTarget) { - final String targetVersion = this.options.get(CompilerOptions.OPTION_TargetPlatform); - // tolerate jsr14 target - if (CompilerOptions.VERSION_JSR14.equals(targetVersion)) { - // expecting source >= 1.5 - if (CompilerOptions.versionToJdkLevel(sourceVersion) < ClassFileConstants.JDK1_5) { - throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForGenericSource", targetVersion, sourceVersion)); //$NON-NLS-1$ - } - } else if (CompilerOptions.VERSION_CLDC1_1.equals(targetVersion)) { - if (this.didSpecifySource && CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_4) { - throw new IllegalArgumentException(this.bind("configure.incompatibleSourceForCldcTarget", targetVersion, sourceVersion)); //$NON-NLS-1$ - } - if (this.complianceLevel >= ClassFileConstants.JDK1_5) { - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForCldcTarget", targetVersion, sourceVersion)); //$NON-NLS-1$ - } - } else { - // target must be 1.8 if source is 1.8 - if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_8 - && CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_8){ - throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_8)); //$NON-NLS-1$ - } - // target must be 1.7 if source is 1.7 - if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_7 - && CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_7){ - throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_7)); //$NON-NLS-1$ - } - // target must be 1.6 if source is 1.6 - if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_6 - && CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_6){ - throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_6)); //$NON-NLS-1$ - } - // target must be 1.5 if source is 1.5 - if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_5 - && CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_5){ - throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_5)); //$NON-NLS-1$ - } - // target must be 1.4 if source is 1.4 - if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_4 - && CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_4){ - throw new IllegalArgumentException(this.bind("configure.incompatibleTargetForSource", targetVersion, CompilerOptions.VERSION_1_4)); //$NON-NLS-1$ - } - // target cannot be greater than compliance level - if (this.complianceLevel < CompilerOptions.versionToJdkLevel(targetVersion)){ - throw new IllegalArgumentException(this.bind("configure.incompatibleComplianceForTarget", this.options.get(CompilerOptions.OPTION_Compliance), targetVersion)); //$NON-NLS-1$ - } - } - } -} -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java deleted file mode 100644 index 7a970f5..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/ModuleFinder.java +++ /dev/null @@ -1,308 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2016, 2020 IBM Corporation. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.eclipse.jdt.internal.compiler.batch; - -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; -import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; -import org.eclipse.jdt.internal.compiler.env.IModule; -import org.eclipse.jdt.internal.compiler.env.PackageExportImpl; -import org.eclipse.jdt.internal.compiler.env.IModule.IPackageExport; -import org.eclipse.jdt.internal.compiler.parser.Parser; -import org.eclipse.jdt.internal.compiler.util.JRTUtil; -import org.eclipse.jdt.internal.compiler.util.Util; - -public class ModuleFinder { - - public static List findModules(File f, String destinationPath, Parser parser, Map options, boolean isModulepath, String release) { - List collector = new ArrayList<>(); - scanForModules(destinationPath, parser, options, isModulepath, false, collector, f, release); - return collector; - } - - protected static FileSystem.Classpath findModule(final File file, String destinationPath, Parser parser, - Map options, boolean isModulepath, String release) { - FileSystem.Classpath modulePath = FileSystem.getClasspath(file.getAbsolutePath(), null, !isModulepath, null, - destinationPath == null ? null : (destinationPath + File.separator + file.getName()), options, release); - if (modulePath != null) { - scanForModule(modulePath, file, parser, isModulepath, release); - } - return modulePath; - } - protected static void scanForModules(String destinationPath, Parser parser, Map options, boolean isModulepath, - boolean thisAnAutomodule, List collector, final File file, String release) { - FileSystem.Classpath entry = FileSystem.getClasspath( - file.getAbsolutePath(), - null, - !isModulepath, - null, - destinationPath == null ? null : (destinationPath + File.separator + file.getName()), - options, - release); - if (entry != null) { - IModule module = scanForModule(entry, file, parser, thisAnAutomodule, release); - if (module != null) { - collector.add(entry); - } else { - if (file.isDirectory()) { - File[] files = file.listFiles(); - for (File f : files) { - scanForModules(destinationPath, parser, options, isModulepath, isModulepath, collector, f, release); - } - } - } - } - } - protected static IModule scanForModule(FileSystem.Classpath modulePath, final File file, Parser parser, boolean considerAutoModules, String release) { - IModule module = null; - if (file.isDirectory()) { - String[] list = file.list(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - if (dir == file && (name.equalsIgnoreCase(IModule.MODULE_INFO_CLASS) - || name.equalsIgnoreCase(IModule.MODULE_INFO_JAVA))) { - return true; - } - return false; - } - }); - if (list.length > 0) { - String fileName = list[0]; - switch (fileName) { - case IModule.MODULE_INFO_CLASS: - module = ModuleFinder.extractModuleFromClass(new File(file, fileName), modulePath); - break; - case IModule.MODULE_INFO_JAVA: - module = ModuleFinder.extractModuleFromSource(new File(file, fileName), parser, modulePath); - if (module == null) - return null; - String modName = new String(module.name()); - if (!modName.equals(file.getName())) { - throw new IllegalArgumentException("module name " + modName + " does not match expected name " + file.getName()); //$NON-NLS-1$ //$NON-NLS-2$ - } - break; - } - } - } else { - String moduleDescPath = getModulePathForArchive(file); - if (moduleDescPath != null) { - module = extractModuleFromArchive(file, modulePath, moduleDescPath, release); - } - } - if (considerAutoModules && module == null && !(modulePath instanceof ClasspathJrt)) { - if (!file.isDirectory()) { - String fileName = getFileName(file); - if (!fileName.isEmpty()) - module = IModule.createAutomatic(fileName, file.isFile(), getManifest(file)); - } - } - if (module != null) - modulePath.acceptModule(module); - return module; - } - private static Manifest getManifest(File file) { - if (getModulePathForArchive(file) == null) - return null; - try (JarFile jar = new JarFile(file)) { - return jar.getManifest(); - } catch (IOException e) { - String error = "Failed to read manifest from " + file; //$NON-NLS-1$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - } - return null; - } - } - private static String getFileName(File file) { - String name = file.getName(); - int index = name.lastIndexOf('.'); - if (index == -1) - return name; - return name.substring(0, index); - } - /** - * Extracts the single reads clause from the given - * command line option (--add-reads). The result is a String[] with two - * element, first being the source module and second being the target module. - * The expected format is: - * {@code --add-reads =} - * @return a String[] with source and target module of the "reads" clause. - */ - protected static String[] extractAddonRead(String option) { - StringTokenizer tokenizer = new StringTokenizer(option, "="); //$NON-NLS-1$ - String source = null; - String target = null; - if (tokenizer.hasMoreTokens()) { - source = tokenizer.nextToken(); - } else { - // Handle error - return null; - } - if (tokenizer.hasMoreTokens()) { - target = tokenizer.nextToken(); - } else { - // Handle error - return null; - } - return new String[]{source, target}; - } - /** - * Simple structure representing one --add-exports value. - */ - static class AddExport { - /** the name of the exporting module. */ - public final String sourceModuleName; - /** the export structure */ - public final IModule.IPackageExport export; - public AddExport(String moduleName, IPackageExport export) { - this.sourceModuleName = moduleName; - this.export = export; - } - } - /** - * Parses the --add-exports command line option and returns the package export definitions. - * - *

    - * The expected format is: - *

    - *

    - * {@code - * --add-exports /=(,)* - * } - *

    - * @param option the option to parse - * @return an {@link AddExport} structure. - */ - protected static AddExport extractAddonExport(String option) { - StringTokenizer tokenizer = new StringTokenizer(option, "/"); //$NON-NLS-1$ - String source = null; - String pack = null; - List targets = new ArrayList<>(); - if (tokenizer.hasMoreTokens()) { - source = tokenizer.nextToken("/"); //$NON-NLS-1$ - } else { - // Handle error - return null; - } - if (tokenizer.hasMoreTokens()) { - pack = tokenizer.nextToken("/="); //$NON-NLS-1$ - } else { - // Handle error - return null; - } - while (tokenizer.hasMoreTokens()) { - targets.add(tokenizer.nextToken("=,")); //$NON-NLS-1$ - } - PackageExportImpl export = new PackageExportImpl(); - export.pack = pack.toCharArray(); - export.exportedTo = new char[targets.size()][]; - for(int i = 0; i < export.exportedTo.length; i++) { - export.exportedTo[i] = targets.get(i).toCharArray(); - } - return new AddExport(source, export); - } - - private static String getModulePathForArchive(File file) { - int format = Util.archiveFormat(file.getAbsolutePath()); - if (format == Util.ZIP_FILE) { - return IModule.MODULE_INFO_CLASS; - } else if(format == Util.JMOD_FILE) { - return "classes/" + IModule.MODULE_INFO_CLASS; //$NON-NLS-1$ - } - return null; - } - private static IModule extractModuleFromArchive(File file, Classpath pathEntry, String path, String release) { - try (ZipFile zipFile = new ZipFile(file)) { - if (release != null) { - String releasePath = "META-INF/versions/" + release + "/" + path; //$NON-NLS-1$ //$NON-NLS-2$ - ZipEntry entry = zipFile.getEntry(releasePath); - if (entry != null) { - path = releasePath; - } - } - ClassFileReader reader = ClassFileReader.read(zipFile, path); - IModule module = getModule(reader); - if (module != null) { - return reader.getModuleDeclaration(); - } - return null; - } catch (ClassFormatException e) { - // Nothing to be done here - } catch (IOException e) { - String error = "Failed to read module for path " + path + " and release " + release + " from " + file; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - } - } - return null; - } - private static IModule extractModuleFromClass(File classfilePath, Classpath pathEntry) { - ClassFileReader reader; - try { - reader = ClassFileReader.read(classfilePath); - IModule module = getModule(reader); - if (module != null) { - return reader.getModuleDeclaration(); - } - return null; - } catch (ClassFormatException e) { - e.printStackTrace(); - } catch (IOException e) { - String error = "Failed to read module from " + classfilePath; //$NON-NLS-1$ - if (JRTUtil.PROPAGATE_IO_ERRORS) { - throw new IllegalStateException(error, e); - } else { - System.err.println(error); - e.printStackTrace(); - } - } - return null; - } - private static IModule getModule(ClassFileReader classfile) { - if (classfile != null) { - return classfile.getModuleDeclaration(); - } - return null; - } - private static IModule extractModuleFromSource(File file, Parser parser, Classpath pathEntry) { - CompilationUnit cu = new CompilationUnit(null, file.getAbsolutePath(), null, pathEntry.getDestinationPath()); - CompilationResult compilationResult = new CompilationResult(cu, 0, 1, 10); - CompilationUnitDeclaration unit = parser.parse(cu, compilationResult); - if (unit.isModuleInfo() && unit.moduleDeclaration != null) { - cu.module = unit.moduleDeclaration.moduleName; - return new BasicModule(unit.moduleDeclaration, pathEntry); - } - return null; - } -} diff --git a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/messages.properties b/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/messages.properties deleted file mode 100644 index 4a2fa61..0000000 --- a/compiler/src/main/ecj/org/eclipse/jdt/internal/compiler/batch/messages.properties +++ /dev/null @@ -1,515 +0,0 @@ -############################################################################### -# Copyright (c) 2000, 2023 IBM Corporation and others. -# -# This program and the accompanying materials -# are made available under the terms of the Eclipse Public License 2.0 -# which accompanies this distribution, and is available at -# https://www.eclipse.org/legal/epl-2.0/ -# -# SPDX-License-Identifier: EPL-2.0 -# -# 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" -# bug 365208 - [compiler][batch] command line options for annotation based null analysis -# bug 374605 - Unreasonable warning for enum-based switch statements -# bug 388281 - [compiler][null] inheritance of null annotations as an option -# bug 440687 - [compiler][batch][null] improve command line option for external annotations -# Bug 408815 - [batch][null] Add CLI option for COMPILER_PB_SYNTACTIC_NULL_ANALYSIS_FOR_FIELDS -# Alan Moraes - Contribution for bug 383644 -# Jesper S Moller - Contribution for bug 407297 - [1.8][compiler] Control generation of parameter names by option -############################################################################### -### JavaBatchCompiler messages. - -### compiler -#Format: compiler.name = word1 word2 word3 -compiler.name = Eclipse Compiler for Java(TM) -#Format: compiler.version = (The place holders will be automatically filled. Do not remove or alter it) -compiler.version = bundle_qualifier, bundle_version -compiler.copyright = Copyright IBM Corp 2000, 2020. All rights reserved. - -### progress -progress.compiling = Compiling - -### compile -compile.repetition = [repetition {0}/{1}] -compile.instantTime = [compiled {0} lines in {1} ms: {2} lines/s] -compile.detailedTime = [parse: {0} ms ({1}%), resolve: {2} ms ({3}%), analyze: {4} ms ({5}%), generate: {6} ms ({7}%) ] -compile.ioTime = [i/o: read: {0} ms ({1}%), write: {2} ms ({3}%)] -compile.averageTime = [average, excluding min-max {0} lines in {1} ms: {2} lines/s] -compile.totalTime = [total compilation time: {0}] -compile.oneProblem = 1 problem ({0}) -compile.severalProblemsErrorsOrWarnings = {0} problems ({1}) -compile.severalProblemsErrorsAndWarnings = {0} problems ({1}, {2}) -compile.severalProblems = {0} problems ({1}, {2}, {3}) -compile.oneError = 1 error -compile.severalErrors = {0} errors -compile.oneWarning = 1 warning -compile.severalWarnings = {0} warnings -compile.oneInfo = 1 info -compile.severalInfos = {0} infos -compile.oneClassFileGenerated = [1 .class file generated] -compile.severalClassFilesGenerated = [{0} .class files generated] -compile.failOnWarning = error: warnings found and -failOnWarning specified - -### configure -configure.requiresJDK1.2orAbove = Need to use a JVM >= 1.2 -configure.duplicateLog = duplicate log specification: {0} -configure.duplicateRepeat = duplicate repeat specification: {0} -configure.duplicateMaxProblems = duplicate max problems specification: {0} -configure.duplicateCompliance = duplicate compliance setting specification: {0} -configure.duplicateSource = duplicate source compliance setting specification: {0} -configure.duplicateTarget = duplicate target compliance setting specification: {0} -configure.unsupportedReleaseOption = option --release is supported only when run with JDK 9 or above -configure.unsupportedWithRelease = option {0} is not supported when --release is used -configure.unsupportedReleaseVersion = release version {0} is not supported -configure.source = source level should be in ''1.1''...''1.8'',''9''...''21'' (or ''5.0''..''21.0''): {0} -configure.invalidSystem = invalid location for system libraries: {0} -configure.unsupportedOption = option {0} not supported at compliance level 9 and above -configure.duplicateOutputPath = duplicate output path specification: {0} -configure.duplicateModuleInfo = duplicate module descriptor file: {0} -configure.duplicateModulePath = duplicate module path specification: {0} -configure.duplicateModuleSourcepath = duplicate source module path specification: {0} -configure.invalidModuleDescriptor = cannot open the module descriptor from {0} -configure.invalidModuleOption = incorrectly formatted option: {0} -configure.duplicateExport = can specify a package in a module only once with --add-export -configure.OneOfModuleOrSourcePath = cannot specify both -source-path and --module-source-path -configure.duplicateBootClasspath = duplicate bootclasspath specification: {0} -configure.duplicateExtDirs = duplicate extdirs specification: {0} -configure.duplicateSourcepath = duplicate sourcepath specification: {0} -configure.invalidDebugOption = invalid debug option: {0} -configure.invalidWarningConfiguration = invalid warning configuration: ''{0}'' -configure.invalidWarning = invalid warning token: ''{0}''. Ignoring warning and compiling -configure.invalidWarningOption = invalid warning option: ''{0}''. Must specify a warning token -configure.targetJDK = target level should be in ''1.1''...''1.8'',''9''...''21'' (or ''5.0''..''21.0'') or cldc1.1: {0} -configure.incompatibleTargetForSource = Target level ''{0}'' is incompatible with source level ''{1}''. A target level ''{1}'' or better is required -configure.incompatibleTargetForGenericSource = Target level ''{0}'' is incompatible with source level ''{1}''. A source level ''1.5'' or better is required -configure.incompatibleComplianceForSource = Compliance level ''{0}'' is incompatible with source level ''{1}''. A compliance level ''{1}'' or better is required -configure.incompatibleComplianceForTarget = Compliance level ''{0}'' is incompatible with target level ''{1}''. A compliance level ''{1}'' or better is required -configure.repetition = repetition must be a positive integer: {0} -configure.maxProblems = max problems must be a positive integer: {0} -configure.invalidNowarnOption = invalid syntax for nowarn option: {0} -configure.unsupportedPreview = Preview of features is supported only at the latest source level - -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.invalidInfoConfiguration = invalid info configuration: ''{0}'' -configure.invalidInfo = invalid info token: ''{0}''. Ignoring this info token and compiling -configure.invalidInfoOption = invalid info option: ''{0}''. Must specify an info token - -configure.notOnModuleSourcePath = ''{0}'' does not belong to a module on the module source path -configure.no.ModuleDescriptorVersionparse = Could not invoke method java.lang.module.ModuleDescriptor.Version.parse(), cannot validate module version. - -## configure.directoryNotExist = directory does not exist: {0} -configure.unrecognizedOption = Unrecognized option : {0} -configure.noClasspath = no classpath defined, using default directory instead -configure.incorrectClasspath = incorrect classpath: {0} -configure.invalidexpansionargumentname = expansion argument file {0} does not exist or cannot be read -configure.cannotOpenLog = cannot open .log file: {0} -configure.cannotOpenLogInvalidEncoding = cannot open .log file: {0}; because UTF-8 is not supported -configure.unexpectedCustomEncoding = unexpected custom encoding specification: {0}[{1}] -configure.unsupportedEncoding = unsupported encoding format: {0} -configure.duplicateDefaultEncoding = duplicate default encoding format specification: {0} -configure.invalidTaskTag ={0} is an invalid task tag -configure.incorrectExtDirsEntry = incorrect ext dir entry; {0} must be a directory -configure.incorrectEndorsedDirsEntry = incorrect endorsed dir entry; {0} must be a directory -configure.duplicateEndorsedDirs = duplicate endorseddirs specification: {0} -configure.missingDestinationPath = destination path must be provided with module source path -configure.incorrectDestinationPathEntry = incorrect destination path entry: {0} -configure.unexpectedBracket = unexpected bracket: {0} -configure.unexpectedDestinationPathEntry = unexpected destination path entry in {0} option -configure.unexpectedDestinationPathEntryFile = unexpected destination path entry for file: {0} -configure.accessRuleAfterDestinationPath = access rules cannot follow destination path entries: {0} -configure.duplicateDestinationPathEntry = duplicate destination path entry in {0} option -configure.invalidClassName = invalid class name: {0} -configure.invalidModuleName = invalid module name: {0} -configure.packageConflict = The package {0} is accessible from more than one module: {1}, {2} -configure.unavailableAPT = Unable to load annotation processing manager {0} from classpath. -configure.incorrectVMVersionforAPT = Annotation processing got disabled, since it requires a 1.6 compliant JVM -configure.incompatibleSourceForCldcTarget=Target level ''{0}'' is incompatible with source level ''{1}''. A source level ''1.3'' or lower is required -configure.incompatibleComplianceForCldcTarget=Target level ''{0}'' is incompatible with compliance level ''{1}''. A compliance level ''1.4''or lower is required -configure.invalidClasspathSection = invalid Class-Path header in manifest of jar file: {0} -configure.multipleClasspathSections = multiple Class-Path headers in manifest of jar file: {0} -configure.missingwarningspropertiesfile=properties file {0} does not exist -configure.ioexceptionwarningspropertiesfile=An IOException occurred while reading the properties file {0} -configure.multipleencodings=Multiple encoding specified: {1}. The default encoding has been set to {0} -configure.differentencodings=Found encoding {0}. Different encodings were specified: {1} -configure.differentencoding=Found encoding {0}. A different encoding was specified: {1} -configure.illegalExportFromSystemModule=Exporting a package from system module ''{0}'' is not allowed with --release - -### null annotations -configure.invalidNullAnnot = Token {0} is not in the expected format "nullAnnot( | | )" -configure.missingAnnotationPath = Missing argument to -annotationpath at ''{0}'' - -### requestor -requestor.error = {0}. ERROR in {1} -requestor.warning = {0}. WARNING in {1} -requestor.info = {0}. INFO in {1} -requestor.extraerror = {0}. ERROR: -requestor.extrawarning = {0}. WARNING: -requestor.extrainfo = {0}. INFO: -requestor.notRetrieveErrorMessage = Cannot retrieve the error message for {0} -requestor.noFileNameSpecified = (original file name is not available) - -### EMACS STYLE -output.emacs.error=error -output.emacs.warning=warning -output.emacs.info=info - -### unit -unit.more = File {0} is specified more than once -unit.missing = File {0} is missing - -### output -output.noClassFileCreated = No .class file created for file {1} in {0} because of an IOException: {2} - -### miscellaneous -misc.version = {0} {1}, {2} -misc.usage = {1} {2}\n\ -{3}\n\ -\ \n\ -\ Usage: \n\ -\ If directories are specified, then their source contents are compiled.\n\ -\ Possible options are listed below. Options enabled by default are prefixed\n\ -\ with ''+''.\n\ -\ \n\ -\ Classpath options:\n\ -\ -cp -classpath \n\ -\ specify location for application classes and sources.\n\ -\ Each directory or file can specify access rules for\n\ -\ types between ''['' and '']'' (e.g. [-X] to forbid\n\ -\ access to type X, [~X] to discourage access to type X,\n\ -\ [+p/X{0}-p/*] to forbid access to all types in package p\n\ -\ but allow access to p/X)\n\ -\ -bootclasspath \n\ -\ specify location for system classes. Each directory or\n\ -\ file can specify access rules for types between ''[''\n\ -\ and '']''\n\ -\ -sourcepath \n\ -\ specify location for application sources. Each directory\n\ -\ or file can specify access rules for types between ''[''\n\ -\ and '']''. Each directory can further specify a specific\n\ -\ destination directory using a ''-d'' option between ''[''\n\ -\ and '']''; this overrides the general ''-d'' option.\n\ -\ .class files created from source files contained in a\n\ -\ jar file are put in the user.dir folder in case no\n\ -\ general ''-d'' option is specified. ZIP archives cannot\n\ -\ override the general ''-d'' option\n\ -\ -extdirs \n\ -\ specify location for extension ZIP archives\n\ -\ -endorseddirs \n\ -\ specify location for endorsed ZIP archives\n\ -\ -d destination directory (if omitted, no directory is\n\ -\ created); this option can be overridden per source\n\ -\ directory\n\ -\ -d none generate no .class files\n\ -\ -encoding specify default encoding for all source files. Each\n\ -\ file/directory can override it when suffixed with\n\ -\ ''['''']'' (e.g. X.java[utf8]).\n\ -\ If multiple default encodings are specified, the last\n\ -\ one will be used.\n\ -\ \n\ -\ Module compilation options:\n\ -\ These options are meaningful only in Java 9 environment or later.\n\ -\ --module-source-path \n\ -\ specify where to find source files for multiple modules\n\ -\ -p --module-path \n\ -\ specify where to find application modules\n\ -\ --processor-module-path \n\ -\ specify module path where annotation processors\n\ -\ can be found\n\ -\ --system Override location of system modules\n\ -\ --add-exports /=(,)*\n\ -\ specify additional package exports clauses to the\n\ -\ given modules\n\ -\ --add-reads =(,)*\n\ -\ specify additional modules to be considered as required\n\ -\ by given modules\n\ -\ --add-modules (,)*\n\ -\ specify the additional module names that should be\n\ -\ resolved to be root modules\n\ -\ --limit-modules (,)*\n\ -\ specify the observable module names\n\ -\ --release compile for a specific VM version\n\ -\ \n\ -\ Compliance options:\n\ -\ -1.3 use 1.3 compliance (-source 1.3 -target 1.1)\n\ -\ -1.4 + use 1.4 compliance (-source 1.3 -target 1.2)\n\ -\ -1.5 -5 -5.0 use 1.5 compliance (-source 1.5 -target 1.5)\n\ -\ -1.6 -6 -6.0 use 1.6 compliance (-source 1.6 -target 1.6)\n\ -\ -1.7 -7 -7.0 use 1.7 compliance (-source 1.7 -target 1.7)\n\ -\ -1.8 -8 -8.0 use 1.8 compliance (-source 1.8 -target 1.8)\n\ -\ -1.9 -9 -9.0 use 1.9 compliance (-source 1.9 -target 1.9)\n\ -\ -10 -10.0 use 10 compliance (-source 10 -target 10)\n\ -\ -11 -11.0 use 11 compliance (-source 11 -target 11)\n\ -\ -12 -12.0 use 12 compliance (-source 12 -target 12)\n\ -\ -13 -13.0 use 13 compliance (-source 13 -target 13)\n\ -\ -14 -14.0 use 14 compliance (-source 14 -target 14)\n\ -\ -15 -15.0 use 15 compliance (-source 15 -target 15)\n\ -\ -16 -16.0 use 16 compliance (-source 16 -target 16)\n\ -\ -17 -17.0 use 17 compliance (-source 17 -target 17)\n\ -\ -18 -18.0 use 18 compliance (-source 18 -target 18)\n\ -\ -19 -19.0 use 19 compliance (-source 19 -target 19)\n\ -\ -20 -20.0 use 20 compliance (-source 20 -target 20)\n\ -\ -21 -21.0 use 21 compliance (-source 21 -target 21)\n\ -\ -source set source level: 1.3 to 1.9, 10 to 21\n\ -\ (or 6, 6.0, etc)\n\ -\ -target set classfile target: 1.3 to 1.9, 10 to 21\n\ -\ (or 6, 6.0, etc)\n\ -\ cldc1.1 can also be used to generate the StackMap\n\ -\ attribute\n\ -\ --enable-preview enable support for preview features of the\n\ -\ latest Java release\n\ -\ \n\ -\ Warning options:\n\ -\ -deprecation + deprecation outside deprecated code (equivalent to\n\ -\ -warn:+deprecation)\n\ -\ -nowarn -warn:none disable all warnings\n\ -\ -nowarn:[]\n\ -\ specify directories from which optional problems should\n\ -\ be ignored\n\ -\ -?:warn -help:warn display advanced warning options\n\ -\ \n\ -\ Error options:\n\ -\ -err: convert exactly the listed warnings\n\ -\ to be reported as errors\n\ -\ -err:+ enable additional warnings to be\n\ -\ reported as errors\n\ -\ -err:- disable specific warnings to be\n\ -\ reported as errors\n\ -\ \n\ -\ Info options:\n\ -\ -info: convert exactly the listed warnings\n\ -\ to be reported as infos\n\ -\ -info:+ enable additional warnings to be\n\ -\ reported as infos\n\ -\ -info:- disable specific warnings to be\n\ -\ reported as infos\n\ -\ \n\ -\ Setting warning, error or info options using properties file:\n\ -\ -properties set warnings/errors/info option based on the properties\n\ -\ file contents. This option can be used with -nowarn,\n\ -\ -err:.., -info: or -warn:.. options, but the last one\n\ -\ on the command line sets the options to be used.\n\ -\ \n\ -\ Debug options:\n\ -\ -g[:lines,vars,source] custom debug info\n\ -\ -g:lines,source + both lines table and source debug info\n\ -\ -g all debug info\n\ -\ -g:none no debug info\n\ -\ -preserveAllLocals preserve unused local vars for debug purpose\n\ -\ \n\ -\ Annotation processing options:\n\ -\ These options are meaningful only in a 1.6 environment.\n\ -\ -Akey[=value] options that are passed to annotation processors\n\ -\ -processorpath \n\ -\ specify locations where to find annotation processors.\n\ -\ If this option is not used, the classpath will be\n\ -\ searched for processors\n\ -\ -processor \n\ -\ qualified names of the annotation processors to run.\n\ -\ This bypasses the default annotation discovery process\n\ -\ -proc:only run annotation processors, but do not compile\n\ -\ -proc:none perform compilation but do not run annotation\n\ -\ processors\n\ -\ -s destination directory for generated source files\n\ -\ -XprintProcessorInfo print information about which annotations and elements\n\ -\ a processor is asked to process\n\ -\ -XprintRounds print information about annotation processing rounds\n\ -\ -classNames \n\ -\ qualified names of binary classes to process\n\ -\ \n\ -\ Advanced options:\n\ -\ @ read command line arguments from file\n\ -\ -maxProblems max number of problems per compilation unit (100 by\n\ -\ default)\n\ -\ -log log to a file. If the file extension is ''.xml'', then\n\ -\ the log will be a xml file.\n\ -\ -proceedOnError[:Fatal]\n\ -\ do not stop at first error, dumping class files with\n\ -\ problem methods\n\ -\ With ":Fatal", all optional errors are treated as fatal\n\ -\ -failOnWarning fail compilation if there are warnings\n\ -\ -verbose enable verbose output\n\ -\ -referenceInfo compute reference info\n\ -\ -progress show progress (only in -log mode)\n\ -\ -time display speed information \n\ -\ -noExit do not call System.exit(n) at end of compilation (n==0\n\ -\ if no error)\n\ -\ -repeat repeat compilation process times for perf analysis\n\ -\ -inlineJSR inline JSR bytecode (implicit if target >= 1.5)\n\ -\ -enableJavadoc consider references in javadoc\n\ -\ -parameters generate method parameters attribute (for target >= 1.8)\n\ -\ -genericsignature generate generic signature for lambda expressions\n\ -\ -Xemacs used to enable emacs-style output in the console.\n\ -\ It does not affect the xml log output\n\ -\ -missingNullDefault report missing default nullness annotation\n\ -\ -annotationpath \n\ -\ specify locations where to find external annotations\n\ -\ to support annotation-based null analysis.\n\ -\ The special name CLASSPATH will cause lookup of\n\ -\ external annotations from the classpath and sourcepath.\n\ -\ \n\ -\ -? -help print this help message\n\ -\ -v -version print compiler version\n\ -\ -showversion print compiler version and continue\n\ -\ \n\ -\ Ignored options:\n\ -\ -J