Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2015-12-08 18:38:48 +0000
committerStephan Herrmann2015-12-08 18:38:48 +0000
commitd1a89d726f70e4e87570ae93c703b6ccb95d1980 (patch)
tree84266cfcf9d82aba32000218bc51d927c3d2cb68 /org.eclipse.jdt.core
parent78f7dfc554cc396c300f5e2309fef78cc569d57e (diff)
downloadorg.eclipse.objectteams-d1a89d726f70e4e87570ae93c703b6ccb95d1980.tar.gz
org.eclipse.objectteams-d1a89d726f70e4e87570ae93c703b6ccb95d1980.tar.xz
org.eclipse.objectteams-d1a89d726f70e4e87570ae93c703b6ccb95d1980.zip
Update jdt.core & tests to I20151208-0800 for 4.6 M4
Diffstat (limited to 'org.eclipse.jdt.core')
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java1
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java3
-rw-r--r--org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java33
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java146
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/RelevanceConstants.java3
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java13
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java4
-rw-r--r--org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLambdaExpression.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java378
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java13
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java17
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java59
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java21
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java11
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java5
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java6
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java10
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Invocation.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java77
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java17
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java164
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java5
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java18
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java3
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java10
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java26
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java10
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java5
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java51
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java4
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java34
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java116
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java11
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java34
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java43
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java23
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java49
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java13
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java2
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java15
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java16
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java7
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java37
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java12
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java40
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java23
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java9
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java10
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java8
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java21
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java23
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java13
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java21
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java108
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java20
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java57
-rw-r--r--org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties3
-rw-r--r--org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java18
-rw-r--r--org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java61
-rw-r--r--org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java137
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java12
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java402
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java15
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java71
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java42
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java4
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java22
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java17
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java21
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java43
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java15
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java16
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java1
-rw-r--r--org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties3
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java171
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java4
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java1248
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameMatchRequestorWrapper.java19
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java5
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java115
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java9
-rw-r--r--org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java148
93 files changed, 2984 insertions, 1577 deletions
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
index 642389111..5b6749306 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/ClasspathDirectory.java
@@ -60,6 +60,7 @@ 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) {
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
index b14620061..b6d9e5f01 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/FileSystem.java
@@ -157,6 +157,9 @@ protected FileSystem(Classpath[] paths, String[] initialFileNames, boolean annot
initializeKnownFileNames(initialFileNames);
this.annotationsFromClasspath = annotationsFromClasspath;
}
+public static Classpath getClasspath(String classpathName, String encoding, AccessRuleSet accessRuleSet) {
+ return getClasspath(classpathName, encoding, false, accessRuleSet, null, null);
+}
public static Classpath getClasspath(String classpathName, String encoding, AccessRuleSet accessRuleSet, Map options) {
return getClasspath(classpathName, encoding, false, accessRuleSet, null, options);
}
diff --git a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
index 3f4b63bdc..b08b3a2cb 100644
--- a/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
+++ b/org.eclipse.jdt.core/batch/org/eclipse/jdt/internal/compiler/batch/Main.java
@@ -1397,6 +1397,7 @@ public class Main implements ProblemSeverities, SuffixConstants {
private File javaHomeCache;
private boolean javaHomeChecked = false;
+ private boolean primaryNullAnnotationsSeen = false;
public long lineCount0;
public String log;
@@ -3866,20 +3867,40 @@ private void handleErrorOrWarningToken(String token, boolean isEnabling, int sev
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 (nullableAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$
+ 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 (nonNullAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$
+ if (isPrimarySet && nonNullAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$
nonNullByDefaultAnnotName = annotationNames.substring(separator2 + 1).trim();
- if (nonNullByDefaultAnnotName.length() == 0) throw new IllegalArgumentException(this.bind("configure.invalidNullAnnot", token)); //$NON-NLS-1$
- this.options.put(CompilerOptions.OPTION_NullableAnnotationName, nullableAnnotName);
- this.options.put(CompilerOptions.OPTION_NonNullAnnotationName, nonNullAnnotName);
- this.options.put(CompilerOptions.OPTION_NonNullByDefaultAnnotationName, nonNullByDefaultAnnotName);
+ 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,
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
index fb9b0fae9..acdc1b57b 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java
@@ -6,11 +6,14 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
+ * Timo Kinnunen - Contributions for bug 377373 - [subwords] known limitations with JDT 3.8
+ * Bug 420953 - [subwords] Constructors that don't match prefix not found
* IBM Corporation - initial API and implementation
* Fraunhofer FIRST - extended API and implementation
* Technical University Berlin - extended 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)
+ * Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions
*******************************************************************************/
package org.eclipse.jdt.internal.codeassist;
@@ -4247,24 +4250,17 @@ public final class CompletionEngine
return 0;
}
int computeRelevanceForCaseMatching(char[] token, char[] proposalName){
- if (this.options.camelCaseMatch) {
- if(CharOperation.equals(token, proposalName, true /* do not ignore case */)) {
- return R_CASE + R_EXACT_NAME;
- } else if (CharOperation.prefixEquals(token, proposalName, true /* do not ignore case */)) {
+ if(CharOperation.equals(token, proposalName, true)) {
+ return R_EXACT_NAME + R_CASE;
+ } else if(CharOperation.equals(token, proposalName, false)) {
+ return R_EXACT_NAME;
+ } else if (CharOperation.prefixEquals(token, proposalName, false)) {
+ if (CharOperation.prefixEquals(token, proposalName, true))
return R_CASE;
- } else if (CharOperation.camelCaseMatch(token, proposalName)){
+ } else if (this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, proposalName)){
return R_CAMEL_CASE;
- } else if(CharOperation.equals(token, proposalName, false /* ignore case */)) {
- return R_EXACT_NAME;
- }
- } else if (CharOperation.prefixEquals(token, proposalName, true /* do not ignore case */)) {
- if(CharOperation.equals(token, proposalName, true /* do not ignore case */)) {
- return R_CASE + R_EXACT_NAME;
- } else {
- return R_CASE;
- }
- } else if(CharOperation.equals(token, proposalName, false /* ignore case */)) {
- return R_EXACT_NAME;
+ } else if (this.options.substringMatch && CharOperation.substringMatch(token, proposalName)) {
+ return R_SUBSTRING;
}
return 0;
}
@@ -5056,8 +5052,7 @@ public final class CompletionEngine
nextAttribute: for (int i = 0; i < methods.length; i++) {
MethodBinding method = methods[i];
- if(!CharOperation.prefixEquals(token, method.selector, false)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, method.selector))) continue nextAttribute;
+ if(isFailedMatch(token, method.selector)) continue nextAttribute;
int length = attributesFound == null ? 0 : attributesFound.length;
for (int j = 0; j < length; j++) {
@@ -5996,8 +5991,7 @@ public final class CompletionEngine
if (enumConstantLength > field.name.length) continue next;
- if (!CharOperation.prefixEquals(enumConstantName, field.name, false /* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(enumConstantName, field.name))) continue next;
+ if (isFailedMatch(enumConstantName, field.name)) continue next;
char[] fieldName = field.name;
@@ -6185,8 +6179,7 @@ public final class CompletionEngine
if (typeName.length > exceptionType.sourceName.length)
return;
- if (!CharOperation.prefixEquals(typeName, exceptionType.sourceName, false/* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, exceptionType.sourceName)))
+ if (isFailedMatch(typeName, exceptionType.sourceName))
return;
if (this.options.checkDeprecation &&
@@ -6518,16 +6511,18 @@ public final class CompletionEngine
if (fieldBeingCompletedId >= 0 && field.id >= fieldBeingCompletedId) {
// Don't propose field which is being declared currently
// Don't propose fields declared after the current field declaration statement
- // Though, if field is static, then it can be still be proposed
- if (!field.isStatic()) {
- continue next;
- } else if (isFieldBeingCompletedStatic) {
- // static fields can't be proposed before they are actually declared if the
- // field currently being declared is also static
- continue next;
+ // Though, if field is static or completion happens in Javadoc, then it can be still be proposed
+ if (this.assistNodeInJavadoc == 0) {
+ if (!field.isStatic()) {
+ continue next;
+ } else if (isFieldBeingCompletedStatic) {
+ // static fields can't be proposed before they are actually declared if the
+ // field currently being declared is also static
+ continue next;
+ }
}
}
-
+
//{ObjectTeams: filter out generated fields
if (!canBeCompleted(field.name)) continue next;
//carp}
@@ -6537,8 +6532,7 @@ public final class CompletionEngine
if (fieldLength > field.name.length) continue next;
- if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name))) continue next;
+ if (isFailedMatch(fieldName, field.name)) continue next;
if (this.options.checkDeprecation &&
field.isViewedAsDeprecated() &&
@@ -7915,8 +7909,7 @@ public final class CompletionEngine
if (fieldLength > field.name.length) continue next;
- if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name))) continue next;
+ if (isFailedMatch(fieldName, field.name)) continue next;
if (this.options.checkDeprecation &&
field.isViewedAsDeprecated() &&
@@ -8156,8 +8149,7 @@ public final class CompletionEngine
if (typeLength > memberType.sourceName.length)
continue next;
- if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false/* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, memberType.sourceName)))
+ if (isFailedMatch(typeName, memberType.sourceName))
continue next;
if (this.options.checkDeprecation && memberType.isViewedAsDeprecated()) continue next;
@@ -8213,8 +8205,7 @@ public final class CompletionEngine
if (!field.isStatic())
continue next;
- if (!CharOperation.prefixEquals(fieldName, field.name, false/* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name)))
+ if (isFailedMatch(fieldName, field.name))
continue next;
if (this.options.checkDeprecation && field.isViewedAsDeprecated()) continue next;
@@ -8278,8 +8269,7 @@ public final class CompletionEngine
if (methodLength > method.selector.length)
continue next;
- if (!CharOperation.prefixEquals(methodName, method.selector, false/* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector)))
+ if (isFailedMatch(methodName, method.selector))
continue next;
int length = method.parameters.length;
@@ -8815,8 +8805,7 @@ public final class CompletionEngine
if (methodLength > method.selector.length)
continue next;
- if (!CharOperation.prefixEquals(methodName, method.selector, false/* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector)))
+ if (isFailedMatch(methodName, method.selector))
continue next;
}
//{ObjectTeams: different methods may produce different completion kinds
@@ -9030,8 +9019,7 @@ public final class CompletionEngine
}
} else {
if (methodLength > method.selector.length) continue next;
- if (!CharOperation.prefixEquals(methodName, method.selector, false /* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector))) {
+ if (isFailedMatch(methodName, method.selector)) {
continue next;
}
}
@@ -9129,14 +9117,14 @@ public final class CompletionEngine
//{ObjectTeams: offset
/* orig:
- for (int i = 0; i < length; i++) {
+ for (int i = 0; i < length; i++) {
:giro */
- for (int i = offset; i < length; i++) {
+ for (int i = offset; i < length; i++) {
// SH}
- TypeBinding type = method.original().parameters[i];
- parameterPackageNames[i] = type.qualifiedPackageName();
- parameterTypeNames[i] = type.qualifiedSourceName();
- }
+ TypeBinding type = method.original().parameters[i];
+ parameterPackageNames[i] = type.qualifiedPackageName();
+ parameterTypeNames[i] = type.qualifiedSourceName();
+ }
//{ObjectTeams: offset:
/* orig:
char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);
@@ -9433,8 +9421,7 @@ public final class CompletionEngine
if (methodLength > method.selector.length) continue next;
- if (!CharOperation.prefixEquals(methodName, method.selector, false /* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector))) {
+ if (isFailedMatch(methodName, method.selector)) {
continue next;
}
@@ -9736,11 +9723,11 @@ public final class CompletionEngine
char[][] parameterPackageNames = new char[length][];
char[][] parameterTypeNames = new char[length][];
- for (int i = 0; i < length; i++) {
- TypeBinding type = method.original().parameters[i];
- parameterPackageNames[i] = type.qualifiedPackageName();
- parameterTypeNames[i] = type.qualifiedSourceName();
- }
+ for (int i = 0; i < length; i++) {
+ TypeBinding type = method.original().parameters[i];
+ parameterPackageNames[i] = type.qualifiedPackageName();
+ parameterTypeNames[i] = type.qualifiedSourceName();
+ }
char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);
char[] completion = CharOperation.NO_CHAR;
@@ -10171,8 +10158,7 @@ public final class CompletionEngine
if (typeLength > memberType.sourceName.length)
continue next;
- if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false/* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, memberType.sourceName)))
+ if (isFailedMatch(typeName, memberType.sourceName))
continue next;
//{ObjectTeams: don't surface __OT__ names:
if (!canTypeBeCompleted(memberType.sourceName))
@@ -10687,6 +10673,7 @@ public final class CompletionEngine
boolean hasPotentialDefaultAbstractMethods = true;
boolean java8Plus = this.compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8;
while (currentType != null) {
+
//{ObjectTeams: don't let availableMethods() look in the interface part!
currentType = currentType.getRealClass();
// SH}
@@ -10823,8 +10810,7 @@ public final class CompletionEngine
if (typeLength > localType.sourceName.length)
continue next;
- if (!CharOperation.prefixEquals(typeName, localType.sourceName, false/* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, localType.sourceName)))
+ if (isFailedMatch(typeName, localType.sourceName))
continue next;
for (int j = typesFound.size; --j >= 0;) {
@@ -11209,8 +11195,7 @@ public final class CompletionEngine
if (typeLength > typeParameter.name.length) continue;
- if (!CharOperation.prefixEquals(token, typeParameter.name, false)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, typeParameter.name))) continue;
+ if (isFailedMatch(token, typeParameter.name)) continue;
int relevance = computeBaseRelevance();
relevance += computeRelevanceForResolution();
@@ -11318,8 +11303,7 @@ public final class CompletionEngine
if (typeLength > sourceType.sourceName.length) continue next;
- if (!CharOperation.prefixEquals(token, sourceType.sourceName, false)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, sourceType.sourceName))) continue next;
+ if (isFailedMatch(token, sourceType.sourceName)) continue next;
if (this.assistNodeIsAnnotation && !hasPossibleAnnotationTarget(sourceType, scope)) {
continue next;
@@ -11697,8 +11681,7 @@ public final class CompletionEngine
if (typeLength > 0) {
if (typeLength > refBinding.sourceName.length) continue next;
- if (!CharOperation.prefixEquals(token, refBinding.sourceName, false)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, refBinding.sourceName))) continue next;
+ if (isFailedMatch(token, refBinding.sourceName)) continue next;
}
@@ -11864,8 +11847,7 @@ public final class CompletionEngine
if (typeLength > typeBinding.sourceName.length) continue next;
- if (!CharOperation.prefixEquals(token, typeBinding.sourceName, false)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, typeBinding.sourceName))) continue next;
+ if (isFailedMatch(token, typeBinding.sourceName)) continue next;
int accessibility = IAccessRule.K_ACCESSIBLE;
if(typeBinding.hasRestrictedAccess()) {
@@ -11989,8 +11971,7 @@ public final class CompletionEngine
if (typeLength > typeBinding.sourceName.length) continue;
- if (!CharOperation.prefixEquals(token, typeBinding.sourceName, false)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, typeBinding.sourceName))) continue;
+ if (isFailedMatch(token, typeBinding.sourceName)) continue;
if (typesFound.contains(typeBinding)) continue;
@@ -12523,8 +12504,7 @@ public final class CompletionEngine
if (tokenLength > local.name.length)
continue next;
- if (!CharOperation.prefixEquals(token, local.name, false /* ignore case */)
- && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, local.name)))
+ if (isFailedMatch(token, local.name))
continue next;
//{ObjectTeams: filter out generated variables
@@ -12942,6 +12922,26 @@ public final class CompletionEngine
private boolean isAllowingLongComputationProposals() {
return this.monitor != null;
}
+
+ /**
+ * Checks whether name matches the token according to the current
+ * code completion settings (substring match, camel case match etc.)
+ * and sets whether the current match is a suffix proposal.
+ *
+ * @param token the token that is tested
+ * @param name the name to match
+ * @return <code>true</code> if the token does not match,
+ * <code>false</code> otherwise
+ */
+ private boolean isFailedMatch(char[] token, char[] name) {
+ if ((this.options.substringMatch && CharOperation.substringMatch(token, name))
+ || (this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, name))
+ || CharOperation.prefixEquals(token, name, false)) {
+ return false;
+ }
+
+ return true;
+ }
private boolean isForbidden(ReferenceBinding binding) {
for (int i = 0; i <= this.forbbidenBindingsPtr; i++) {
if(this.forbbidenBindings[i] == binding) {
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/RelevanceConstants.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/RelevanceConstants.java
index 12dbc47ae..53f1215ab 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/RelevanceConstants.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/RelevanceConstants.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -44,6 +44,7 @@ public interface RelevanceConstants {
int R_NAME_FIRST_SUFFIX = 4;
int R_NAME_SUFFIX = 3;
int R_NAME_LESS_NEW_CHARACTERS = 15;
+ int R_SUBSTRING = -1;
int R_METHOD_OVERIDE = 3;
int R_NON_RESTRICTED = 3;
int R_TRUE_OR_FALSE = 1;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java
index ce75101a7..8c6d3d342 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistOptions.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions
*******************************************************************************/
package org.eclipse.jdt.internal.codeassist.impl;
@@ -51,6 +52,8 @@ public class AssistOptions {
"org.eclipse.jdt.core.codeComplete.discouragedReferenceCheck"; //$NON-NLS-1$
public static final String OPTION_CamelCaseMatch =
"org.eclipse.jdt.core.codeComplete.camelCaseMatch"; //$NON-NLS-1$
+ public static final String OPTION_SubstringMatch =
+ "org.eclipse.jdt.core.codeComplete.substringMatch"; //$NON-NLS-1$
public static final String OPTION_SuggestStaticImports =
"org.eclipse.jdt.core.codeComplete.suggestStaticImports"; //$NON-NLS-1$
@@ -63,6 +66,7 @@ public class AssistOptions {
public boolean checkDiscouragedReference = false;
public boolean forceImplicitQualification = false;
public boolean camelCaseMatch = true;
+ public boolean substringMatch = true;
public boolean suggestStaticImport = true;
public char[][] fieldPrefixes = null;
public char[][] staticFieldPrefixes = null;
@@ -229,6 +233,13 @@ public class AssistOptions {
this.camelCaseMatch = false;
}
}
+ if ((optionValue = optionsMap.get(OPTION_SubstringMatch)) != null) {
+ if (ENABLED.equals(optionValue)) {
+ this.substringMatch = true;
+ } else if (DISABLED.equals(optionValue)) {
+ this.substringMatch = false;
+ }
+ }
if ((optionValue = optionsMap.get(OPTION_PerformDeprecationCheck)) != null) {
if (ENABLED.equals(optionValue)) {
this.checkDeprecation = true;
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
index 3ac27f561..0b8ff4597 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java
@@ -1900,7 +1900,7 @@ public void parseBlockStatements(AbstractMethodMappingDeclaration mapping, Compi
}
// SH}
-//the name is a misnomer, we allow "pop"s not just at the TOS. Lambda wants to be sticky till fully reduced, however we do want other elements poppped at the right point, so ...
+// the name is a misnomer, we allow "pop"s not just at the TOS. Lambda wants to be sticky till fully reduced, however we do want other elements popped at the right point, so ...
protected void popElement(int kind) {
if (this.elementPtr < 0)
@@ -1910,7 +1910,7 @@ protected void popElement(int kind) {
if (kind != K_LAMBDA_EXPRESSION_DELIMITER) {
while (this.elementKindStack[stackPointer] == K_LAMBDA_EXPRESSION_DELIMITER) {
- stackPointer --;
+ if (--stackPointer < 0) break;
}
}
if (stackPointer < 0 || this.elementKindStack[stackPointer] != kind)
diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLambdaExpression.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLambdaExpression.java
index 1afe17f52..08da45d75 100644
--- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLambdaExpression.java
+++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/select/SelectionOnLambdaExpression.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2014 IBM Corporation and others.
+ * Copyright (c) 2014, 2015 IBM Corporation and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,7 +8,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
- */
+ *******************************************************************************/
package org.eclipse.jdt.internal.codeassist.select;
@@ -30,8 +30,8 @@ public class SelectionOnLambdaExpression extends LambdaExpression {
this.setArrowPosition(expression.arrowPosition());
}
@Override
- public TypeBinding resolveType(BlockScope blockScope) {
- TypeBinding resolveType = super.resolveType(blockScope);
+ public TypeBinding resolveType(BlockScope blockScope, boolean skipKosherCheck) {
+ TypeBinding resolveType = super.resolveType(blockScope, skipKosherCheck);
if (this.expectedType != null && this.original == this) { // final resolution.
throw new SelectionNodeFound(this.descriptor);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
index df0ad2fa8..e62e8e210 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/CharOperation.java
@@ -8,6 +8,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Luiz-Otavio Zorzella <zorzella at gmail dot com> - Improve CamelCase algorithm
+ * Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions
*******************************************************************************/
package org.eclipse.jdt.core.compiler;
@@ -694,6 +695,94 @@ public static final boolean camelCaseMatch(char[] pattern, int patternStart, int
}
/**
+ * 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
@@ -1156,6 +1245,148 @@ public static final char[] concat(
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.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = { 'a' }
+ * separator = '/'
+ * => result = { ' a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { ' a' }
+ * second = null
+ * separator = '/'
+ * => result = { ' a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { ' a' }
+ * second = { ' b' }
+ * separator = '/'
+ * => result = { ' a' , '/', 'b' }
+ * </pre>
+ * </li>
+ * * <li><pre>
+ * first = { ' a' }
+ * second = { }
+ * separator = '/'
+ * => result = { ' a'}
+ * </pre>
+ * </li>
+
+ * </ol>
+ *
+ * @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.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * sep1 = '/'
+ * second = { 'a' }
+ * sep2 = ':'
+ * third = { 'b' }
+ * => result = { ' a' , ':', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = null
+ * sep2 = ':'
+ * third = { 'b' }
+ * => result = { ' a' , '/', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = { 'b' }
+ * sep2 = ':'
+ * third = null
+ * => result = { ' a' , '/', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = { 'b' }
+ * sep2 = ':'
+ * third = { 'c' }
+ * => result = { ' a' , '/', 'b' , ':', 'c' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = { }
+ * sep2 = ':'
+ * third = { 'c' }
+ * => result = { ' a', ':', 'c' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @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
@@ -1384,6 +1615,65 @@ public static final char[] concatWith(char[][] array, char separator) {
}
/**
+ * 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.
+ * <br>
+ * <br>
+ * For example:<br>
+ * <ol>
+ * <li><pre>
+ * array = { { 'a' }, {}, { 'b' } }
+ * separator = ''
+ * => result = { 'a', '/', '/', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { { 'a' }, { 'b' } }
+ * separator = '.'
+ * => result = { 'a', '.', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = null
+ * separator = '.'
+ * => result = { }
+ * </pre></li>
+ * </ol>
+ *
+ * @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.
*
* <br>
@@ -3554,6 +3844,94 @@ public static final char[][] splitOn(
}
/**
+ * 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.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * divider = ','
+ * array = { 'A' , '<', 'B', ',', 'C', '>', ',', 'D' }
+ * start = 0
+ * end = 8
+ * result => { { 'A' , '<', 'B', ',', 'C', '>'}, { 'D' }}
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @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
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
index f6a849161..89c602edd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/core/compiler/IProblem.java
@@ -1818,6 +1818,8 @@ void setSourceStart(int sourceStart);
int ContradictoryNullAnnotationsInferredFunctionType = MethodRelated + 973;
/** @since 3.11 */
int IllegalReturnNullityRedefinitionFreeTypeVariable = MethodRelated + 974;
+ /** @since 3.12 */
+ int IllegalRedefinitionOfTypeVariable = 975;
// Java 8 work
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
index 50a948d6a..aacac0a0f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ASTNode.java
@@ -735,12 +735,17 @@ public abstract class ASTNode implements TypeConstants, TypeIds {
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 = argument.resolveType(scope);
+ TypeBinding updatedArgumentType;
if (argument instanceof LambdaExpression) {
- // LE.resolveType may return a valid binding because resolve does not detect structural errors at this point.
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.isCompatibleWith(parameterType, scope) || lambda.hasErrors())
continue;
+ } else {
+ updatedArgumentType = argument.resolveType(scope);
}
if (updatedArgumentType != null && updatedArgumentType.kind() != Binding.POLY_TYPE)
argumentTypes[i] = updatedArgumentType;
@@ -1040,10 +1045,10 @@ public abstract class ASTNode implements TypeConstants, TypeIds {
System.arraycopy(se8Annotations, 0, se8Annotations = new AnnotationBinding[se8count + 1], 0, se8count);
se8Annotations[se8count++] = annotation;
}
- if (annotationType.id == TypeIds.T_ConfiguredAnnotationNonNull) {
+ if (annotationType.hasNullBit(TypeIds.BitNonNullAnnotation)) {
se8nullBits |= TagBits.AnnotationNonNull;
se8NullAnnotation = annotations[i];
- } else if (annotationType.id == TypeIds.T_ConfiguredAnnotationNullable) {
+ } else if (annotationType.hasNullBit(TypeIds.BitNullableAnnotation)) {
se8nullBits |= TagBits.AnnotationNullable;
se8NullAnnotation = annotations[i];
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
index 1d5b5abfe..315d40b4e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/AllocationExpression.java
@@ -215,9 +215,10 @@ public Expression enclosingInstance() {
}
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
+ cleanUpInferenceContexts();
if (!valueRequired)
currentScope.problemReporter().unusedObjectAllocation(this);
-
+
//{ObjectTeams: redirect?
if (this.roleCreatorCall != null) {
this.roleCreatorCall.generateCode(currentScope, codeStream, valueRequired);
@@ -556,7 +557,6 @@ public TypeBinding resolveType(BlockScope scope) {
this.resolvedType = this.type.resolvedType = this.binding.declaringClass;
resolvePolyExpressionArguments(this, this.binding, this.argumentTypes, scope);
} else {
-
//{ObjectTeams: may need to instantiate parameters of constructor
AnchorMapping anchorMapping = AnchorMapping.setupNewMapping(null, this.arguments, scope);
try {
@@ -625,7 +625,7 @@ public TypeBinding resolveType(BlockScope scope) {
if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) {
TypeVariableBinding[] typeVariables = this.binding.original().typeVariables();
for (int i = 0; i < this.typeArguments.length; i++)
- this.typeArguments[i].checkNullConstraints(scope, typeVariables, i);
+ this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i);
}
}
}
@@ -957,6 +957,17 @@ public InferenceContext18 getInferenceContext(ParameterizedMethodBinding method)
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;
+}
+
//-- interface InvocationSite: --
public ExpressionContext getExpressionContext() {
return this.expressionContext;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
index e37bca254..828fa15f1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Annotation.java
@@ -400,34 +400,32 @@ public abstract class Annotation extends Expression {
tagBits |= TagBits.AnnotationInstantiation;
break;
// SH}
- case TypeIds.T_ConfiguredAnnotationNullable :
- tagBits |= TagBits.AnnotationNullable;
- break;
- case TypeIds.T_ConfiguredAnnotationNonNull :
- tagBits |= TagBits.AnnotationNonNull;
- break;
- case TypeIds.T_ConfiguredAnnotationNonNullByDefault :
- // seeing this id implies that null annotation analysis is enabled
- 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 |= TagBits.AnnotationNonNullByDefault; // custom unconfigurable NNBD
- }
- if (value instanceof BooleanConstant) {
- // boolean value is used for declaration annotations, signal using the annotation tag bit:
- tagBits |= ((BooleanConstant)value).booleanValue() ? TagBits.AnnotationNonNullByDefault : TagBits.AnnotationNullUnspecifiedByDefault;
- } else if (value != null) {
- // non-boolean value signals type annotations, evaluate from DefaultLocation[] to bitvector a la Binding#NullnessDefaultMASK:
- tagBits |= nullLocationBitsFromAnnotationValue(value);
- }
- break;
}
+ if (annotationType.hasNullBit(TypeIds.BitNullableAnnotation)) {
+ tagBits |= TagBits.AnnotationNullable;
+ } else if (annotationType.hasNullBit(TypeIds.BitNonNullAnnotation)) {
+ tagBits |= TagBits.AnnotationNonNull;
+ } else if (annotationType.hasNullBit(TypeIds.BitNonNullByDefaultAnnotation)) {
+ 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 |= TagBits.AnnotationNonNullByDefault; // custom unconfigurable NNBD
+ }
+ if (value instanceof BooleanConstant) {
+ // boolean value is used for declaration annotations, signal using the annotation tag bit:
+ tagBits |= ((BooleanConstant)value).booleanValue() ? TagBits.AnnotationNonNullByDefault : TagBits.AnnotationNullUnspecifiedByDefault;
+ } else if (value != null) {
+ // non-boolean value signals type annotations, evaluate from DefaultLocation[] to bitvector a la Binding#NullnessDefaultMASK:
+ tagBits |= nullLocationBitsFromAnnotationValue(value);
+ }
+ }
+
return tagBits;
}
@@ -1200,8 +1198,7 @@ public abstract class Annotation extends Expression {
QualifiedTypeReference.rejectAnnotationsOnStaticMemberQualififer(scope, currentType, new Annotation [] { annotation });
continue nextAnnotation;
} else {
- int id = annotation.resolvedType.id;
- if (id == TypeIds.T_ConfiguredAnnotationNonNull || id == TypeIds.T_ConfiguredAnnotationNullable) {
+ if (annotation.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) {
scope.problemReporter().nullAnnotationUnsupportedLocation(annotation);
continue nextAnnotation;
}
@@ -1212,6 +1209,10 @@ public abstract class Annotation extends Expression {
}
}
+ public boolean hasNullBit(int bit) {
+ return this.resolvedType instanceof ReferenceBinding && ((ReferenceBinding) this.resolvedType).hasNullBit(bit);
+ }
+
public abstract void traverse(ASTVisitor visitor, BlockScope scope);
public abstract void traverse(ASTVisitor visitor, ClassScope scope);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java
index 6aaaa5c25..a922effd6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayAllocationExpression.java
@@ -48,6 +48,8 @@ public class ArrayAllocationExpression extends Expression {
public Annotation [][] annotationsOnDimensions; // jsr308 style annotations.
public ArrayInitializer initializer;
+ private TypeBinding expectedType;
+
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
for (int i = 0, max = this.dimensions.length; i < max; i++) {
Expression dim;
@@ -184,6 +186,21 @@ public class ArrayAllocationExpression extends Expression {
{
scope.problemReporter().contradictoryNullAnnotations(this.type.annotations[this.type.annotations.length-1]);
}
+ LookupEnvironment environment = scope.environment();
+ if (environment.usesNullTypeAnnotations()
+ && this.annotationsOnDimensions == null // don't annotate if explicit annotations are given on dimensions ...
+ && ((referenceType.tagBits & TagBits.AnnotationNullMASK) == 0) // ... or leaf type
+ && this.expectedType != null) // need this to determine our action
+ {
+ Expression lastDim = this.dimensions[this.dimensions.length-1];
+ if (lastDim instanceof IntLiteral && ((IntLiteral) lastDim).value == 0) {
+ long tagBit = this.expectedType.leafComponentType().tagBits & TagBits.AnnotationNullMASK;
+ // let new X[0] be seen as "@NonNull X[]", or "@Nullable X[]" just as expected
+ AnnotationBinding[] nullAnnotations = environment.nullAnnotationsFromTagBits(tagBit);
+ if (nullAnnotations != null)
+ referenceType = environment.createAnnotatedType(referenceType, nullAnnotations);
+ }
+ }
//{ObjectTeams:
referenceType = RoleTypeCreator.maybeWrapUnqualifiedRoleType(referenceType, scope, this);
// SH}
@@ -214,6 +231,10 @@ public class ArrayAllocationExpression extends Expression {
return this.resolvedType;
}
+ @Override
+ public void setExpectedType(TypeBinding expectedType) {
+ this.expectedType = expectedType;
+ }
public void traverse(ASTVisitor visitor, BlockScope scope) {
if (visitor.visit(this, scope)) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
index 0f13ed995..b8163091e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ArrayReference.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -60,7 +60,7 @@ public FlowInfo analyseAssignment(BlockScope currentScope, FlowContext flowConte
}
public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
- this.receiver.checkNPE(currentScope, flowContext, flowInfo);
+ this.receiver.checkNPE(currentScope, flowContext, flowInfo, 1);
flowInfo = this.receiver.analyseCode(currentScope, flowContext, flowInfo);
flowInfo = this.position.analyseCode(currentScope, flowContext, flowInfo);
this.position.checkNPEbyUnboxing(currentScope, flowContext, flowInfo);
@@ -69,12 +69,12 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
return flowInfo;
}
-public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
+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);
+ return super.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck);
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
index 80f55b404..13f06d9e1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CastExpression.java
@@ -359,9 +359,9 @@ public static void checkNeedForArgumentCasts(BlockScope scope, int operator, int
}
}
-public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
+public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
checkNPEbyUnboxing(scope, flowContext, flowInfo);
- return this.expression.checkNPE(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) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
index c12c1756e..c375e8aa2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ClassLiteralAccess.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -120,7 +120,8 @@ public class ClassLiteralAccess extends Expression {
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.
*/
- this.targetType = scope.environment().convertToRawType(this.targetType, true /* force conversion of enclosing types*/);
+ 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;
@@ -174,11 +175,13 @@ public class ClassLiteralAccess extends Expression {
// Integer.class --> Class<Integer>, perform boxing of base types (int.class --> Class<Integer>)
TypeBinding boxedType = null;
if (this.targetType.id == T_void) {
- boxedType = scope.environment().getResolvedType(JAVA_LANG_VOID, scope);
+ boxedType = environment.getResolvedType(JAVA_LANG_VOID, scope);
} else {
boxedType = scope.boxing(this.targetType);
}
- this.resolvedType = scope.environment().createParameterizedType(classType, new TypeBinding[]{ boxedType }, null/*not a member*/);
+ if (environment.usesNullTypeAnnotations())
+ boxedType = environment.createAnnotatedType(boxedType, new AnnotationBinding[] { environment.getNonNullAnnotation() });
+ this.resolvedType = environment.createParameterizedType(classType, new TypeBinding[]{ boxedType }, null/*not a member*/);
} else {
this.resolvedType = classType;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
index 4eb6fb133..dee664d14 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/CompilationUnitDeclaration.java
@@ -196,6 +196,9 @@ public void cleanUp() {
}
this.suppressWarningAnnotations = null;
+
+ if (this.scope != null)
+ this.scope.cleanUpInferenceContexts();
}
private void cleanUp(TypeDeclaration type) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
index d285c6d72..57665e9e4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java
@@ -187,7 +187,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
return mergedInfo;
}
- public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
+ 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)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
index fab1d4d99..b640d8991 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ExplicitConstructorCall.java
@@ -887,6 +887,11 @@ public class ExplicitConstructorCall extends Statement implements Invocation {
return null;
}
+ @Override
+ public void cleanUpInferenceContexts() {
+ // Nothing to do.
+ }
+
public Expression[] arguments() {
return this.arguments;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
index f082e6835..e5b0f4dff 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java
@@ -765,9 +765,10 @@ boolean handledByGeneratedMethod(Scope scope, TypeBinding castType, TypeBinding
* @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) {
+public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
boolean isNullable = false;
if (this.resolvedType != null) {
// 1. priority: @NonNull
@@ -800,6 +801,9 @@ public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flow
}
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) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
index 46ebd3afb..25b874298 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FieldReference.java
@@ -187,7 +187,7 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
boolean nonStatic = !this.binding.isStatic();
this.receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic);
if (nonStatic) {
- this.receiver.checkNPE(currentScope, flowContext, flowInfo);
+ this.receiver.checkNPE(currentScope, flowContext, flowInfo, 1);
}
if (valueRequired || currentScope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_4) {
@@ -196,11 +196,11 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
return flowInfo;
}
-public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
+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);
+ return checkNullableFieldDereference(scope, this.binding, this.nameSourcePosition, flowContext, ttlForFieldCheck);
}
/**
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
index 47db93b27..c92668eda 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ForeachStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -106,7 +106,7 @@ public class ForeachStatement extends Statement {
int initialComplaintLevel = (flowInfo.reachMode() & FlowInfo.UNREACHABLE) != 0 ? Statement.COMPLAINED_FAKE_REACHABLE : Statement.NOT_COMPLAINED;
// process the element variable and collection
- this.collection.checkNPE(currentScope, flowContext, flowInfo);
+ this.collection.checkNPE(currentScope, flowContext, flowInfo, 1);
flowInfo = this.elementVariable.analyseCode(this.scope, flowContext, flowInfo);
FlowInfo condInfo = this.collection.analyseCode(this.scope, flowContext, flowInfo.copy());
LocalVariableBinding elementVarBinding = this.elementVariable.binding;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
index fa1201380..a765f78d1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/FunctionalExpression.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2013, 2014 IBM Corporation and others.
+ * Copyright (c) 2013, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -167,6 +167,10 @@ public abstract class FunctionalExpression extends Expression {
}
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());
@@ -179,7 +183,7 @@ public abstract class FunctionalExpression extends Expression {
}
this.descriptor = sam;
- if (kosherDescriptor(blockScope, sam, true)) {
+ if (skipKosherCheck || kosherDescriptor(blockScope, sam, true)) {
if (blockScope.environment().globalOptions.isAnnotationBasedNullAnalysisEnabled)
NullAnnotationMatching.checkForContradictions(sam, this, blockScope);
return this.resolvedType = this.expectedType;
@@ -268,7 +272,7 @@ public abstract class FunctionalExpression extends Expression {
status = false;
if (!inspector.visible(sam.thrownExceptions))
status = false;
- if (!inspector.visible(sam.declaringClass))
+ if (!inspector.visible(this.expectedType))
status = false;
return status;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Invocation.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Invocation.java
index f77cd139a..2f30eea26 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Invocation.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Invocation.java
@@ -42,6 +42,8 @@ public interface Invocation extends InvocationSite {
*/
InferenceContext18 getInferenceContext(ParameterizedMethodBinding method);
+ void cleanUpInferenceContexts();
+
/** Record result against target type */
void registerResult(TypeBinding targetType, MethodBinding method);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
index 12cf94c5f..b1242e0cd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java
@@ -233,7 +233,7 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
* @see org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding.resolveTypesFor(MethodBinding)
* @see org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration.resolve(ClassScope)
*/
- public TypeBinding resolveType(BlockScope blockScope) {
+ public TypeBinding resolveType(BlockScope blockScope, boolean skipKosherCheck) {
boolean argumentsTypeElided = argumentsTypeElided();
int argumentsLength = this.arguments == null ? 0 : this.arguments.length;
@@ -257,11 +257,11 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
this.scope = new MethodScope(blockScope, this, methodScope.isStatic, methodScope.lastVisibleFieldID);
this.scope.isConstructorCall = methodScope.isConstructorCall;
- super.resolveType(blockScope); // compute & capture interface function descriptor.
+ super.resolveType(blockScope, skipKosherCheck); // compute & capture interface function descriptor.
final boolean haveDescriptor = this.descriptor != null;
- if (!haveDescriptor || this.descriptor.typeVariables != Binding.NO_TYPE_VARIABLES) // already complained in kosher*
+ 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,
@@ -465,10 +465,14 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
if (targetType instanceof ReferenceBinding && targetType.isValidBinding()) {
ParameterizedTypeBinding withWildCards = InferenceContext18.parameterizedWithWildcard(targetType);
if (withWildCards != null) {
- if (!argumentTypesElided)
- return new InferenceContext18(blockScope).inferFunctionalInterfaceParameterization(this, blockScope, withWildCards);
- else
+ if (!argumentTypesElided) {
+ InferenceContext18 freshInferenceContext = new InferenceContext18(blockScope);
+ ReferenceBinding inferredType = freshInferenceContext.inferFunctionalInterfaceParameterization(this, blockScope, withWildCards);
+ freshInferenceContext.cleanUp();
+ return inferredType;
+ } else {
return findGroundTargetTypeForElidedLambda(blockScope, withWildCards);
+ }
}
return (ReferenceBinding) targetType;
}
@@ -577,13 +581,8 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
AnnotationBinding [] annotations = descParameters[i].getTypeAnnotations();
for (int j = 0, length = annotations.length; j < length; j++) {
AnnotationBinding annotation = annotations[j];
- if (annotation != null) {
- switch (annotation.getAnnotationType().id) {
- case TypeIds.T_ConfiguredAnnotationNullable :
- case TypeIds.T_ConfiguredAnnotationNonNull :
- ourParameters[i] = env.createAnnotatedType(ourParameters[i], new AnnotationBinding [] { annotation });
- break;
- }
+ if (annotation != null && annotation.getAnnotationType().hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) {
+ ourParameters[i] = env.createAnnotatedType(ourParameters[i], new AnnotationBinding [] { annotation });
}
}
}
@@ -609,7 +608,30 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
}
}
- public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) {
+ public boolean isPertinentToApplicability(final TypeBinding targetType, final MethodBinding method) {
+
+ class NotPertientToApplicability extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+ }
+ class ResultsAnalyser extends ASTVisitor {
+ public boolean visit(TypeDeclaration type, BlockScope skope) {
+ return false;
+ }
+ public boolean visit(TypeDeclaration type, ClassScope skope) {
+ return false;
+ }
+ public boolean visit(LambdaExpression type, BlockScope skope) {
+ return false;
+ }
+ public boolean visit(ReturnStatement returnStatement, BlockScope skope) {
+ if (returnStatement.expression != null) {
+ if (!returnStatement.expression.isPertinentToApplicability(targetType, method))
+ throw new NotPertientToApplicability();
+ }
+ return false;
+ }
+ }
+
if (targetType == null) // assumed to signal another primary error
return true;
@@ -624,9 +646,18 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
return false;
} else {
Expression [] returnExpressions = this.resultExpressions;
- for (int i = 0, length = returnExpressions.length; i < length; i++) {
- if (!returnExpressions[i].isPertinentToApplicability(targetType, method))
+ if (returnExpressions != NO_EXPRESSIONS) {
+ for (int i = 0, length = returnExpressions.length; i < length; i++) {
+ if (!returnExpressions[i].isPertinentToApplicability(targetType, method))
+ return false;
+ }
+ } else {
+ // return expressions not yet discovered by resolveType(), so traverse no looking just for one that's not pertinent
+ try {
+ this.body.traverse(new ResultsAnalyser(), this.scope);
+ } catch (NotPertientToApplicability npta) {
return false;
+ }
}
}
@@ -806,6 +837,10 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
if (!isPertinentToApplicability(targetType, null))
return true;
+ // catch up on one check deferred via skipKosherCheck=true (only if pertinent for applicability)
+ if (!kosherDescriptor(this.enclosingScope, sam, false))
+ return false;
+
Expression [] returnExpressions = copy.resultExpressions;
for (int i = 0, length = returnExpressions.length; i < length; i++) {
if (this.enclosingScope.parameterCompatibilityLevel(returnExpressions[i].resolvedType, sam.returnType) == Scope.NOT_COMPATIBLE) {
@@ -855,7 +890,7 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
copy.setExpressionContext(this.expressionContext);
copy.setExpectedType(targetType);
copy.inferenceContext = context;
- TypeBinding type = copy.resolveType(this.enclosingScope);
+ TypeBinding type = copy.resolveType(this.enclosingScope, true);
if (type == null || !type.isValidBinding())
return null;
@@ -1035,8 +1070,12 @@ public class LambdaExpression extends FunctionalExpression implements IPolyExpre
switch(parent.kind) {
case Scope.CLASS_SCOPE:
case Scope.METHOD_SCOPE:
- parent.referenceContext().tagAsHavingErrors();
- return;
+ ReferenceContext parentAST = parent.referenceContext();
+ if (parentAST != this) {
+ parentAST.tagAsHavingErrors();
+ return;
+ }
+ break;
default:
parent = parent.parent;
break;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
index 08bfabc69..ef581a557 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/MessageSend.java
@@ -250,7 +250,8 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
}
if (nonStatic) {
- this.receiver.checkNPE(currentScope, flowContext, flowInfo);
+ int timeToLive = ((this.bits & ASTNode.InsideExpressionStatement) != 0) ? 3 : 2;
+ this.receiver.checkNPE(currentScope, flowContext, flowInfo, timeToLive);
}
if (this.arguments != null) {
@@ -497,7 +498,7 @@ private FlowInfo analyseNullAssertion(BlockScope currentScope, Expression argume
return flowInfo;
}
-public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
+public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
// message send as a receiver
if ((nullStatus(flowInfo, flowContext) & FlowInfo.POTENTIALLY_NULL) != 0) // note that flowInfo is not used inside nullStatus(..)
scope.problemReporter().messageSendPotentialNullReference(this.binding, this);
@@ -557,6 +558,7 @@ public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBind
* @param valueRequired boolean
*/
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();
@@ -1181,7 +1183,7 @@ public TypeBinding resolveType(BlockScope scope) {
if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) {
TypeVariableBinding[] typeVariables = this.binding.original().typeVariables();
for (int i = 0; i < this.typeArguments.length; i++)
- this.typeArguments[i].checkNullConstraints(scope, typeVariables, i);
+ this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i);
}
}
}
@@ -1675,6 +1677,15 @@ public InferenceContext18 getInferenceContext(ParameterizedMethodBinding method)
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;
+}
public Expression[] arguments() {
return this.arguments;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java
index 8f590f7a9..1d5bdd85c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/NullAnnotationMatching.java
@@ -27,6 +27,7 @@ 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;
@@ -50,10 +51,26 @@ public class NullAnnotationMatching {
public enum CheckMode {
/** in this mode we check normal assignment compatibility. */
COMPATIBLE,
- /** in this mode we do not tolerate incompatibly missing annotations on type parameters (for overriding analysis) */
- OVERRIDE,
+ /** 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
+ BOUND_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 CheckMode toDetail() {
+ return OVERRIDE;
+ }
+ };
+
+ CheckMode toDetail() {
+ return CheckMode.EXACT;
+ }
}
/** 0 = OK, 1 = unchecked, 2 = definite mismatch */
@@ -126,7 +143,7 @@ public class NullAnnotationMatching {
* @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, nullStatus, CheckMode.COMPATIBLE);
+ return analyse(requiredType, providedType, null, null, nullStatus, CheckMode.COMPATIBLE);
}
/**
* Find any mismatches between the two given types, which are caused by null type annotations.
@@ -134,11 +151,12 @@ public class NullAnnotationMatching {
* @param providedType
* @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 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, int nullStatus, CheckMode mode) {
+ public static NullAnnotationMatching analyse(TypeBinding requiredType, TypeBinding providedType, TypeBinding providedSubstitute, Substitution substitution, int nullStatus, CheckMode mode) {
if (!requiredType.enterRecursiveFunction())
return NullAnnotationMatching.NULL_ANNOTATIONS_OK;
try {
@@ -150,23 +168,32 @@ public class NullAnnotationMatching {
return NullAnnotationMatching.NULL_ANNOTATIONS_OK_NONNULL;
return okStatus;
}
+ if (requiredType instanceof TypeVariableBinding && substitution != null && (mode == CheckMode.EXACT || mode == CheckMode.COMPATIBLE)) {
+ requiredType.exitRecursiveFunction();
+ requiredType = Scope.substitute(substitution, requiredType);
+ if (!requiredType.enterRecursiveFunction())
+ return NullAnnotationMatching.NULL_ANNOTATIONS_OK;
+ }
if (mode == CheckMode.BOUND_CHECK && requiredType instanceof TypeVariableBinding) {
- // during bound check against a type variable check the provided type against all upper bounds:
- TypeBinding superClass = requiredType.superclass();
- if (superClass != null && superClass.hasNullTypeAnnotations()) {
- NullAnnotationMatching status = analyse(superClass, providedType, null, nullStatus, mode);
- severity = Math.max(severity, status.severity);
- if (severity == 2)
- return new NullAnnotationMatching(severity, nullStatus, superTypeHint);
- }
- TypeBinding[] superInterfaces = requiredType.superInterfaces();
- if (superInterfaces != null) {
- for (int i = 0; i < superInterfaces.length; i++) {
- if (superInterfaces[i].hasNullTypeAnnotations()) {
- NullAnnotationMatching status = analyse(superInterfaces[i], providedType, null, nullStatus, mode);
- severity = Math.max(severity, status.severity);
- if (severity == 2)
- return new NullAnnotationMatching(severity, nullStatus, superTypeHint);
+ 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, CheckMode.COMPATIBLE);
+ severity = Math.max(severity, status.severity);
+ if (severity == 2)
+ return new NullAnnotationMatching(severity, nullStatus, superTypeHint);
+ }
+ 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, CheckMode.COMPATIBLE);
+ severity = Math.max(severity, status.severity);
+ if (severity == 2)
+ return new NullAnnotationMatching(severity, nullStatus, superTypeHint);
+ }
}
}
}
@@ -185,7 +212,7 @@ public class NullAnnotationMatching {
long providedBits = validNullTagBits(providedDimsTagBits[i]);
if (i > 0)
currentNullStatus = -1; // don't use beyond the outermost dimension
- severity = Math.max(severity, computeNullProblemSeverity(requiredBits, providedBits, currentNullStatus, mode == CheckMode.OVERRIDE && nullStatus == -1));
+ severity = Math.max(severity, computeNullProblemSeverity(requiredBits, providedBits, currentNullStatus, i == 0 ? mode : mode.toDetail(), false));
if (severity == 2)
return NullAnnotationMatching.NULL_ANNOTATIONS_MISMATCH;
if (severity == 0)
@@ -202,7 +229,7 @@ public class NullAnnotationMatching {
|| nullStatus == -1) // only at detail/recursion even nullable must be matched exactly
{
long providedBits = providedNullTagBits(providedType);
- int s = computeNullProblemSeverity(requiredBits, providedBits, nullStatus, mode == CheckMode.OVERRIDE && nullStatus == -1);
+ int s = computeNullProblemSeverity(requiredBits, providedBits, nullStatus, mode, requiredType.isTypeVariable());
severity = Math.max(severity, s);
if (severity == 0 && (providedBits & TagBits.AnnotationNonNull) != 0)
okStatus = NullAnnotationMatching.NULL_ANNOTATIONS_OK_NONNULL;
@@ -219,7 +246,7 @@ public class NullAnnotationMatching {
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, -1, mode);
+ NullAnnotationMatching status = analyse(requiredArguments[i], providedArguments[i], providedArgSubstitute, substitution, -1, mode.toDetail());
severity = Math.max(severity, status.severity);
if (severity == 2)
return new NullAnnotationMatching(severity, nullStatus, superTypeHint);
@@ -230,7 +257,7 @@ public class NullAnnotationMatching {
TypeBinding providedEnclosing = providedType.enclosingType();
if (requiredEnclosing != null && providedEnclosing != null) {
TypeBinding providedEnclSubstitute = providedSubstitute != null ? providedSubstitute.enclosingType() : null;
- NullAnnotationMatching status = analyse(requiredEnclosing, providedEnclosing, providedEnclSubstitute, -1, mode);
+ NullAnnotationMatching status = analyse(requiredEnclosing, providedEnclosing, providedEnclSubstitute, substitution, -1, mode);
severity = Math.max(severity, status.severity);
}
}
@@ -307,8 +334,13 @@ public class NullAnnotationMatching {
return TagBits.AnnotationNullable; // type cannot require @NonNull
}
}
- if (mode != CheckMode.BOUND_CHECK) // no pessimistic checks during boundcheck (we *have* the instantiation)
- return TagBits.AnnotationNonNull; // instantiation could require @NonNull
+ switch (mode) {
+ case BOUND_CHECK: // no pessimistic checks during boundcheck (we *have* the instantiation)
+ case OVERRIDE_RETURN: // allow covariance
+ break;
+ default:
+ return TagBits.AnnotationNonNull; // instantiation could require @NonNull
+ }
}
return 0;
@@ -398,27 +430,60 @@ public class NullAnnotationMatching {
* @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 overrideDetailChecking true enables strictest mode during override analysis when checking type details (type argument, array content)
+ * @param mode check mode (see {@link CheckMode})
+ * @param requiredIsTypeVariable is the required type a type variable (possibly: "free type variable")?
* @return see {@link #severity} for interpretation of values
*/
- private static int computeNullProblemSeverity(long requiredBits, long providedBits, int nullStatus, boolean overrideDetailChecking) {
- // nullStatus:
- // overrideDetailChecking:
- if ((requiredBits != 0 || overrideDetailChecking) && requiredBits != providedBits) {
- if (requiredBits == TagBits.AnnotationNonNull && nullStatus == FlowInfo.NON_NULL) {
- return 0; // OK by flow analysis
+ private static int computeNullProblemSeverity(long requiredBits, long providedBits, int nullStatus, CheckMode mode, boolean requiredIsTypeVariable) {
+ if (requiredBits == providedBits)
+ return 0;
+ if (requiredBits == 0) {
+ switch (mode) {
+ case COMPATIBLE:
+ case BOUND_CHECK:
+ case EXACT:
+ return 0;
+ case OVERRIDE_RETURN:
+ if (providedBits == TagBits.AnnotationNonNull)
+ return 0; // covariant redefinition to nonnull is good
+ if (!requiredIsTypeVariable)
+ return 0; // refining an unconstrained non-TVB return to nullable is also legal
+ return 1;
+ case OVERRIDE:
+ return 1; // warn about dropped annotation
}
- if (requiredBits == TagBits.AnnotationNullMASK)
- return 0; // OK since LHS accepts either
- if (nullStatus != -1 && !overrideDetailChecking && requiredBits == TagBits.AnnotationNullable)
- return 0; // when using flow info, everything is compatible to nullable
- if (providedBits != 0) {
- return 2; // mismatching annotations
- } else {
- return 1; // need unchecked conversion regarding type detail
+ } else if (requiredBits == TagBits.AnnotationNullMASK) {
+ return 0; // OK since LHS accepts either
+ } else if (requiredBits == TagBits.AnnotationNonNull) {
+ switch (mode) {
+ case COMPATIBLE:
+ if (nullStatus == FlowInfo.NON_NULL)
+ return 0; // OK by flow analysis
+ //$FALL-THROUGH$
+ case BOUND_CHECK:
+ case EXACT:
+ case OVERRIDE_RETURN:
+ case OVERRIDE:
+ if (providedBits == 0)
+ return 1;
+ return 2;
+ }
+
+ } else if (requiredBits == TagBits.AnnotationNullable) {
+ switch (mode) {
+ case COMPATIBLE:
+ case OVERRIDE_RETURN:
+ return 0; // in these modes everything is compatible to nullable
+ case BOUND_CHECK:
+ case EXACT:
+ if (providedBits == 0)
+ return 1;
+ return 2;
+ case OVERRIDE:
+ return 2;
}
}
- return 0; // OK by tagBits
+ return 0; // shouldn't get here, requiredBits should be one of the listed cases
}
static class SearchContradictions extends TypeBindingVisitor {
@@ -565,4 +630,17 @@ public class NullAnnotationMatching {
}
return mainType;
}
+
+ @SuppressWarnings("nls")
+ @Override
+ public String toString() {
+ if (this == NULL_ANNOTATIONS_OK) return "OK";
+ if (this == NULL_ANNOTATIONS_MISMATCH) return "MISMATCH";
+ if (this == NULL_ANNOTATIONS_OK_NONNULL) return "OK NonNull";
+ if (this == NULL_ANNOTATIONS_UNCHECKED) return "UNCHECKED";
+ StringBuilder buf = new StringBuilder();
+ buf.append("Analysis result: severity="+this.severity);
+ buf.append(" nullStatus="+this.nullStatus);
+ return buf.toString();
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
index 241dc3dd5..c641fcca2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedQualifiedTypeReference.java
@@ -103,7 +103,6 @@ public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeRefer
parameterizedType.boundCheck(scope, this.typeArguments[index]);
}
}
- checkNullConstraints(scope, this.typeArguments[index]);
}
public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) {
int totalDimensions = this.dimensions() + additionalDimensions;
@@ -216,9 +215,9 @@ public class ParameterizedQualifiedTypeReference extends ArrayQualifiedTypeRefer
TypeBinding type = internalResolveLeafType(scope, checkBounds);
createArrayType(scope);
resolveAnnotations(scope, location);
- if (this.typeArguments != null && checkBounds)
+ if (this.typeArguments != null)
// relevant null annotations are on the inner most type:
- checkNullConstraints(scope, this.typeArguments[this.typeArguments.length-1]);
+ checkIllegalNullAnnotations(scope, this.typeArguments[this.typeArguments.length-1]);
return type == null ? type : this.resolvedType;
}
private TypeBinding internalResolveLeafType(Scope scope, boolean checkBounds) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
index 4540e62f5..293f83191 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ParameterizedSingleTypeReference.java
@@ -92,14 +92,11 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference {
if (this.resolvedType.leafComponentType() instanceof ParameterizedTypeBinding) {
ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) this.resolvedType.leafComponentType();
- ReferenceBinding currentType = parameterizedType.genericType();
- TypeVariableBinding[] typeVariables = currentType.typeVariables();
TypeBinding[] argTypes = parameterizedType.arguments;
- if (argTypes != null && typeVariables != null) { // may be null in error cases
+ if (argTypes != null) { // may be null in error cases
parameterizedType.boundCheck(scope, this.typeArguments);
}
}
- checkNullConstraints(scope, this.typeArguments);
}
public TypeReference augmentTypeWithAdditionalDimensions(int additionalDimensions, Annotation [][] additionalAnnotations, boolean isVarargs) {
@@ -268,8 +265,6 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference {
// note: handling of arrays differs for role and regular types
if (len == 0) {
resolveAnnotations(scope, location);
- if (checkBounds)
- checkNullConstraints(scope, this.typeArguments);
return this.resolvedType; // we're done
}
@@ -302,21 +297,15 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference {
if (type == null) {
this.resolvedType = createArrayType(scope, this.resolvedType);
resolveAnnotations(scope, 0); // no defaultNullness for buggy type
- if (checkBounds)
- checkNullConstraints(scope, this.typeArguments);
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
- if (checkBounds)
- checkNullConstraints(scope, this.typeArguments);
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 (checkBounds)
- checkNullConstraints(scope, this.typeArguments);
return this.resolvedType; // pick up any annotated type.
}
}
@@ -458,6 +447,7 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference {
return null;
}
}
+
//{ObjectTeams: already done?
if (!isDiamond && argLength == 0)
return this.resolvedType;
@@ -472,7 +462,7 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference {
}
ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType(currentOriginal, argTypes, anchor, valParPos, enclosingType, currentAnnotations);
/* orig:
- ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType(currentOriginal, argTypes, enclosingType);
+ ParameterizedTypeBinding parameterizedType = scope.environment().createParameterizedType(currentOriginal, argTypes, enclosingType);
:giro */
// SH}
// check argument type compatibility for non <> cases - <> case needs no bounds check, we will scream foul if needed during inference.
@@ -487,6 +477,8 @@ public class ParameterizedSingleTypeReference extends ArrayTypeReference {
if (isTypeUseDeprecated(parameterizedType, scope))
reportDeprecatedType(parameterizedType, scope);
+ checkIllegalNullAnnotations(scope, this.typeArguments);
+
if (!this.resolvedType.isValidBinding()) {
return parameterizedType;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
index 7bd040497..47c44101b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedAllocationExpression.java
@@ -240,6 +240,7 @@ public static abstract class AbstractQualifiedAllocationExpression extends Alloc
}
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
+ cleanUpInferenceContexts();
if (!valueRequired)
currentScope.problemReporter().unusedObjectAllocation(this);
int pc = codeStream.position;
@@ -372,7 +373,7 @@ public static abstract class AbstractQualifiedAllocationExpression extends Alloc
if (this.binding instanceof ParameterizedGenericMethodBinding && this.typeArguments != null) {
TypeVariableBinding[] typeVariables = this.binding.original().typeVariables();
for (int i = 0; i < this.typeArguments.length; i++)
- this.typeArguments[i].checkNullConstraints(scope, typeVariables, i);
+ this.typeArguments[i].checkNullConstraints(scope, (ParameterizedGenericMethodBinding) this.binding, typeVariables, i);
}
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
index 78d7d9d30..d06692fff 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedNameReference.java
@@ -292,18 +292,18 @@ private void checkInternalNPE(BlockScope scope, FlowContext flowContext, FlowInf
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]);
+ 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]);
+ checkNullableFieldDereference(scope, this.otherBindings[i], this.sourcePositions[this.indexOfFirstFieldBinding+i], flowContext, 0);
}
}
}
-public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
- if (super.checkNPE(scope, flowContext, flowInfo)) {
+public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
+ if (super.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck)) {
return true;
}
FieldBinding fieldBinding = null;
@@ -318,7 +318,7 @@ public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flow
position = this.sourcePositions[this.sourcePositions.length - 1];
}
if (fieldBinding != null) {
- return checkNullableFieldDereference(scope, fieldBinding, position);
+ return checkNullableFieldDereference(scope, fieldBinding, position, flowContext, ttlForFieldCheck);
}
return false;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
index 281de66ff..a8cff6cdf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Reference.java
@@ -68,22 +68,26 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, Fl
return flowInfo;
}
-public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
+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);
+ return super.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck);
}
-protected boolean checkNullableFieldDereference(Scope scope, FieldBinding field, long sourcePosition) {
- // 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.tagBits & TagBits.AnnotationNullable) != 0) {
- scope.problemReporter().nullableFieldDereference(field, sourcePosition);
- return true;
+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.tagBits & TagBits.AnnotationNullable) != 0) {
+ scope.problemReporter().nullableFieldDereference(field, sourcePosition);
+ return true;
+ }
}
return false;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
index 1950dde5f..9f7216e75 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SingleNameReference.java
@@ -281,14 +281,12 @@ public TypeBinding checkFieldAccess(BlockScope scope) {
}
-public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
- if (!super.checkNPE(scope, flowContext, flowInfo)) {
+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) {
- VariableBinding var = nullAnnotatedVariableBinding(compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8);
- if (var instanceof FieldBinding) {
- checkNullableFieldDereference(scope, (FieldBinding) var, ((long)this.sourceStart<<32)+this.sourceEnd);
- return true;
+ if (this.binding instanceof FieldBinding) {
+ return checkNullableFieldDereference(scope, (FieldBinding) this.binding, ((long)this.sourceStart<<32)+this.sourceEnd, flowContext, ttlForFieldCheck);
}
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
index 9b7120fb6..12d85d563 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Statement.java
@@ -200,6 +200,11 @@ void internalAnalyseOneArgument18(BlockScope currentScope, FlowContext flowConte
// immediate reporting:
currentScope.problemReporter().nullityMismatchingTypeAnnotation(argument, argument.resolvedType, expectedType, annotationStatus);
} else if (annotationStatus.isAnyMismatch() || (statusFromAnnotatedNull & FlowInfo.POTENTIALLY_NULL) != 0) {
+ if (!expectedType.hasNullTypeAnnotations() && expectedNonNullness == Boolean.TRUE) {
+ // improve problem rendering when using a declaration annotation in a 1.8 setting
+ LookupEnvironment env = currentScope.environment();
+ expectedType = env.createAnnotatedType(expectedType, new AnnotationBinding[] {env.getNonNullAnnotation()});
+ }
flowContext.recordNullityMismatch(currentScope, argument, argument.resolvedType, expectedType, flowInfo, nullStatus, annotationStatus);
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
index 5f6e1110d..bd51350fd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SwitchStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -79,7 +79,7 @@ public class SwitchStatement extends Statement {
if ((this.expression.implicitConversion & TypeIds.UNBOXING) != 0
|| (this.expression.resolvedType != null
&& (this.expression.resolvedType.id == T_JavaLangString || this.expression.resolvedType.isEnum()))) {
- this.expression.checkNPE(currentScope, flowContext, flowInfo);
+ this.expression.checkNPE(currentScope, flowContext, flowInfo, 1);
}
SwitchFlowContext switchContext =
new SwitchFlowContext(flowContext, this, (this.breakLabel = new BranchLabel()), true);
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java
index cd2c2a408..61d86d63d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/SynchronizedStatement.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2011, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* 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;
@@ -170,31 +171,31 @@ 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)
- return;
- 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;
+ 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;
+ }
+ //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);
}
- //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);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java
index b9e751876..76c802117 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ThisReference.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -78,7 +78,7 @@ public class ThisReference extends Reference {
return true;
}
- public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo) {
+ public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
return true; // never problematic
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
index 0822a281a..0101b0d5c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/TypeReference.java
@@ -842,42 +842,39 @@ protected void resolveAnnotations(Scope scope, int location) {
public int getAnnotatableLevels() {
return 1;
}
-/** Check all typeArguments against null constraints on their corresponding type variables. */
-protected void checkNullConstraints(Scope scope, TypeReference[] typeArguments) {
- if (scope.environment().usesNullTypeAnnotations()
- && typeArguments != null)
- {
- TypeVariableBinding[] typeVariables = this.resolvedType.original().typeVariables();
+/** 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.checkNullConstraints(scope, typeVariables, i);
+ arg.checkIllegalNullAnnotation(scope);
}
}
}
/** Check whether this type reference conforms to the null constraints defined for the corresponding type variable. */
-protected void checkNullConstraints(Scope scope, TypeBinding[] variables, int rank) {
+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, -1, CheckMode.BOUND_CHECK).isAnyMismatch())
+ if (NullAnnotationMatching.analyse(variable, this.resolvedType, null, substitution, -1, CheckMode.BOUND_CHECK).isAnyMismatch())
scope.problemReporter().nullityMismatchTypeArgument(variable, this.resolvedType, this);
}
}
- if (this.resolvedType.leafComponentType().isBaseType() && hasNullTypeAnnotation(AnnotationPosition.LEAF_TYPE)) {
- scope.problemReporter().illegalAnnotationForBaseType(this, this.annotations[0], this.resolvedType.tagBits & TagBits.AnnotationNullMASK);
- }
+ 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 annId = nullTagBits == TagBits.AnnotationNonNull ? TypeIds.T_ConfiguredAnnotationNonNull : TypeIds.T_ConfiguredAnnotationNullable;
+ int annBit = nullTagBits == TagBits.AnnotationNonNull ? TypeIds.BitNonNullAnnotation : TypeIds.BitNullableAnnotation;
for (int i = 0; i < innerAnnotations.length; i++) {
- if (innerAnnotations[i] != null
- && innerAnnotations[i].resolvedType != null
- && innerAnnotations[i].resolvedType.id == annId)
+ if (innerAnnotations[i] != null && innerAnnotations[i].hasNullBit(annBit))
return innerAnnotations[i];
}
}
@@ -901,10 +898,7 @@ public boolean hasNullTypeAnnotation(AnnotationPosition position) {
public static boolean containsNullAnnotation(Annotation[] annotations) {
if (annotations != null) {
for (int i = 0; i < annotations.length; i++) {
- if (annotations[i] != null
- && annotations[i].resolvedType != null
- && (annotations[i].resolvedType.id == TypeIds.T_ConfiguredAnnotationNonNull
- || annotations[i].resolvedType.id == TypeIds.T_ConfiguredAnnotationNullable))
+ if (annotations[i] != null && (annotations[i].hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)))
return true;
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
index dc163a571..4828a697c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ClassFileReader.java
@@ -31,6 +31,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
import org.eclipse.jdt.internal.compiler.codegen.AttributeNamesConstants;
import org.eclipse.jdt.internal.compiler.env.*;
import org.eclipse.jdt.internal.compiler.impl.Constant;
@@ -1149,6 +1150,9 @@ public boolean hasStructuralChanges(byte[] newBytes, boolean orderRequired, bool
// annotations
if (hasStructuralAnnotationChanges(getAnnotations(), newClassFile.getAnnotations()))
return true;
+ if (this.version >= ClassFileConstants.JDK1_8
+ && hasStructuralTypeAnnotationChanges(getTypeAnnotations(), newClassFile.getTypeAnnotations()))
+ return true;
// generic signature
if (!CharOperation.equals(getGenericSignature(), newClassFile.getGenericSignature()))
@@ -1275,43 +1279,48 @@ private boolean hasStructuralAnnotationChanges(IBinaryAnnotation[] currentAnnota
if (currentAnnotationsLength != otherAnnotationsLength)
return true;
for (int i = 0; i < currentAnnotationsLength; i++) {
- if (!CharOperation.equals(currentAnnotations[i].getTypeName(), otherAnnotations[i].getTypeName()))
- return true;
- IBinaryElementValuePair[] currentPairs = currentAnnotations[i].getElementValuePairs();
- IBinaryElementValuePair[] otherPairs = otherAnnotations[i].getElementValuePairs();
- int currentPairsLength = currentPairs == null ? 0 : currentPairs.length;
- int otherPairsLength = otherPairs == null ? 0 : otherPairs.length;
- if (currentPairsLength != otherPairsLength)
- return true;
- for (int j = 0; j < currentPairsLength; j++) {
- if (!CharOperation.equals(currentPairs[j].getName(), otherPairs[j].getName()))
- return true;
- final Object value = currentPairs[j].getValue();
- final Object value2 = otherPairs[j].getValue();
- if (value instanceof Object[]) {
- Object[] currentValues = (Object[]) value;
- if (value2 instanceof Object[]) {
- Object[] currentValues2 = (Object[]) value2;
- final int length = currentValues.length;
- if (length != currentValues2.length) {
- return true;
- }
- for (int n = 0; n < length; n++) {
- if (!currentValues[n].equals(currentValues2[n])) {
- return true;
- }
+ Boolean match = matchAnnotations(currentAnnotations[i], otherAnnotations[i]);
+ if (match != null)
+ return match.booleanValue();
+ }
+ return false;
+}
+private Boolean matchAnnotations(IBinaryAnnotation currentAnnotation, IBinaryAnnotation otherAnnotation) {
+ if (!CharOperation.equals(currentAnnotation.getTypeName(), otherAnnotation.getTypeName()))
+ return true;
+ IBinaryElementValuePair[] currentPairs = currentAnnotation.getElementValuePairs();
+ IBinaryElementValuePair[] otherPairs = otherAnnotation.getElementValuePairs();
+ int currentPairsLength = currentPairs == null ? 0 : currentPairs.length;
+ int otherPairsLength = otherPairs == null ? 0 : otherPairs.length;
+ if (currentPairsLength != otherPairsLength)
+ return Boolean.TRUE;
+ for (int j = 0; j < currentPairsLength; j++) {
+ if (!CharOperation.equals(currentPairs[j].getName(), otherPairs[j].getName()))
+ return Boolean.TRUE;
+ final Object value = currentPairs[j].getValue();
+ final Object value2 = otherPairs[j].getValue();
+ if (value instanceof Object[]) {
+ Object[] currentValues = (Object[]) value;
+ if (value2 instanceof Object[]) {
+ Object[] currentValues2 = (Object[]) value2;
+ final int length = currentValues.length;
+ if (length != currentValues2.length) {
+ return Boolean.TRUE;
+ }
+ for (int n = 0; n < length; n++) {
+ if (!currentValues[n].equals(currentValues2[n])) {
+ return Boolean.TRUE;
}
- return false;
}
- return true;
- } else if (!value.equals(value2)) {
- return true;
+ return Boolean.FALSE;
}
+ return Boolean.TRUE;
+ } else if (!value.equals(value2)) {
+ return Boolean.TRUE;
}
}
- return false;
+ return null;
}
-
private boolean hasStructuralFieldChanges(FieldInfo currentFieldInfo, FieldInfo otherFieldInfo) {
// generic signature
if (!CharOperation.equals(currentFieldInfo.getGenericSignature(), otherFieldInfo.getGenericSignature()))
@@ -1322,6 +1331,9 @@ private boolean hasStructuralFieldChanges(FieldInfo currentFieldInfo, FieldInfo
return true;
if (hasStructuralAnnotationChanges(currentFieldInfo.getAnnotations(), otherFieldInfo.getAnnotations()))
return true;
+ if (this.version >= ClassFileConstants.JDK1_8
+ && hasStructuralTypeAnnotationChanges(currentFieldInfo.getTypeAnnotations(), otherFieldInfo.getTypeAnnotations()))
+ return true;
if (!CharOperation.equals(currentFieldInfo.getName(), otherFieldInfo.getName()))
return true;
if (!CharOperation.equals(currentFieldInfo.getTypeName(), otherFieldInfo.getTypeName()))
@@ -1378,6 +1390,9 @@ private boolean hasStructuralMethodChanges(MethodInfo currentMethodInfo, MethodI
if (hasStructuralAnnotationChanges(currentMethodInfo.getParameterAnnotations(i, this.classFileName), otherMethodInfo.getParameterAnnotations(i, this.classFileName)))
return true;
}
+ if (this.version >= ClassFileConstants.JDK1_8
+ && hasStructuralTypeAnnotationChanges(currentMethodInfo.getTypeAnnotations(), otherMethodInfo.getTypeAnnotations()))
+ return true;
if (!CharOperation.equals(currentMethodInfo.getSelector(), otherMethodInfo.getSelector()))
return true;
@@ -1400,6 +1415,45 @@ private boolean hasStructuralMethodChanges(MethodInfo currentMethodInfo, MethodI
return false;
}
+private boolean hasStructuralTypeAnnotationChanges(IBinaryTypeAnnotation[] currentTypeAnnotations, IBinaryTypeAnnotation[] otherTypeAnnotations) {
+ if (otherTypeAnnotations != null) {
+ // copy so we can delete matched annotations:
+ int len = otherTypeAnnotations.length;
+ System.arraycopy(otherTypeAnnotations, 0, otherTypeAnnotations = new IBinaryTypeAnnotation[len], 0, len);
+ }
+ if (currentTypeAnnotations != null) {
+ loopCurrent:
+ for (IBinaryTypeAnnotation currentAnnotation : currentTypeAnnotations) {
+ if (!affectsSignature(currentAnnotation)) continue;
+ if (otherTypeAnnotations == null)
+ return true;
+ for (int i = 0; i < otherTypeAnnotations.length; i++) {
+ IBinaryTypeAnnotation otherAnnotation = otherTypeAnnotations[i];
+ if (otherAnnotation != null && matchAnnotations(currentAnnotation.getAnnotation(), otherAnnotation.getAnnotation()) == Boolean.TRUE) {
+ otherTypeAnnotations[i] = null; // matched
+ continue loopCurrent;
+ }
+ }
+ return true; // not matched
+ }
+ }
+ if (otherTypeAnnotations != null) {
+ for (IBinaryTypeAnnotation otherAnnotation : otherTypeAnnotations) {
+ if (affectsSignature(otherAnnotation))
+ return true;
+ }
+ }
+ return false;
+}
+
+private boolean affectsSignature(IBinaryTypeAnnotation typeAnnotation) {
+ if (typeAnnotation == null) return false;
+ int targetType = typeAnnotation.getTargetType();
+ if (targetType >= AnnotationTargetTypeConstants.LOCAL_VARIABLE && targetType <= AnnotationTargetTypeConstants.METHOD_REFERENCE_TYPE_ARGUMENT)
+ return false; // affects detail within a block
+ return true;
+}
+
/**
* This method is used to fully initialize the contents of the receiver. All methodinfos, fields infos
* will be therefore fully initialized and we can get rid of the bytes.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java
index bdce24ef5..cbb2bc1ca 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/classfmt/ExternalAnnotationProvider.java
@@ -146,7 +146,7 @@ public class ExternalAnnotationProvider {
* Assert that the given line is a class header for 'typeName' (slash-separated qualified name).
*/
public static void assertClassHeader(String line, String typeName) throws IOException {
- if (line.startsWith(CLASS_PREFIX)) {
+ if (line != null && line.startsWith(CLASS_PREFIX)) {
line = line.substring(CLASS_PREFIX.length());
} else {
throw new IOException("missing class header in annotation file"); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
index 383f3d1be..eb58e53ca 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/codegen/CodeStream.java
@@ -3491,8 +3491,17 @@ public static TypeBinding getConstantPoolDeclaringClass(Scope currentScope, Meth
&& (options.complianceLevel >= ClassFileConstants.JDK1_4 || !(isImplicitThisReceiver && codegenBinding.isStatic()))
&& codegenBinding.declaringClass.id != TypeIds.T_JavaLangObject) // no change for Object methods
|| !codegenBinding.declaringClass.canBeSeenBy(currentScope)) {
- if (!actualReceiverType.isIntersectionType18()) // no constant pool representation. FIXME, visibility issue not handled.
+ if (actualReceiverType.isIntersectionType18()) {
+ TypeBinding[] intersectingTypes = ((IntersectionTypeBinding18)actualReceiverType).getIntersectingTypes();
+ for(int i = 0; i < intersectingTypes.length; i++) {
+ if (intersectingTypes[i].findSuperTypeOriginatingFrom(constantPoolDeclaringClass) != null) {
+ constantPoolDeclaringClass = intersectingTypes[i];
+ break;
+ }
+ }
+ } else {
constantPoolDeclaringClass = actualReceiverType.erasure();
+ }
}
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
index c6dcc0aa3..6b1a868d9 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowContext.java
@@ -82,10 +82,10 @@ public class FlowContext implements TypeConstants {
public TypeBinding[][] providedExpectedTypes = null;
// record field references known to be non-null
- // this array will never shrink, only grow. reset happens by nulling the first cell
- // adding elements after reset ensures that the valid part of the array is always null-terminated
+ // this array will never shrink, only grow. reset happens by nulling expired entries
+ // this array grows in lock step with timesToLiveForNullCheckInfo, which controls expiration
private Reference[] nullCheckedFieldReferences = null;
- private int timeToLiveForNullCheckInfo = -1;
+ private int[] timesToLiveForNullCheckInfo = null;
public static final int DEFER_NULL_DIAGNOSTIC = 0x1;
public static final int PREEMPT_NULL_DIAGNOSTIC = 0x2;
@@ -131,6 +131,7 @@ public FlowContext(FlowContext parent, ASTNode associatedNode) {
this.initsOnFinally = parent.initsOnFinally;
this.conditionalLevel = parent.conditionalLevel;
this.nullCheckedFieldReferences = parent.nullCheckedFieldReferences; // re-use list if there is one
+ this.timesToLiveForNullCheckInfo = parent.timesToLiveForNullCheckInfo;
}
}
@@ -141,33 +142,35 @@ public FlowContext(FlowContext parent, ASTNode associatedNode) {
* @param timeToLive control how many expire events are needed to expire this information
*/
public void recordNullCheckedFieldReference(Reference reference, int timeToLive) {
- this.timeToLiveForNullCheckInfo = timeToLive;
if (this.nullCheckedFieldReferences == null) {
// first entry:
- this.nullCheckedFieldReferences = new Reference[2];
- this.nullCheckedFieldReferences[0] = reference;
+ this.nullCheckedFieldReferences = new Reference[] { reference, null };
+ this.timesToLiveForNullCheckInfo = new int[] { timeToLive, -1 };
} else {
int len = this.nullCheckedFieldReferences.length;
// insert into first empty slot:
for (int i=0; i<len; i++) {
if (this.nullCheckedFieldReferences[i] == null) {
this.nullCheckedFieldReferences[i] = reference;
- if (i+1 < len) {
- this.nullCheckedFieldReferences[i+1] = null; // lazily mark next as empty
- }
+ this.timesToLiveForNullCheckInfo[i] = timeToLive;
return;
}
}
- // grow array:
+ // grow arrays:
System.arraycopy(this.nullCheckedFieldReferences, 0, this.nullCheckedFieldReferences=new Reference[len+2], 0, len);
+ System.arraycopy(this.timesToLiveForNullCheckInfo, 0, this.timesToLiveForNullCheckInfo=new int[len+2], 0, len);
this.nullCheckedFieldReferences[len] = reference;
+ this.timesToLiveForNullCheckInfo[len] = timeToLive;
}
}
/** If a null checked field has been recorded recently, increase its time to live. */
public void extendTimeToLiveForNullCheckedField(int t) {
- if (this.timeToLiveForNullCheckInfo > 0)
- this.timeToLiveForNullCheckInfo += t;
+ if (this.timesToLiveForNullCheckInfo != null) {
+ for (int i = 0; i < this.timesToLiveForNullCheckInfo.length; i++)
+ if (this.timesToLiveForNullCheckInfo[i] > 0)
+ this.timesToLiveForNullCheckInfo[i] += t;
+ }
}
/**
@@ -178,8 +181,9 @@ public void extendTimeToLiveForNullCheckedField(int t) {
*/
public void expireNullCheckedFieldInfo() {
if (this.nullCheckedFieldReferences != null) {
- if (--this.timeToLiveForNullCheckInfo == 0) {
- this.nullCheckedFieldReferences[0] = null; // lazily wipe
+ for (int i = 0; i < this.nullCheckedFieldReferences.length; i++) {
+ if (--this.timesToLiveForNullCheckInfo[i] == 0)
+ this.nullCheckedFieldReferences[i] = null;
}
}
}
@@ -196,7 +200,7 @@ public boolean isNullcheckedFieldAccess(Reference reference) {
for (int i=0; i<len; i++) {
Reference checked = this.nullCheckedFieldReferences[i];
if (checked == null) {
- return false;
+ continue;
}
if (checked.isEquivalent(reference)) {
return true;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
index ff1a847fd..4ba481557 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/CompilerOptions.java
@@ -262,6 +262,9 @@ public class CompilerOptions {
public static final String OPTION_NullableAnnotationName = "org.eclipse.jdt.core.compiler.annotation.nullable"; //$NON-NLS-1$
public static final String OPTION_NonNullAnnotationName = "org.eclipse.jdt.core.compiler.annotation.nonnull"; //$NON-NLS-1$
public static final String OPTION_NonNullByDefaultAnnotationName = "org.eclipse.jdt.core.compiler.annotation.nonnullbydefault"; //$NON-NLS-1$
+ public static final String OPTION_NullableAnnotationSecondaryNames = "org.eclipse.jdt.core.compiler.annotation.nullable.secondary"; //$NON-NLS-1$
+ public static final String OPTION_NonNullAnnotationSecondaryNames = "org.eclipse.jdt.core.compiler.annotation.nonnull.secondary"; //$NON-NLS-1$
+ public static final String OPTION_NonNullByDefaultAnnotationSecondaryNames = "org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary"; //$NON-NLS-1$
public static final String OPTION_ReportUninternedIdentityComparison = "org.eclipse.jdt.core.compiler.problem.uninternedIdentityComparison"; //$NON-NLS-1$
// defaults for the above:
static final char[][] DEFAULT_NULLABLE_ANNOTATION_NAME = CharOperation.splitOn('.', "org.eclipse.jdt.annotation.Nullable".toCharArray()); //$NON-NLS-1$
@@ -303,6 +306,8 @@ public class CompilerOptions {
public static final String NO_TAG = "no_tag"; //$NON-NLS-1$
public static final String ALL_STANDARD_TAGS = "all_standard_tags"; //$NON-NLS-1$
+ private static final String[] NO_STRINGS = new String[0];
+
/**
* Bit mask for configurable problems (error/warning threshold)
* Note: bitmask assumes 3 highest bits to denote irritant group (to allow storing 8 groups of 29 bits each
@@ -572,6 +577,12 @@ public class CompilerOptions {
public char[][] nonNullAnnotationName;
/** Fully qualified name of annotation to use as marker for default nonnull. */
public char[][] nonNullByDefaultAnnotationName;
+ /** Fully qualified names of secondary annotations to use as marker for nullable types. */
+ public String[] nullableAnnotationSecondaryNames = NO_STRINGS;
+ /** Fully qualified names of secondary annotations to use as marker for nonnull types. */
+ public String[] nonNullAnnotationSecondaryNames = NO_STRINGS;
+ /** Fully qualified names of secondary annotations to use as marker for default nonnull. */
+ public String[] nonNullByDefaultAnnotationSecondaryNames = NO_STRINGS;
/** TagBits-encoded default for non-annotated types. */
public long intendedDefaultNonNullness; // 0 or TagBits#AnnotationNonNull
/** Should resources (objects of type Closeable) be analysed for matching calls to close()? */
@@ -1534,6 +1545,9 @@ public class CompilerOptions {
optionsMap.put(OPTION_NullableAnnotationName, String.valueOf(CharOperation.concatWith(this.nullableAnnotationName, '.')));
optionsMap.put(OPTION_NonNullAnnotationName, String.valueOf(CharOperation.concatWith(this.nonNullAnnotationName, '.')));
optionsMap.put(OPTION_NonNullByDefaultAnnotationName, String.valueOf(CharOperation.concatWith(this.nonNullByDefaultAnnotationName, '.')));
+ optionsMap.put(OPTION_NullableAnnotationSecondaryNames, nameListToString(this.nullableAnnotationSecondaryNames));
+ optionsMap.put(OPTION_NonNullAnnotationSecondaryNames, nameListToString(this.nonNullAnnotationSecondaryNames));
+ optionsMap.put(OPTION_NonNullByDefaultAnnotationSecondaryNames, nameListToString(this.nonNullByDefaultAnnotationSecondaryNames));
optionsMap.put(OPTION_ReportMissingNonNullByDefaultAnnotation, getSeverityString(MissingNonNullByDefaultAnnotation));
optionsMap.put(OPTION_ReportUnusedTypeParameter, getSeverityString(UnusedTypeParameter));
optionsMap.put(OPTION_SyntacticNullAnalysisForFields, this.enableSyntacticNullAnalysisForFields ? ENABLED : DISABLED);
@@ -2112,6 +2126,15 @@ public class CompilerOptions {
if ((optionValue = optionsMap.get(OPTION_NonNullByDefaultAnnotationName)) != null) {
this.nonNullByDefaultAnnotationName = CharOperation.splitAndTrimOn('.', optionValue.toCharArray());
}
+ if ((optionValue = optionsMap.get(OPTION_NullableAnnotationSecondaryNames)) != null) {
+ this.nullableAnnotationSecondaryNames = stringToNameList(optionValue);
+ }
+ if ((optionValue = optionsMap.get(OPTION_NonNullAnnotationSecondaryNames)) != null) {
+ this.nonNullAnnotationSecondaryNames = stringToNameList(optionValue);
+ }
+ if ((optionValue = optionsMap.get(OPTION_NonNullByDefaultAnnotationSecondaryNames)) != null) {
+ this.nonNullByDefaultAnnotationSecondaryNames = stringToNameList(optionValue);
+ }
if ((optionValue = optionsMap.get(OPTION_ReportMissingNonNullByDefaultAnnotation)) != null) updateSeverity(MissingNonNullByDefaultAnnotation, optionValue);
if ((optionValue = optionsMap.get(OPTION_SyntacticNullAnalysisForFields)) != null) {
this.enableSyntacticNullAnalysisForFields = ENABLED.equals(optionValue);
@@ -2257,6 +2280,26 @@ public class CompilerOptions {
}
}
}
+
+ private String[] stringToNameList(String optionValue) {
+ String[] result = optionValue.split(","); //$NON-NLS-1$
+ if (result == null)
+ return NO_STRINGS;
+ for (int i = 0; i < result.length; i++)
+ result[i] = result[i].trim();
+ return result;
+ }
+
+ String nameListToString(String[] names) {
+ if (names == null) return ""; //$NON-NLS-1$
+ StringBuilder buf = new StringBuilder();
+ for (int i = 0; i < names.length; i++) {
+ if (i > 0) buf.append(',');
+ buf.append(names[i]);
+ }
+ return buf.toString();
+ }
+
public String toString() {
StringBuffer buf = new StringBuffer("CompilerOptions:"); //$NON-NLS-1$
buf.append("\n\t- local variables debug attributes: ").append((this.produceDebugAttributes & ClassFileConstants.ATTR_VARS) != 0 ? "ON" : " OFF"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
index ac12a5e08..f4c1572cf 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ArrayBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -414,15 +414,12 @@ public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNull
for (int i = 0, length = annotations.length; i < length; i++) {
AnnotationBinding annotation = annotations[i];
if (annotation != null) {
- switch (annotation.type.id) {
- case TypeIds.T_ConfiguredAnnotationNullable :
- nullTagBits |= TagBits.AnnotationNullable;
- this.tagBits |= TagBits.HasNullTypeAnnotation;
- break;
- case TypeIds.T_ConfiguredAnnotationNonNull :
- nullTagBits |= TagBits.AnnotationNonNull;
- this.tagBits |= TagBits.HasNullTypeAnnotation;
- break;
+ if (annotation.type.hasNullBit(TypeIds.BitNullableAnnotation)) {
+ nullTagBits |= TagBits.AnnotationNullable;
+ this.tagBits |= TagBits.HasNullTypeAnnotation;
+ } else if (annotation.type.hasNullBit(TypeIds.BitNonNullAnnotation)) {
+ nullTagBits |= TagBits.AnnotationNonNull;
+ this.tagBits |= TagBits.HasNullTypeAnnotation;
}
} else {
// null signals end of annotations for the current dimension in the serialized form.
@@ -507,4 +504,10 @@ public TypeBinding uncapture(Scope scope) {
public boolean acceptsNonNullDefault() {
return true;
}
+@Override
+public long updateTagBits() {
+ if (this.leafComponentType != null)
+ this.tagBits |= this.leafComponentType.updateTagBits();
+ return super.updateTagBits();
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
index 4b534395e..4ba51baa1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
@@ -751,10 +751,9 @@ private ITypeAnnotationWalker getTypeAnnotationWalker(IBinaryTypeAnnotation[] an
private int getNullDefaultFrom(IBinaryAnnotation[] declAnnotations) {
if (declAnnotations != null) {
- char[][] nonNullByDefaultAnnotationName = this.environment.getNonNullByDefaultAnnotationName();
for (IBinaryAnnotation annotation : declAnnotations) {
char[][] typeName = signature2qualifiedTypeName(annotation.getTypeName());
- if (CharOperation.equals(typeName, nonNullByDefaultAnnotationName))
+ if (this.environment.getNullAnnotationBit(typeName) == TypeIds.BitNonNullByDefaultAnnotation)
return getNonNullByDefaultValue(annotation);
}
}
@@ -1958,10 +1957,6 @@ private void scanFieldForNullAnnotation(IBinaryField field, FieldBinding fieldBi
}
// global option is checked by caller
- char[][] nullableAnnotationName = this.environment.getNullableAnnotationName();
- char[][] nonNullAnnotationName = this.environment.getNonNullAnnotationName();
- if (nullableAnnotationName == null || nonNullAnnotationName == null)
- return; // not well-configured to use null annotations
if (fieldBinding.type == null || fieldBinding.type.isBaseType())
return; // null annotations are only applied to reference types
@@ -1975,13 +1970,13 @@ private void scanFieldForNullAnnotation(IBinaryField field, FieldBinding fieldBi
char[] annotationTypeName = annotations[i].getTypeName();
if (annotationTypeName[0] != Util.C_RESOLVED)
continue;
- char[][] typeName = signature2qualifiedTypeName(annotationTypeName);
- if (CharOperation.equals(typeName, nonNullAnnotationName)) {
+ int typeBit = this.environment.getNullAnnotationBit(signature2qualifiedTypeName(annotationTypeName));
+ if (typeBit == TypeIds.BitNonNullAnnotation) {
fieldBinding.tagBits |= TagBits.AnnotationNonNull;
explicitNullness = true;
break;
}
- if (CharOperation.equals(typeName, nullableAnnotationName)) {
+ if (typeBit == TypeIds.BitNullableAnnotation) {
fieldBinding.tagBits |= TagBits.AnnotationNullable;
explicitNullness = true;
break;
@@ -2015,11 +2010,6 @@ private void scanMethodForNullAnnotation(IBinaryMethod method, MethodBinding met
return;
}
}
- char[][] nullableAnnotationName = this.environment.getNullableAnnotationName();
- char[][] nonNullAnnotationName = this.environment.getNonNullAnnotationName();
- char[][] nonNullByDefaultAnnotationName = this.environment.getNonNullByDefaultAnnotationName();
- if (nullableAnnotationName == null || nonNullAnnotationName == null || nonNullByDefaultAnnotationName == null)
- return; // not well-configured to use null annotations
// return:
ITypeAnnotationWalker returnWalker = externalAnnotationWalker.toMethodReturn();
@@ -2031,16 +2021,21 @@ private void scanMethodForNullAnnotation(IBinaryMethod method, MethodBinding met
char[] annotationTypeName = annotations[i].getTypeName();
if (annotationTypeName[0] != Util.C_RESOLVED)
continue;
- char[][] typeName = signature2qualifiedTypeName(annotationTypeName);
- if (CharOperation.equals(typeName, nonNullByDefaultAnnotationName)) {
+ int typeBit = this.environment.getNullAnnotationBit(signature2qualifiedTypeName(annotationTypeName));
+ if (typeBit == TypeIds.BitNonNullByDefaultAnnotation) {
methodBinding.defaultNullness = getNonNullByDefaultValue(annotations[i]);
- if (methodBinding.defaultNullness == Binding.NULL_UNSPECIFIED_BY_DEFAULT)
+ if (methodBinding.defaultNullness == Binding.NULL_UNSPECIFIED_BY_DEFAULT) {
methodBinding.tagBits |= TagBits.AnnotationNullUnspecifiedByDefault;
- else if (methodBinding.defaultNullness != 0)
+ } else if (methodBinding.defaultNullness != 0) {
methodBinding.tagBits |= TagBits.AnnotationNonNullByDefault;
- } else if (CharOperation.equals(typeName, nonNullAnnotationName)) {
+ if (methodBinding.defaultNullness == Binding.NONNULL_BY_DEFAULT && this.environment.usesNullTypeAnnotations()) {
+ // reading a decl-nnbd in a project using type annotations, mimic corresponding semantics by enumerating:
+ methodBinding.defaultNullness |= Binding.DefaultLocationParameter | Binding.DefaultLocationReturnType;
+ }
+ }
+ } else if (typeBit == TypeIds.BitNonNullAnnotation) {
methodBinding.tagBits |= TagBits.AnnotationNonNull;
- } else if (CharOperation.equals(typeName, nullableAnnotationName)) {
+ } else if (typeBit == TypeIds.BitNullableAnnotation) {
methodBinding.tagBits |= TagBits.AnnotationNullable;
}
}
@@ -2065,13 +2060,13 @@ private void scanMethodForNullAnnotation(IBinaryMethod method, MethodBinding met
char[] annotationTypeName = paramAnnotations[i].getTypeName();
if (annotationTypeName[0] != Util.C_RESOLVED)
continue;
- char[][] typeName = signature2qualifiedTypeName(annotationTypeName);
- if (CharOperation.equals(typeName, nonNullAnnotationName)) {
+ int typeBit = this.environment.getNullAnnotationBit(signature2qualifiedTypeName(annotationTypeName));
+ if (typeBit == TypeIds.BitNonNullAnnotation) {
if (methodBinding.parameterNonNullness == null)
methodBinding.parameterNonNullness = new Boolean[numVisibleParams];
methodBinding.parameterNonNullness[j] = Boolean.TRUE;
break;
- } else if (CharOperation.equals(typeName, nullableAnnotationName)) {
+ } else if (typeBit == TypeIds.BitNullableAnnotation) {
if (methodBinding.parameterNonNullness == null)
methodBinding.parameterNonNullness = new Boolean[numVisibleParams];
methodBinding.parameterNonNullness[j] = Boolean.FALSE;
@@ -2103,14 +2098,18 @@ private void scanTypeForNullDefaultAnnotation(IBinaryType binaryType, PackageBin
char[] annotationTypeName = annotations[i].getTypeName();
if (annotationTypeName[0] != Util.C_RESOLVED)
continue;
- char[][] typeName = signature2qualifiedTypeName(annotationTypeName);
- if (CharOperation.equals(typeName, nonNullByDefaultAnnotationName)) {
+ int typeBit = this.environment.getNullAnnotationBit(signature2qualifiedTypeName(annotationTypeName));
+ if (typeBit == TypeIds.BitNonNullByDefaultAnnotation) {
// using NonNullByDefault we need to inspect the details of the value() attribute:
nullness = getNonNullByDefaultValue(annotations[i]);
if (nullness == NULL_UNSPECIFIED_BY_DEFAULT) {
annotationBit = TagBits.AnnotationNullUnspecifiedByDefault;
} else if (nullness != 0) {
annotationBit = TagBits.AnnotationNonNullByDefault;
+ if (nullness == Binding.NONNULL_BY_DEFAULT && this.environment.usesNullTypeAnnotations()) {
+ // reading a decl-nnbd in a project using type annotations, mimic corresponding semantics by enumerating:
+ nullness |= Binding.DefaultLocationParameter | Binding.DefaultLocationReturnType | Binding.DefaultLocationField;
+ }
}
this.defaultNullness = nullness;
break;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
index 869e8b8e9..ee47b4da4 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/BoundSet.java
@@ -590,8 +590,10 @@ class BoundSet {
// not per JLS: if the new constraint relates types where at least one has a null annotations,
// record all null tagBits as hints for the final inference solution.
long nullHints = (newConstraint.left.tagBits | newConstraint.right.tagBits) & TagBits.AnnotationNullMASK;
- boundI.nullHints |= nullHints;
- boundJ.nullHints |= nullHints;
+ if (nullHints != 0 && TypeBinding.equalsEquals(boundI.left, boundJ.left)) {
+ boundI.nullHints |= nullHints;
+ boundJ.nullHints |= nullHints;
+ }
}
}
ConstraintFormula[] typeArgumentConstraints = deriveTypeArgumentConstraints ? deriveTypeArgumentConstraints(boundI, boundJ) : null;
@@ -778,9 +780,12 @@ class BoundSet {
// α = U and S <: T imply ⟨S[α:=U] <: T[α:=U]⟩
TypeBinding u = boundS.right;
if (u.isProperType(true)) {
- TypeBinding left = (TypeBinding.equalsEquals(alpha, boundT.left)) ? u : boundT.left;
+ boolean substitute = TypeBinding.equalsEquals(alpha, boundT.left);
+ TypeBinding left = substitute ? u : boundT.left;
TypeBinding right = boundT.right.substituteInferenceVariable(alpha, u);
- return ConstraintTypeFormula.create(left, right, boundT.relation, boundT.isSoft||boundS.isSoft);
+ substitute |= TypeBinding.notEquals(right, boundT.right);
+ if (substitute) // avoid redundant constraint
+ return ConstraintTypeFormula.create(left, right, boundT.relation, boundT.isSoft||boundS.isSoft);
}
return null;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
index e430d9b1f..c6f68376e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ClassScope.java
@@ -1682,7 +1682,7 @@ public class ClassScope extends Scope {
sourceType.tagBits |= (superType.tagBits & TagBits.HierarchyHasProblems); // propagate if missing supertpye
sourceType.setSuperClass(superType);
// bound check (in case of bogus definition of Enum type)
- if (refTypeVariables[0].boundCheck(superType, sourceType, this) != TypeConstants.OK) {
+ if (!refTypeVariables[0].boundCheck(superType, sourceType, this, null).isOKbyJLS()) {
problemReporter().typeMismatchError(rootEnumType, refTypeVariables[0], sourceType, null);
}
return !foundCycle;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
index 1f013a4cd..96ae35acd 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/CompilationUnitScope.java
@@ -17,6 +17,8 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
+import java.util.ArrayList;
+
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.ast.*;
@@ -91,6 +93,7 @@ public class CompilationUnitScope extends Scope {
private boolean skipCachingImports;
boolean connectingHierarchy;
+ private ArrayList<Invocation> inferredInvocations;
//{ObjectTeams: when used as a baseimport scope, remember the original scope during this current lookup
public Scope originalScope;
// SH}
@@ -1296,4 +1299,16 @@ public boolean hasDefaultNullnessFor(int location) {
return (this.fPackage.defaultNullness & location) != 0;
return false;
}
+public void registerInferredInvocation(Invocation invocation) {
+ if (this.inferredInvocations == null)
+ this.inferredInvocations = new ArrayList<>();
+ this.inferredInvocations.add(invocation);
+}
+public void cleanUpInferenceContexts() {
+ if (this.inferredInvocations == null)
+ return;
+ for (Invocation invocation : this.inferredInvocations)
+ invocation.cleanUpInferenceContexts();
+ this.inferredInvocations = null;
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
index 10675ce15..7247fc3bb 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ImplicitNullAnnotationVerifier.java
@@ -306,7 +306,7 @@ public class ImplicitNullAnnotationVerifier {
ParameterizedGenericMethodBinding substitute = this.environment.createParameterizedGenericMethod(currentMethod, typeVariables);
substituteReturnType = substitute.returnType;
}
- if (NullAnnotationMatching.analyse(inheritedMethod.returnType, currentMethod.returnType, substituteReturnType, 0, CheckMode.OVERRIDE).isAnyMismatch()) {
+ if (NullAnnotationMatching.analyse(inheritedMethod.returnType, currentMethod.returnType, substituteReturnType, null, 0, CheckMode.OVERRIDE_RETURN).isAnyMismatch()) {
if (srcMethod != null)
scope.problemReporter().illegalReturnRedefinition(srcMethod, inheritedMethod,
this.environment.getNonNullAnnotationName());
@@ -437,7 +437,7 @@ public class ImplicitNullAnnotationVerifier {
if (useTypeAnnotations) {
TypeBinding inheritedParameter = inheritedMethod.parameters[i];
TypeBinding substituteParameter = substituteParameters != null ? substituteParameters[i] : null;
- if (NullAnnotationMatching.analyse(currentMethod.parameters[i], inheritedParameter, substituteParameter, 0, CheckMode.OVERRIDE).isAnyMismatch()) {
+ if (NullAnnotationMatching.analyse(currentMethod.parameters[i], inheritedParameter, substituteParameter, null, 0, CheckMode.OVERRIDE).isAnyMismatch()) {
if (currentArgument != null)
scope.problemReporter().illegalParameterRedefinition(currentArgument, inheritedMethod.declaringClass, inheritedParameter);
else
@@ -446,6 +446,18 @@ public class ImplicitNullAnnotationVerifier {
}
}
}
+
+ if (shouldComplain && useTypeAnnotations && srcMethod != null) {
+ TypeVariableBinding[] currentTypeVariables = currentMethod.typeVariables();
+ TypeVariableBinding[] inheritedTypeVariables = inheritedMethod.typeVariables();
+ if (currentTypeVariables != Binding.NO_TYPE_VARIABLES && currentTypeVariables.length == inheritedTypeVariables.length) {
+ for (int i = 0; i < currentTypeVariables.length; i++) {
+ TypeVariableBinding inheritedVariable = inheritedTypeVariables[i];
+ if (NullAnnotationMatching.analyse(inheritedVariable, currentTypeVariables[i], null, null, -1, CheckMode.BOUND_CHECK).isAnyMismatch())
+ scope.problemReporter().cannotRedefineTypeArgumentNullity(inheritedVariable, inheritedMethod, srcMethod.typeParameters()[i]);
+ }
+ }
+ }
}
void applyReturnNullBits(MethodBinding method, long nullnessBits) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
index 45b6c032a..5fecda127 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java
@@ -212,6 +212,8 @@ public class InferenceContext18 {
this.invocationArguments = arguments;
this.currentInvocation = site;
this.outerContext = outerContext;
+ if (site instanceof Invocation)
+ scope.compilationUnitScope().registerInferredInvocation((Invocation) site);
}
public InferenceContext18(Scope scope) {
@@ -1656,4 +1658,9 @@ public class InferenceContext18 {
}
}
}
+
+ public void cleanUp() {
+ this.b2 = null;
+ this.currentBounds = null;
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java
index fd43592f8..a93c1b59b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/IntersectionTypeBinding18.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -292,4 +292,10 @@ public class IntersectionTypeBinding18 extends ReferenceBinding { // abstraction
}
return false;
}
+ @Override
+ public long updateTagBits() {
+ for (TypeBinding intersectingType : this.intersectingTypes)
+ this.tagBits |= intersectingType.updateTagBits();
+ return super.updateTagBits();
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
index 3bb73da32..a4269c4c1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/LookupEnvironment.java
@@ -160,6 +160,8 @@ public class LookupEnvironment implements ProblemReasons, TypeConstants {
AnnotationBinding nonNullAnnotation;
AnnotationBinding nullableAnnotation;
+ Map<String,Integer> allNullAnnotations = null;
+
final List<MethodBinding> deferredEnumMethods = new ArrayList<>(); // during early initialization we cannot mark Enum-methods as nonnull.
/** Global access to the outermost active inference context as the universe for inference variable interning. */
@@ -1262,9 +1264,10 @@ public TypeBinding createAnnotatedType(TypeBinding type, AnnotationBinding[] new
continue;
}
long tagBits = 0;
- switch (newbies[i].type.id) {
- case TypeIds.T_ConfiguredAnnotationNonNull : tagBits = TagBits.AnnotationNonNull; break;
- case TypeIds.T_ConfiguredAnnotationNullable : tagBits = TagBits.AnnotationNullable; break;
+ if (newbies[i].type.hasNullBit(TypeIds.BitNonNullAnnotation)) {
+ tagBits = TagBits.AnnotationNonNull;
+ } else if (newbies[i].type.hasNullBit(TypeIds.BitNullableAnnotation)) {
+ tagBits = TagBits.AnnotationNullable;
}
if ((tagBitsSeen & tagBits) == 0) {
tagBitsSeen |= tagBits;
@@ -1368,6 +1371,27 @@ public char[][] getNonNullByDefaultAnnotationName() {
return this.globalOptions.nonNullByDefaultAnnotationName;
}
+int getNullAnnotationBit(char[][] qualifiedTypeName) {
+ if (this.allNullAnnotations == null) {
+ this.allNullAnnotations = new HashMap<>();
+ this.allNullAnnotations.put(CharOperation.toString(this.globalOptions.nonNullAnnotationName), TypeIds.BitNonNullAnnotation);
+ this.allNullAnnotations.put(CharOperation.toString(this.globalOptions.nullableAnnotationName), TypeIds.BitNullableAnnotation);
+ this.allNullAnnotations.put(CharOperation.toString(this.globalOptions.nonNullByDefaultAnnotationName), TypeIds.BitNonNullByDefaultAnnotation);
+ for (String name : this.globalOptions.nullableAnnotationSecondaryNames)
+ this.allNullAnnotations.put(name, TypeIds.BitNullableAnnotation);
+ for (String name : this.globalOptions.nonNullAnnotationSecondaryNames)
+ this.allNullAnnotations.put(name, TypeIds.BitNonNullAnnotation);
+ for (String name : this.globalOptions.nonNullByDefaultAnnotationSecondaryNames)
+ this.allNullAnnotations.put(name, TypeIds.BitNonNullByDefaultAnnotation);
+ }
+ String qualifiedTypeString = CharOperation.toString(qualifiedTypeName);
+ Integer typeBit = this.allNullAnnotations.get(qualifiedTypeString);
+ return typeBit == null ? 0 : typeBit;
+}
+public boolean isNullnessAnnotationPackage(PackageBinding pkg) {
+ return this.nonnullAnnotationPackage == pkg || this.nullableAnnotationPackage == pkg || this.nonnullByDefaultAnnotationPackage == pkg;
+}
+
public boolean usesNullTypeAnnotations() {
if (this.globalOptions.useNullTypeAnnotations != null)
return this.globalOptions.useNullTypeAnnotations;
@@ -2045,8 +2069,7 @@ public AnnotationBinding[] filterNullTypeAnnotations(AnnotationBinding[] typeAnn
if (typeAnnotation == null) {
count++; // sentinel in annotation sequence for array dimensions
} else {
- int id = typeAnnotation.type.id;
- if (id != TypeIds.T_ConfiguredAnnotationNonNull && id != TypeIds.T_ConfiguredAnnotationNullable)
+ if (!typeAnnotation.type.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation))
filtered[count++] = typeAnnotation;
}
}
@@ -2061,15 +2084,13 @@ public AnnotationBinding[] filterNullTypeAnnotations(AnnotationBinding[] typeAnn
public boolean containsNullTypeAnnotation(IBinaryAnnotation[] typeAnnotations) {
if (typeAnnotations.length == 0)
return false;
- char[][] nonNullAnnotationName = this.getNonNullAnnotationName();
- char[][] nullableAnnotationName = this.getNullableAnnotationName();
for (int i = 0; i < typeAnnotations.length; i++) {
IBinaryAnnotation typeAnnotation = typeAnnotations[i];
char[] typeName = typeAnnotation.getTypeName();
// typeName must be "Lfoo/X;"
if (typeName == null || typeName.length < 3 || typeName[0] != 'L') continue;
char[][] name = CharOperation.splitOn('/', typeName, 1, typeName.length-1);
- if (CharOperation.equals(name, nonNullAnnotationName) || CharOperation.equals(name, nullableAnnotationName))
+ if (getNullAnnotationBit(name) != 0)
return true;
}
return false;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
index 0d53059a3..41307d3d6 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/PackageBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -283,22 +283,24 @@ private boolean isPackageOfQualifiedTypeName(char[][] packageName, char[][] type
void checkIfNullAnnotationType(ReferenceBinding type) {
// check if type is one of the configured null annotation types
- // if so mark as a well known type using the corresponding typeID:
+ // if so mark as a well known type using the corresponding typeBit:
if (this.environment.nullableAnnotationPackage == this
&& CharOperation.equals(type.compoundName, this.environment.getNullableAnnotationName())) {
- type.id = TypeIds.T_ConfiguredAnnotationNullable;
+ type.typeBits |= TypeIds.BitNullableAnnotation;
if (!(type instanceof UnresolvedReferenceBinding)) // unresolved will need to check back for the resolved type
this.environment.nullableAnnotationPackage = null; // don't check again
} else if (this.environment.nonnullAnnotationPackage == this
&& CharOperation.equals(type.compoundName, this.environment.getNonNullAnnotationName())) {
- type.id = TypeIds.T_ConfiguredAnnotationNonNull;
+ type.typeBits |= TypeIds.BitNonNullAnnotation;
if (!(type instanceof UnresolvedReferenceBinding)) // unresolved will need to check back for the resolved type
this.environment.nonnullAnnotationPackage = null; // don't check again
} else if (this.environment.nonnullByDefaultAnnotationPackage == this
&& CharOperation.equals(type.compoundName, this.environment.getNonNullByDefaultAnnotationName())) {
- type.id = TypeIds.T_ConfiguredAnnotationNonNullByDefault;
+ type.typeBits |= TypeIds.BitNonNullByDefaultAnnotation;
if (!(type instanceof UnresolvedReferenceBinding)) // unresolved will need to check back for the resolved type
this.environment.nonnullByDefaultAnnotationPackage = null; // don't check again
+ } else {
+ type.typeBits |= this.environment.getNullAnnotationBit(type.compoundName);
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
index 983e84f5c..82e4b2d60 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedGenericMethodBinding.java
@@ -27,6 +27,7 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
+import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.Invocation;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
@@ -193,12 +194,12 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin
if (actualReceiverType instanceof ReferenceBinding)
actualReceiverRefType = (ReferenceBinding) actualReceiverType;
}
- switch (typeVariable.boundCheck(substitution, substituteForChecks, actualReceiverRefType, scope)) {
+ switch (typeVariable.boundCheck(substitution, substituteForChecks, actualReceiverRefType, scope, null)) {
/* orig:
- switch (typeVariable.boundCheck(substitution, substituteForChecks, scope)) {
+ switch (typeVariable.boundCheck(substitution, substituteForChecks, scope, null)) {
:giro */
// SH}
- case TypeConstants.MISMATCH :
+ case MISMATCH :
// incompatible due to bound check
int argLength = arguments.length;
TypeBinding[] augmentedArguments = new TypeBinding[argLength + 2]; // append offending substitute and typeVariable
@@ -206,10 +207,12 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin
augmentedArguments[argLength] = substitute;
augmentedArguments[argLength+1] = typeVariable;
return new ProblemMethodBinding(methodSubstitute, originalMethod.selector, augmentedArguments, ProblemReasons.ParameterBoundMismatch);
- case TypeConstants.UNCHECKED :
+ case UNCHECKED :
// tolerate unchecked bounds
methodSubstitute.tagBits |= TagBits.HasUncheckedTypeArgumentForBoundCheck;
break;
+ default:
+ break;
}
}
// check presence of unchecked argument conversion a posteriori (15.12.2.6)
@@ -314,12 +317,7 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin
if (invocationTypeInferred) {
if (compilerOptions.isAnnotationBasedNullAnalysisEnabled)
NullAnnotationMatching.checkForContradictions(methodSubstitute, invocationSite, scope);
-//{ObjectTeams: 2nd arg added:
-/* orig:
- MethodBinding problemMethod = methodSubstitute.boundCheck18(scope, arguments);
- :giro */
- MethodBinding problemMethod = methodSubstitute.boundCheck18(scope, invocationSite, arguments);
-// SH}
+ MethodBinding problemMethod = methodSubstitute.boundCheck18(scope, arguments, invocationSite);
if (problemMethod != null) {
return problemMethod;
}
@@ -343,12 +341,7 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin
}
}
-//{ObjectTeams: second arg added:
-/*orig:
- MethodBinding boundCheck18(Scope scope, TypeBinding[] arguments) {
- :giro */
- MethodBinding boundCheck18(Scope scope, InvocationSite invocationSite, TypeBinding[] arguments) {
-// SH}
+ MethodBinding boundCheck18(Scope scope, TypeBinding[] arguments, InvocationSite site) {
Substitution substitution = this;
ParameterizedGenericMethodBinding methodSubstitute = this;
TypeVariableBinding[] originalTypeVariables = this.originalMethod.typeVariables;
@@ -369,17 +362,18 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin
//{ObjectTeams: methods with generic declared lifting need to be checked in knowledge of the actual receiver type:
ReferenceBinding actualReceiverRefType = null;
- if (invocationSite instanceof MessageSend) {
- TypeBinding actualReceiverType = ((MessageSend)invocationSite).actualReceiverType;
+ if (site instanceof MessageSend) {
+ TypeBinding actualReceiverType = ((MessageSend)site).actualReceiverType;
if (actualReceiverType instanceof ReferenceBinding)
actualReceiverRefType = (ReferenceBinding) actualReceiverType;
}
- switch (typeVariable.boundCheck(substitution, substituteForChecks, actualReceiverRefType, scope)) {
+ ASTNode location = site instanceof ASTNode ? (ASTNode) site : null;
+ switch (typeVariable.boundCheck(substitution, substituteForChecks, actualReceiverRefType, scope, location)) {
/* orig:
- switch (typeVariable.boundCheck(substitution, substituteForChecks, scope)) {
+ switch (typeVariable.boundCheck(substitution, substituteForChecks, scope, location)) {
:giro */
// SH}
- case TypeConstants.MISMATCH :
+ case MISMATCH :
// incompatible due to bound check
int argLength = arguments.length;
TypeBinding[] augmentedArguments = new TypeBinding[argLength + 2]; // append offending substitute and typeVariable
@@ -387,10 +381,12 @@ public class ParameterizedGenericMethodBinding extends ParameterizedMethodBindin
augmentedArguments[argLength] = substitute;
augmentedArguments[argLength+1] = typeVariable;
return new ProblemMethodBinding(methodSubstitute, this.originalMethod.selector, augmentedArguments, ProblemReasons.ParameterBoundMismatch);
- case TypeConstants.UNCHECKED :
+ case UNCHECKED :
// tolerate unchecked bounds
methodSubstitute.tagBits |= TagBits.HasUncheckedTypeArgumentForBoundCheck;
break;
+ default:
+ break;
}
}
return null;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java
index 514c3e69e..40c4f6aba 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedMethodBinding.java
@@ -324,10 +324,18 @@ public class ParameterizedMethodBinding extends MethodBinding {
ReferenceBinding genericClassType = scope.getJavaLangClass();
LookupEnvironment environment = scope.environment();
TypeBinding rawType = environment.convertToRawType(receiverType.erasure(), false /*do not force conversion of enclosing types*/);
+ if (environment.usesNullTypeAnnotations())
+ rawType = environment.createAnnotatedType(rawType, new AnnotationBinding[] { environment.getNonNullAnnotation() });
method.returnType = environment.createParameterizedType(
genericClassType,
new TypeBinding[] { environment.createWildcard(genericClassType, 0, rawType, null /*no extra bound*/, Wildcard.EXTENDS) },
null);
+ if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
+ if (environment.usesNullTypeAnnotations())
+ method.returnType = environment.createAnnotatedType(method.returnType, new AnnotationBinding[] { environment.getNonNullAnnotation() });
+ else
+ method.tagBits |= TagBits.AnnotationNonNull;
+ }
if ((method.returnType.tagBits & TagBits.HasMissingType) != 0) {
method.tagBits |= TagBits.HasMissingType;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
index 1056a1c71..246f94c3c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ParameterizedTypeBinding.java
@@ -56,6 +56,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants.BoundCheckStatus;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
import org.eclipse.objectteams.otdt.internal.core.compiler.util.RoleTypeCreator.TypeArgumentUpdater;
@@ -149,13 +150,12 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi
TypeVariableBinding[] typeVariables = this.type.typeVariables();
if (this.arguments != null && typeVariables != null) { // arguments may be null in error cases
for (int i = 0, length = typeVariables.length; i < length; i++) {
- if (typeVariables[i].boundCheck(this, this.arguments[i], scope) != TypeConstants.OK) {
- hasErrors = true;
- if ((this.arguments[i].tagBits & TagBits.HasMissingType) == 0) {
- // do not report secondary error, if type reference already got complained against
- scope.problemReporter().typeMismatchError(this.arguments[i], typeVariables[i], this.type, argumentReferences[i]);
- }
- }
+ BoundCheckStatus checkStatus = typeVariables[i].boundCheck(this, this.arguments[i], scope, argumentReferences[i]);
+ hasErrors |= checkStatus != BoundCheckStatus.OK;
+ if (!checkStatus.isOKbyJLS() && (this.arguments[i].tagBits & TagBits.HasMissingType) == 0) {
+ // do not report secondary error, if type reference already got complained against
+ scope.problemReporter().typeMismatchError(this.arguments[i], typeVariables[i], this.type, argumentReferences[i]);
+ }
}
}
if (!hasErrors) this.tagBits |= TagBits.PassedBoundCheck; // no need to recheck it in the future
@@ -1610,7 +1610,7 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi
declaringType = scope.environment().createParameterizedType(genericType, types, genericType.enclosingType());
TypeVariableBinding [] typeParameters = genericType.typeVariables();
for (int i = 0, length = typeParameters.length; i < length; i++) {
- if (typeParameters[i].boundCheck(declaringType, types[i], scope) != TypeConstants.OK)
+ if (!typeParameters[i].boundCheck(declaringType, types[i], scope, null).isOKbyJLS())
return this.singleAbstractMethod[index] = new ProblemMethodBinding(TypeConstants.ANONYMOUS_METHOD, null, ProblemReasons.NotAWellFormedParameterizedType);
}
ReferenceBinding substitutedDeclaringType = (ReferenceBinding) declaringType.findSuperTypeOriginatingFrom(theAbstractMethod.declaringClass);
@@ -1693,6 +1693,13 @@ public class ParameterizedTypeBinding extends ReferenceBinding implements Substi
}
return types;
}
+ @Override
+ public long updateTagBits() {
+ if (this.arguments != null)
+ for (TypeBinding argument : this.arguments)
+ this.tagBits |= argument.updateTagBits();
+ return super.updateTagBits();
+ }
//{ObjectTeams: recursive role wrapping:
@Override
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
index a1d8b7c6a..0c878c44e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ReferenceBinding.java
@@ -1442,6 +1442,11 @@ public final boolean hasRestrictedAccess() {
return (this.modifiers & ExtraCompilerModifiers.AccRestrictedAccess) != 0;
}
+/** Query typeBits without triggering supertype lookup. */
+public boolean hasNullBit(int mask) {
+ return (this.typeBits & mask) != 0;
+}
+
//{ObjectTeams: support asymmetric comparison. // FIXME(SH): is this needed or is super-impl smart enough??
@Override
public boolean isProvablyDistinct(TypeBinding otherType) {
@@ -2066,8 +2071,8 @@ protected void appendNullAnnotation(StringBuffer nameBuffer, CompilerOptions opt
if (options.isAnnotationBasedNullAnalysisEnabled) {
if (options.usesNullTypeAnnotations()) {
for (AnnotationBinding annotation : this.typeAnnotations) {
- TypeBinding annotationType = annotation.getAnnotationType();
- if (annotationType.id == TypeIds.T_ConfiguredAnnotationNonNull || annotation.type.id == TypeIds.T_ConfiguredAnnotationNullable) {
+ ReferenceBinding annotationType = annotation.getAnnotationType();
+ if (annotationType.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) {
nameBuffer.append('@').append(annotationType.shortReadableName()).append(' ');
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
index 58bfb49f0..aaf60c319 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/Scope.java
@@ -1044,8 +1044,14 @@ public abstract class Scope {
}
// after bounds have been resolved we're ready for resolving the type parameter itself,
// which includes resolving/evaluating type annotations and checking for inconsistencies
- for (int i = 0; i < paramLength; i++)
+ boolean declaresNullTypeAnnotation = false;
+ for (int i = 0; i < paramLength; i++) {
resolveTypeParameter(typeParameters[i]);
+ declaresNullTypeAnnotation |= typeParameters[i].binding.hasNullTypeAnnotations();
+ }
+ if (declaresNullTypeAnnotation)
+ for (int i = 0; i < paramLength; i++)
+ typeParameters[i].binding.updateTagBits(); // <T extends List<U>, @NonNull U> --> tag T as having null type annotations
return noProblems;
}
@@ -3665,7 +3671,7 @@ public abstract class Scope {
unitScope.recordSimpleReference(name);
if ((mask & Binding.PACKAGE) != 0) {
PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name);
- if (packageBinding != null) {
+ if (packageBinding != null && (packageBinding.tagBits & TagBits.HasMissingType) == 0) {
if (typeOrPackageCache != null)
typeOrPackageCache.put(name, packageBinding);
return packageBinding;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
index 069edf181..bb9e35f32 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -2789,8 +2789,7 @@ public void evaluateNullAnnotations() {
for (int i = 0; i < annotations.length; i++) {
ReferenceBinding annotationType = annotations[i].getCompilerAnnotation().getAnnotationType();
if (annotationType != null) {
- if (annotationType.id == TypeIds.T_ConfiguredAnnotationNonNull
- || annotationType.id == TypeIds.T_ConfiguredAnnotationNullable) {
+ if (annotationType.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) {
this.scope.problemReporter().nullAnnotationUnsupportedLocation(annotations[i]);
this.tagBits &= ~TagBits.AnnotationNullMASK;
}
@@ -2802,10 +2801,7 @@ public void evaluateNullAnnotations() {
PackageBinding pkg = getPackage();
boolean isInDefaultPkg = (pkg.compoundName == CharOperation.NO_CHAR_CHAR);
if (!isPackageInfo) {
- boolean isInNullnessAnnotationPackage =
- pkg == this.scope.environment().nonnullAnnotationPackage
- || pkg == this.scope.environment().nullableAnnotationPackage
- || pkg == this.scope.environment().nonnullByDefaultAnnotationPackage;
+ boolean isInNullnessAnnotationPackage = this.scope.environment().isNullnessAnnotationPackage(pkg);
if (pkg.defaultNullness == NO_NULL_DEFAULT && !isInDefaultPkg && !isInNullnessAnnotationPackage && !(this instanceof NestedTypeBinding)) {
ReferenceBinding packageInfo = pkg.getType(TypeConstants.PACKAGE_INFO_NAME);
if (packageInfo == null) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
index f3ba9bc59..3a97bb9b1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -1599,14 +1599,10 @@ public void setTypeAnnotations(AnnotationBinding[] annotations, boolean evalNull
for (int i = 0, length = annotations.length; i < length; i++) {
AnnotationBinding annotation = annotations[i];
if (annotation != null) {
- switch (annotation.type.id) {
- case TypeIds.T_ConfiguredAnnotationNullable :
- this.tagBits |= TagBits.AnnotationNullable | TagBits.HasNullTypeAnnotation;
- break;
- case TypeIds.T_ConfiguredAnnotationNonNull :
- this.tagBits |= TagBits.AnnotationNonNull | TagBits.HasNullTypeAnnotation;
- break;
- }
+ if (annotation.type.hasNullBit(TypeIds.BitNullableAnnotation))
+ this.tagBits |= TagBits.AnnotationNullable | TagBits.HasNullTypeAnnotation;
+ else if (annotation.type.hasNullBit(TypeIds.BitNonNullAnnotation))
+ this.tagBits |= TagBits.AnnotationNonNull | TagBits.HasNullTypeAnnotation;
}
}
// we do accept contradictory tagBits here, to support detecting contradictions caused by type substitution
@@ -1778,4 +1774,11 @@ public void exitRecursiveFunction() {
public boolean isFunctionalType() {
return false;
}
+/**
+ * Refresh some tagBits from details into the main type.
+ * Currently handled: TagBits.HasNullTypeAnnotation
+ */
+public long updateTagBits() {
+ return this.tagBits & TagBits.HasNullTypeAnnotation; // subclasses to override
+}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
index 0284bd1c6..baa1c68f3 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeConstants.java
@@ -345,10 +345,25 @@ public interface TypeConstants {
int CONSTRAINT_EXTENDS = 1; // Actual << Formal
int CONSTRAINT_SUPER = 2; // Actual >> Formal
- // Constants used to perform bound checks
- int OK = 0;
- int UNCHECKED = 1;
- int MISMATCH = 2;
+ // status of bound checks
+ public static enum BoundCheckStatus {
+ OK, NULL_PROBLEM, UNCHECKED, MISMATCH;
+ /** true if no problem or only a null problem. */
+ boolean isOKbyJLS() {
+ switch (this) {
+ case OK:
+ case NULL_PROBLEM:
+ return true;
+ default:
+ return false;
+ }
+ }
+ public BoundCheckStatus betterOf(BoundCheckStatus other) {
+ if (this.ordinal() < other.ordinal())
+ return this;
+ return other;
+ }
+ }
// Synthetics
char[] INIT = "<init>".toCharArray(); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
index 1693a6587..af32c7801 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeIds.java
@@ -108,10 +108,7 @@ public interface TypeIds {
// java 7 java.lang.AutoCloseable
final int T_JavaLangAutoCloseable = 62;
- // new in 3.8 for null annotations:
- final int T_ConfiguredAnnotationNullable = 65;
- final int T_ConfiguredAnnotationNonNull = 66;
- final int T_ConfiguredAnnotationNonNullByDefault = 67;
+ // new in 3.8 for null annotations, removed in 4.6 (ids 65-67)
// new in 3.8 to identify org.eclipse.core.runtime.Assert
final int T_OrgEclipseCoreRuntimeAssert = 68;
@@ -247,6 +244,14 @@ public interface TypeIds {
final int BitResourceFreeCloseable = 8;
final int BitUninternedType = 16;
+
+ /** Bit for a type configured as a @NonNull annotation. */
+ final int BitNonNullAnnotation = 32;
+ /** Bit for a type configured as a @Nullable annotation. */
+ final int BitNullableAnnotation = 64;
+ /** Bit for a type configured as a @NonNullByDefault annotation. */
+ final int BitNonNullByDefaultAnnotation = 128;
+
/**
* Set of type bits that should be inherited by any sub types.
*/
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
index 74e292b43..cbf69ab1e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeSystem.java
@@ -11,6 +11,8 @@
* Bug 434602 - Possible error with inferred null annotations leading to contradictory null annotations
* Bug 456497 - [1.8][null] during inference nullness from target type is lost against weaker hint from applicability analysis
* Bug 456487 - [1.8][null] @Nullable type variant of @NonNull-constrained type parameter causes grief
+ * Till Brychcy - Contribution for
+ * Bug 473713 - [1.8][null] Type mismatch: cannot convert from @NonNull A1 to @NonNull A1
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
@@ -217,14 +219,19 @@ public class TypeSystem {
// Given a type, answer its unannotated aka naked prototype. This is also a convenient way to "register" a type with TypeSystem and have it id stamped.
public final TypeBinding getUnannotatedType(TypeBinding type) {
UnresolvedReferenceBinding urb = null;
- if (type.isUnresolvedType() && CharOperation.indexOf('$', type.sourceName()) > 0) {
+ if (type.isUnresolvedType()) {
urb = (UnresolvedReferenceBinding) type;
- boolean mayTolerateMissingType = this.environment.mayTolerateMissingType;
- this.environment.mayTolerateMissingType = true;
- try {
- type = BinaryTypeBinding.resolveType(type, this.environment, true); // to ensure unique id assignment (when enclosing type is parameterized, inner type is also)
- } finally {
- this.environment.mayTolerateMissingType = mayTolerateMissingType;
+ ReferenceBinding resolvedType = urb.resolvedType;
+ if (resolvedType != null) {
+ type = resolvedType;
+ } else if (CharOperation.indexOf('$', type.sourceName()) > 0) {
+ boolean mayTolerateMissingType = this.environment.mayTolerateMissingType;
+ this.environment.mayTolerateMissingType = true;
+ try {
+ type = BinaryTypeBinding.resolveType(type, this.environment, true); // to ensure unique id assignment (when enclosing type is parameterized, inner type is also)
+ } finally {
+ this.environment.mayTolerateMissingType = mayTolerateMissingType;
+ }
}
}
if (type.id == TypeIds.NoId) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
index 633240832..fa31d41af 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeVariableBinding.java
@@ -47,8 +47,10 @@ import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
+import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching.CheckMode;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.lookup.TypeConstants.BoundCheckStatus;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.CallinCalloutBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.DependentTypeBinding;
import org.eclipse.objectteams.otdt.internal.core.compiler.lookup.ITeamAnchor;
@@ -117,38 +119,39 @@ public class TypeVariableBinding extends ReferenceBinding {
/**
* Returns true if the argument type satisfies all bounds of the type parameter
+ * @param location if non-null this may be used for reporting errors relating to null type annotations (if enabled)
*/
+ public TypeConstants.BoundCheckStatus boundCheck(Substitution substitution, TypeBinding argumentType, Scope scope, ASTNode location) {
//{ObjectTeams: added optional argument actualReceiverType:
- public int boundCheck(Substitution substitution, TypeBinding argumentType, Scope scope) {
- return boundCheck(substitution, argumentType, null, scope);
+ return boundCheck(substitution, argumentType, null, scope, location);
}
- public int boundCheck(Substitution substitution, TypeBinding argumentType, ReferenceBinding actualReceiverType, Scope scope) {
- int code = internalBoundCheck(substitution, argumentType, actualReceiverType, scope);
+ public TypeConstants.BoundCheckStatus boundCheck(Substitution substitution, TypeBinding argumentType, ReferenceBinding actualReceiverType, Scope scope, ASTNode location) {
+ TypeConstants.BoundCheckStatus code = internalBoundCheck(substitution, argumentType, actualReceiverType, scope, location);
// SH}
- if (code == TypeConstants.MISMATCH) {
+ if (code == BoundCheckStatus.MISMATCH) {
if (argumentType instanceof TypeVariableBinding && scope != null) {
TypeBinding bound = ((TypeVariableBinding)argumentType).firstBound;
if (bound instanceof ParameterizedTypeBinding) {
- int code2 = boundCheck(substitution, bound.capture(scope, -1, -1), scope); // no position needed as this capture will never escape this context
- return Math.min(code, code2);
+ BoundCheckStatus code2 = boundCheck(substitution, bound.capture(scope, -1, -1), scope, location); // no capture position needed as this capture will never escape this context
+ return code.betterOf(code2);
}
}
}
return code;
}
//{ObjectTeams: added optional argument actualReceiverType:
- private int internalBoundCheck(Substitution substitution, TypeBinding argumentType, ReferenceBinding actualReceiverType, Scope scope) {
+ private TypeConstants.BoundCheckStatus internalBoundCheck(Substitution substitution, TypeBinding argumentType, ReferenceBinding actualReceiverType, Scope scope, ASTNode location) {
// SH}
if (argumentType == TypeBinding.NULL || TypeBinding.equalsEquals(argumentType, this)) {
- return TypeConstants.OK;
+ return BoundCheckStatus.OK;
}
boolean hasSubstitution = substitution != null;
if (!(argumentType instanceof ReferenceBinding || argumentType.isArrayType()))
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
// special case for re-entrant source types (selection, code assist, etc)...
// can request additional types during hierarchy walk that are found as source types that also 'need' to connect their hierarchy
if (this.superclass == null)
- return TypeConstants.OK;
+ return BoundCheckStatus.OK;
if (argumentType.kind() == Binding.WILDCARD_TYPE) {
WildcardBinding wildcard = (WildcardBinding) argumentType;
@@ -156,30 +159,30 @@ public class TypeVariableBinding extends ReferenceBinding {
case Wildcard.EXTENDS :
TypeBinding wildcardBound = wildcard.bound;
if (TypeBinding.equalsEquals(wildcardBound, this))
- return TypeConstants.OK;
+ return BoundCheckStatus.OK;
boolean isArrayBound = wildcardBound.isArrayType();
if (!wildcardBound.isInterface()) {
TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superclass) : this.superclass;
if (substitutedSuperType.id != TypeIds.T_JavaLangObject) {
if (isArrayBound) {
if (!wildcardBound.isCompatibleWith(substitutedSuperType, scope))
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
} else {
TypeBinding match = wildcardBound.findSuperTypeOriginatingFrom(substitutedSuperType);
if (match != null) {
if (substitutedSuperType.isProvablyDistinct(match)) {
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
}
} else {
match = substitutedSuperType.findSuperTypeOriginatingFrom(wildcardBound);
if (match != null) {
if (match.isProvablyDistinct(wildcardBound)) {
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
}
} else {
if (denotesRelevantSuperClass(wildcardBound) && denotesRelevantSuperClass(substitutedSuperType)) {
// non-object real superclass should have produced a valid 'match' above
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
}
}
}
@@ -191,15 +194,15 @@ public class TypeVariableBinding extends ReferenceBinding {
TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superInterfaces[i]) : this.superInterfaces[i];
if (isArrayBound) {
if (!wildcardBound.isCompatibleWith(substitutedSuperType, scope))
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
} else {
TypeBinding match = wildcardBound.findSuperTypeOriginatingFrom(substitutedSuperType);
if (match != null) {
if (substitutedSuperType.isProvablyDistinct(match)) {
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
}
} else if (mustImplement) {
- return TypeConstants.MISMATCH; // cannot be extended further to satisfy missing bounds
+ return BoundCheckStatus.MISMATCH; // cannot be extended further to satisfy missing bounds
}
}
@@ -210,19 +213,21 @@ public class TypeVariableBinding extends ReferenceBinding {
// if the wildcard is lower-bounded by a type variable that has no relevant upper bound there's nothing to check here (bug 282152):
if (wildcard.bound.isTypeVariable() && ((TypeVariableBinding)wildcard.bound).superclass.id == TypeIds.T_JavaLangObject)
break;
- return boundCheck(substitution, wildcard.bound, scope);
+ return boundCheck(substitution, wildcard.bound, scope, location);
case Wildcard.UNBOUND :
break;
}
- return TypeConstants.OK;
+ return BoundCheckStatus.OK;
}
boolean unchecked = false;
+ boolean checkNullAnnotations = scope.environment().usesNullTypeAnnotations();
+ boolean haveReportedNullProblem = false;
if (this.superclass.id != TypeIds.T_JavaLangObject) {
TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superclass) : this.superclass;
if (TypeBinding.notEquals(substitutedSuperType, argumentType)) {
if (!argumentType.isCompatibleWith(substitutedSuperType, scope)) {
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
}
TypeBinding match = argumentType.findSuperTypeOriginatingFrom(substitutedSuperType);
if (match != null){
@@ -231,6 +236,12 @@ public class TypeVariableBinding extends ReferenceBinding {
unchecked = true;
}
}
+ if (location != null && checkNullAnnotations) {
+ if (NullAnnotationMatching.analyse(this, argumentType, substitutedSuperType, substitution, -1, CheckMode.BOUND_CHECK).isAnyMismatch()) {
+ scope.problemReporter().nullityMismatchTypeArgument(this, argumentType, location);
+ haveReportedNullProblem = true;
+ }
+ }
}
//{ObjectTeams: type check <B base R>
if (this.roletype != null) {
@@ -239,14 +250,14 @@ public class TypeVariableBinding extends ReferenceBinding {
TypeVariableBinding argTypeVar = (TypeVariableBinding) argumentType;
if (argTypeVar.roletype != null) {
if (this.roletype.isCompatibleWith(argTypeVar.roletype))
- return TypeConstants.OK;
+ return BoundCheckStatus.OK;
else
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
}
}
TypeBinding substitutedRoleType = hasSubstitution ? Scope.substitute(substitution, this.roletype) : this.roletype;
if (!substitutedRoleType.isRole())
- return TypeConstants.MISMATCH; // actually roletype was already checked for role-ness.
+ return BoundCheckStatus.MISMATCH; // actually roletype was already checked for role-ness.
// FIXME(SH): handle arrays? enums? nested generics?
if (actualReceiverType != null)
substitutedRoleType = TeamModel.strengthenRoleType(actualReceiverType, substitutedRoleType);
@@ -254,21 +265,21 @@ public class TypeVariableBinding extends ReferenceBinding {
for (ReferenceBinding aRoletype : roletypes) {
ReferenceBinding basetype = aRoletype.baseclass(); // non-null by definition of getBoundDescendants()
if (TypeBinding.equalsEquals(basetype, argumentType) || argumentType.isCompatibleWith(basetype)) {
- return TypeConstants.OK;
+ return BoundCheckStatus.OK;
}
}
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
}
// check value-dependent type-variable:
if (this.anchors != null && substitution != null) {
ITeamAnchor anchor = substitution.substituteAnchor(this.anchors[0], 0); // TODO(SH): support multiple anchors
if (anchor != null) {
if (!(argumentType instanceof DependentTypeBinding)) {
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
} else {
ITeamAnchor argAnchor = ((DependentTypeBinding)argumentType).getAnchor();
if (!argAnchor.hasSameBestNameAs(anchor))
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
}
}
}
@@ -277,7 +288,7 @@ public class TypeVariableBinding extends ReferenceBinding {
TypeBinding substitutedSuperType = hasSubstitution ? Scope.substitute(substitution, this.superInterfaces[i]) : this.superInterfaces[i];
if (TypeBinding.notEquals(substitutedSuperType, argumentType)) {
if (!argumentType.isCompatibleWith(substitutedSuperType, scope)) {
- return TypeConstants.MISMATCH;
+ return BoundCheckStatus.MISMATCH;
}
TypeBinding match = argumentType.findSuperTypeOriginatingFrom(substitutedSuperType);
if (match != null){
@@ -286,15 +297,21 @@ public class TypeVariableBinding extends ReferenceBinding {
unchecked = true;
}
}
+ if (location != null && checkNullAnnotations) {
+ if (NullAnnotationMatching.analyse(this, argumentType, substitutedSuperType, substitution, -1, CheckMode.BOUND_CHECK).isAnyMismatch()) {
+ scope.problemReporter().nullityMismatchTypeArgument(this, argumentType, location);
+ haveReportedNullProblem = true;
+ }
+ }
}
- long nullTagBits = NullAnnotationMatching.validNullTagBits(this.tagBits);
- if (nullTagBits != 0) {
- long argBits = NullAnnotationMatching.validNullTagBits(argumentType.tagBits);
- if (argBits != nullTagBits) {
-// System.err.println("TODO(stephan): issue proper error: bound conflict at "+String.valueOf(this.declaringElement.readableName()));
- }
+ if (location != null && checkNullAnnotations && !haveReportedNullProblem) {
+ long nullBits = this.tagBits & TagBits.AnnotationNullMASK;
+ if (nullBits != 0 && nullBits != (argumentType.tagBits & TagBits.AnnotationNullMASK)) {
+ scope.problemReporter().nullityMismatchTypeArgument(this, argumentType, location);
+ haveReportedNullProblem = true;
+ }
}
- return unchecked ? TypeConstants.UNCHECKED : TypeConstants.OK;
+ return unchecked ? BoundCheckStatus.UNCHECKED : haveReportedNullProblem ? BoundCheckStatus.NULL_PROBLEM : BoundCheckStatus.OK;
}
boolean denotesRelevantSuperClass(TypeBinding type) {
@@ -1133,4 +1150,21 @@ public class TypeVariableBinding extends ReferenceBinding {
public boolean acceptsNonNullDefault() {
return false;
}
+
+ @Override
+ public long updateTagBits() {
+ if (!this.inRecursiveFunction) {
+ this.inRecursiveFunction = true;
+ try {
+ if (this.superclass != null)
+ this.tagBits |= this.superclass.updateTagBits();
+ if (this.superInterfaces != null)
+ for (TypeBinding superIfc : this.superInterfaces)
+ this.tagBits |= superIfc.updateTagBits();
+ } finally {
+ this.inRecursiveFunction = false;
+ }
+ }
+ return super.updateTagBits();
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
index 3ff8e77bb..1f859b702 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/WildcardBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2014 IBM Corporation and others.
+ * Copyright (c) 2005, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -994,4 +994,22 @@ public class WildcardBinding extends ReferenceBinding {
public boolean acceptsNonNullDefault() {
return false;
}
+
+ @Override
+ public long updateTagBits() {
+ if (!this.inRecursiveFunction) {
+ this.inRecursiveFunction = true;
+ try {
+ if (this.bound != null)
+ this.tagBits |= this.bound.updateTagBits();
+ if (this.otherBounds != null) {
+ for (int i = 0, length = this.otherBounds.length; i < length; i++)
+ this.tagBits |= this.otherBounds[i].updateTagBits();
+ }
+ } finally {
+ this.inRecursiveFunction = false;
+ }
+ }
+ return super.updateTagBits();
+ }
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
index 689813bb3..59c3bcd1d 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java
@@ -462,6 +462,7 @@ public static int getIrritant(int problemID) {
case IProblem.IllegalReturnNullityRedefinition:
case IProblem.IllegalReturnNullityRedefinitionFreeTypeVariable:
case IProblem.IllegalRedefinitionToNonNullParameter:
+ case IProblem.IllegalRedefinitionOfTypeVariable:
case IProblem.IllegalDefinitionToNonNullParameter:
case IProblem.ParameterLackingNullableAnnotation:
case IProblem.CannotImplementIncompatibleNullness:
@@ -9532,9 +9533,6 @@ private boolean excludeDueToAnnotation(Annotation[] annotations, int problemId)
case TypeIds.T_JavaLangSuppressWarnings:
case TypeIds.T_JavaLangDeprecated:
case TypeIds.T_JavaLangSafeVarargs:
- case TypeIds.T_ConfiguredAnnotationNonNull:
- case TypeIds.T_ConfiguredAnnotationNullable:
- case TypeIds.T_ConfiguredAnnotationNonNullByDefault:
break;
case TypeIds.T_JavaxInjectInject:
case TypeIds.T_ComGoogleInjectInject:
@@ -9543,8 +9541,10 @@ private boolean excludeDueToAnnotation(Annotation[] annotations, int problemId)
return true; // @Inject on method/ctor does constitute a relevant use, just on fields it doesn't
break;
default:
- // non-standard annotation found, don't warn
- return true;
+ if (resolvedType instanceof ReferenceBinding)
+ if (((ReferenceBinding) resolvedType).hasNullBit(TypeIds.BitNullableAnnotation|TypeIds.BitNonNullAnnotation|TypeIds.BitNonNullByDefaultAnnotation))
+ break;
+ return true; // non-standard annotation found, don't warn
}
}
}
@@ -13668,9 +13668,7 @@ public void illegalRedefinitionToNonNullParameter(Argument argument, ReferenceBi
if (argument.annotations != null) {
for (int i=0; i<argument.annotations.length; i++) {
Annotation annotation = argument.annotations[i];
- if ( annotation.resolvedType.id == TypeIds.T_ConfiguredAnnotationNullable
- || annotation.resolvedType.id == TypeIds.T_ConfiguredAnnotationNonNull)
- {
+ if (annotation.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) {
sourceStart = annotation.sourceStart;
break;
}
@@ -13721,9 +13719,7 @@ public void illegalParameterRedefinition(Argument argument, ReferenceBinding dec
if (argument.annotations != null) {
for (int i=0; i<argument.annotations.length; i++) {
Annotation annotation = argument.annotations[i];
- if ( annotation.resolvedType.id == TypeIds.T_ConfiguredAnnotationNullable
- || annotation.resolvedType.id == TypeIds.T_ConfiguredAnnotationNonNull)
- {
+ if (annotation.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) {
sourceStart = annotation.sourceStart;
break;
}
@@ -13752,7 +13748,7 @@ public void illegalReturnRedefinition(AbstractMethodDeclaration abstractMethodDe
.append(inheritedMethod.shortReadableName());
int sourceStart = methodDecl.returnType.sourceStart;
Annotation[] annotations = methodDecl.annotations;
- Annotation annotation = findAnnotation(annotations, TypeIds.T_ConfiguredAnnotationNullable);
+ Annotation annotation = findAnnotation(annotations, TypeIds.BitNullableAnnotation);
if (annotation != null) {
sourceStart = annotation.sourceStart;
}
@@ -13907,7 +13903,7 @@ public void nullAnnotationIsRedundant(AbstractMethodDeclaration sourceMethod, in
int sourceStart, sourceEnd;
if (i == -1) {
MethodDeclaration methodDecl = (MethodDeclaration) sourceMethod;
- Annotation annotation = findAnnotation(methodDecl.annotations, TypeIds.T_ConfiguredAnnotationNonNull);
+ Annotation annotation = findAnnotation(methodDecl.annotations, TypeIds.BitNonNullAnnotation);
sourceStart = annotation != null ? annotation.sourceStart : methodDecl.returnType.sourceStart;
sourceEnd = methodDecl.returnType.sourceEnd;
} else {
@@ -13919,14 +13915,14 @@ public void nullAnnotationIsRedundant(AbstractMethodDeclaration sourceMethod, in
}
public void nullAnnotationIsRedundant(FieldDeclaration sourceField) {
- Annotation annotation = findAnnotation(sourceField.annotations, TypeIds.T_ConfiguredAnnotationNonNull);
+ Annotation annotation = findAnnotation(sourceField.annotations, TypeIds.BitNonNullAnnotation);
int sourceStart = annotation != null ? annotation.sourceStart : sourceField.type.sourceStart;
int sourceEnd = sourceField.type.sourceEnd;
this.handle(IProblem.RedundantNullAnnotation, ProblemHandler.NoArgument, ProblemHandler.NoArgument, sourceStart, sourceEnd);
}
public void nullDefaultAnnotationIsRedundant(ASTNode location, Annotation[] annotations, Binding outer) {
- Annotation annotation = findAnnotation(annotations, TypeIds.T_ConfiguredAnnotationNonNullByDefault);
+ Annotation annotation = findAnnotation(annotations, TypeIds.BitNonNullByDefaultAnnotation);
int start = annotation != null ? annotation.sourceStart : location.sourceStart;
int end = annotation != null ? annotation.sourceEnd : location.sourceStart;
String[] args = NoArgument;
@@ -14046,13 +14042,13 @@ public void conflictingInheritedNullAnnotations(ASTNode location, boolean previo
public void illegalAnnotationForBaseType(TypeReference type, Annotation[] annotations, long nullAnnotationTagBit)
{
- int typeId = (nullAnnotationTagBit == TagBits.AnnotationNullable)
- ? TypeIds.T_ConfiguredAnnotationNullable : TypeIds.T_ConfiguredAnnotationNonNull;
+ int typeBit = (nullAnnotationTagBit == TagBits.AnnotationNullable)
+ ? TypeIds.BitNullableAnnotation : TypeIds.BitNonNullAnnotation;
char[][] annotationNames = (nullAnnotationTagBit == TagBits.AnnotationNonNull)
? this.options.nonNullAnnotationName
: this.options.nullableAnnotationName;
String[] args = new String[] { new String(annotationNames[annotationNames.length-1]), new String(type.getLastToken()) };
- Annotation annotation = findAnnotation(annotations, typeId);
+ Annotation annotation = findAnnotation(annotations, typeBit);
int start = annotation != null ? annotation.sourceStart : type.sourceStart;
int end = annotation != null ? annotation.sourceEnd : type.sourceEnd;
this.handle(IProblem.IllegalAnnotationForBaseType,
@@ -14114,12 +14110,12 @@ String internalAnnotatedTypeName(char[] annotationName, char[] typeName, int dim
}
return String.valueOf(fullName);
}
-private Annotation findAnnotation(Annotation[] annotations, int typeId) {
+private Annotation findAnnotation(Annotation[] annotations, int typeBit) {
if (annotations != null) {
// should have a @NonNull/@Nullable annotation, search for it:
int length = annotations.length;
for (int j=0; j<length; j++) {
- if (annotations[j].resolvedType != null && annotations[j].resolvedType.id == typeId) {
+ if (annotations[j].hasNullBit(typeBit)) {
return annotations[j];
}
}
@@ -14261,6 +14257,27 @@ public void nullityMismatchTypeArgument(TypeBinding typeVariable, TypeBinding ty
location.sourceEnd);
}
+public void cannotRedefineTypeArgumentNullity(TypeBinding typeVariable, Binding superElement, ASTNode location) {
+ String[] arguments = new String[2];
+ String[] shortArguments = new String[2];
+ arguments[0] = String.valueOf(typeVariable.nullAnnotatedReadableName(this.options, false));
+ shortArguments[0] = String.valueOf(typeVariable.nullAnnotatedReadableName(this.options, true));
+ if (superElement instanceof MethodBinding) {
+ ReferenceBinding declaringClass = ((MethodBinding) superElement).declaringClass;
+ arguments[1] = String.valueOf(CharOperation.concat(declaringClass.readableName(), superElement.shortReadableName(), '.'));
+ shortArguments[1] = String.valueOf(CharOperation.concat(declaringClass.shortReadableName(), superElement.shortReadableName(), '.'));
+ } else {
+ arguments[1] = String.valueOf(superElement.readableName());
+ shortArguments[1] = String.valueOf(superElement.shortReadableName());
+ }
+ this.handle(
+ IProblem.IllegalRedefinitionOfTypeVariable,
+ arguments,
+ shortArguments,
+ location.sourceStart,
+ location.sourceEnd);
+}
+
public void implicitObjectBoundNoNullDefault(TypeReference reference) {
this.handle(IProblem.ImplicitObjectBoundNoNullDefault,
NoArgument, NoArgument,
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
index c1fdaa424..353784da1 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2000, 2014 IBM Corporation and others.
+# Copyright (c) 2000, 2015 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
@@ -833,6 +833,7 @@
972 = Illegal redefinition of parameter {0}, inherited method from {1} declares this parameter as ''{2}'' (mismatching null constraints)
973 = Contradictory null annotations: function type was inferred as ''{2} ({4})'', but only one of ''@{0}'' and ''@{1}'' can be effective at any location
974 = The return type is incompatible with the free type variable ''{1}'' returned from {0} (mismatching null constraints)
+975 = Cannot redefine null constraints of type variable ''{0}'' declared in ''{1}''
# Java 8
1001 = Syntax error, modifiers and annotations are not allowed for the lambda parameter {0} as its type is elided
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
index 4f8f4df35..dd7d04d64 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTConverter.java
@@ -3781,12 +3781,24 @@ class ASTConverter {
private void setTypeAnnotationsAndSourceRangeOnArray(ArrayType arrayType, org.eclipse.jdt.internal.compiler.ast.Annotation[][] annotationsOnDimensions) {
List dimensions = arrayType.dimensions();
Type elementType = arrayType.getElementType();
+
+ // Object[] a
+ // ^
int start = elementType.getStartPosition();
- int endElement = start + elementType.getLength() - 1;
- int end = retrieveProperRightBracketPosition(dimensions.size(), endElement);
+
+ // Object[] a
+ // ^
+ int startArray = start + elementType.getLength();
+
+ // Object[] a
+ // ^
+ int end = retrieveProperRightBracketPosition(dimensions.size(), startArray);
+ if (end == -1) {
+ end = startArray - 1;
+ }
arrayType.setSourceRange(start, end - start + 1);
- start = endElement + 1;
+ start = startArray;
for (int i = 0; i < dimensions.size(); i++) {
Dimension currentDimension = (Dimension) dimensions.get(i);
setTypeAnnotationsOnDimension(currentDimension, annotationsOnDimensions, i);
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
index 3ecb49e81..f18de8146 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CompilationUnitResolver.java
@@ -4,7 +4,6 @@
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- * $Id: CompilationUnitResolver.java 23404 2010-02-03 14:10:22Z stephan $
*
* Contributors:
* IBM Corporation - initial API and implementation
@@ -118,7 +117,7 @@ class CompilationUnitResolver extends Compiler {
CategorizedProblem abortProblem;
private IProgressMonitor monitor;
-
+
/**
* Set to <code>true</code> if the receiver was initialized using a java project name environment
*/
@@ -183,7 +182,7 @@ class CompilationUnitResolver extends Compiler {
SourceTypeElementInfo sourceType = (SourceTypeElementInfo) sourceTypes[0];
accept((org.eclipse.jdt.internal.compiler.env.ICompilationUnit) sourceType.getHandle().getCompilationUnit(), accessRestriction);
}
-
+
public synchronized void accept(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit, AccessRestriction accessRestriction) {
super.accept(sourceUnit, accessRestriction);
}
@@ -554,7 +553,7 @@ class CompilationUnitResolver extends Compiler {
}
} else {
//fill the methods bodies in order for the code to be generated
- //real parse of the method....
+ //real parse of the method....
org.eclipse.jdt.internal.compiler.ast.TypeDeclaration[] types = compilationUnitDeclaration.types;
if (types != null) {
for (int j = 0, typeLength = types.length; j < typeLength; j++) {
@@ -1240,34 +1239,39 @@ class CompilationUnitResolver extends Compiler {
}
if (unit.scope != null) {
+ CompilationUnitDeclaration previousUnit = this.lookupEnvironment.unitBeingCompleted;
+ this.lookupEnvironment.unitBeingCompleted = unit;
+ try {
//{ObjectTeams: replace single step by Dependencies:
/* orig:
- // fault in fields & methods
- unit.scope.faultInTypes();
- if (unit.scope != null && verifyMethods) {
- // http://dev.eclipse.org/bugs/show_bug.cgi?id=23117
- // verify inherited methods
- unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier());
- }
- // type checking
- unit.resolve();
-
- // flow analysis
- if (analyzeCode) unit.analyseCode();
-
- // code generation
- if (generateCode) unit.generateCode();
+ // fault in fields & methods
+ unit.scope.faultInTypes();
+ if (unit.scope != null && verifyMethods) {
+ // http://dev.eclipse.org/bugs/show_bug.cgi?id=23117
+ // verify inherited methods
+ unit.scope.verifyMethods(this.lookupEnvironment.methodVerifier());
+ }
+ // type checking
+ unit.resolve();
+
+ // flow analysis
+ if (analyzeCode) unit.analyseCode();
+
+ // code generation
+ if (generateCode) unit.generateCode();
*/
- if (generateCode)
- Dependencies.ensureState(unit, ITranslationStates.STATE_BYTE_CODE_GENERATED);
- else if (analyzeCode)
- Dependencies.ensureState(unit, ITranslationStates.STATE_CODE_ANALYZED);
- else
- Dependencies.ensureState(unit, ITranslationStates.STATE_RESOLVED);
+ if (generateCode)
+ Dependencies.ensureState(unit, ITranslationStates.STATE_BYTE_CODE_GENERATED);
+ else if (analyzeCode)
+ Dependencies.ensureState(unit, ITranslationStates.STATE_CODE_ANALYZED);
+ else
+ Dependencies.ensureState(unit, ITranslationStates.STATE_RESOLVED);
// SH}
-
- // finalize problems (suppressWarnings)
- unit.finalizeProblems();
+ // finalize problems (suppressWarnings)
+ unit.finalizeProblems();
+ } finally {
+ this.lookupEnvironment.unitBeingCompleted = previousUnit; // paranoia, always null in org.eclipse.jdt.core.tests.dom.RunAllTests
+ }
}
// TODO(SH): release also role file units!
if (this.unitsToProcess != null) this.unitsToProcess[0] = null; // release reference to processed unit declaration
@@ -1295,7 +1299,6 @@ class CompilationUnitResolver extends Compiler {
// this.reset();
}
}
-
/*
* Internal API used to resolve a given compilation unit. Can run a subset of the compilation process
*/
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java
index 5922e45a3..673f34ef8 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/rewrite/ImportRewrite.java
@@ -25,8 +25,7 @@ import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IImportDeclaration;
@@ -36,10 +35,42 @@ import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.dom.*;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTParser;
+import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
+import org.eclipse.jdt.core.dom.AnnotatableType;
+import org.eclipse.jdt.core.dom.Annotation;
+import org.eclipse.jdt.core.dom.ArrayInitializer;
+import org.eclipse.jdt.core.dom.ArrayType;
+import org.eclipse.jdt.core.dom.CharacterLiteral;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.Dimension;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.FieldAccess;
+import org.eclipse.jdt.core.dom.IAnnotationBinding;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IMemberValuePairBinding;
+import org.eclipse.jdt.core.dom.IMethodBinding;
+import org.eclipse.jdt.core.dom.ITypeBinding;
+import org.eclipse.jdt.core.dom.IVariableBinding;
+import org.eclipse.jdt.core.dom.ImportDeclaration;
+import org.eclipse.jdt.core.dom.MarkerAnnotation;
+import org.eclipse.jdt.core.dom.MemberValuePair;
+import org.eclipse.jdt.core.dom.Modifier;
+import org.eclipse.jdt.core.dom.Name;
+import org.eclipse.jdt.core.dom.NormalAnnotation;
+import org.eclipse.jdt.core.dom.ParameterizedType;
+import org.eclipse.jdt.core.dom.PrimitiveType;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SimpleType;
+import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
+import org.eclipse.jdt.core.dom.StringLiteral;
+import org.eclipse.jdt.core.dom.Type;
+import org.eclipse.jdt.core.dom.TypeLiteral;
+import org.eclipse.jdt.core.dom.WildcardType;
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
-import org.eclipse.jdt.internal.core.dom.rewrite.imports.ImportRewriteConfiguration;
import org.eclipse.jdt.internal.core.dom.rewrite.imports.ImportRewriteAnalyzer;
+import org.eclipse.jdt.internal.core.dom.rewrite.imports.ImportRewriteConfiguration;
import org.eclipse.jdt.internal.core.dom.rewrite.imports.ImportRewriteConfiguration.ImplicitImportIdentification;
import org.eclipse.jdt.internal.core.dom.rewrite.imports.ImportRewriteConfiguration.ImportContainerSorting;
import org.eclipse.jdt.internal.core.util.Messages;
@@ -1157,79 +1188,73 @@ public final class ImportRewrite {
* @throws CoreException the exception is thrown if the rewrite fails.
*/
public final TextEdit rewriteImports(IProgressMonitor monitor) throws CoreException {
- if (monitor == null) {
- monitor= new NullProgressMonitor();
- }
- try {
- monitor.beginTask(Messages.bind(Messages.importRewrite_processDescription), 2);
- if (!hasRecordedChanges()) {
- this.createdImports= CharOperation.NO_STRINGS;
- this.createdStaticImports= CharOperation.NO_STRINGS;
+ SubMonitor subMonitor = SubMonitor.convert(monitor,
+ Messages.bind(Messages.importRewrite_processDescription), 2);
+ if (!hasRecordedChanges()) {
+ this.createdImports= CharOperation.NO_STRINGS;
+ this.createdStaticImports= CharOperation.NO_STRINGS;
//{ObjectTeams: base
- this.createdBaseImports= CharOperation.NO_STRINGS;
-// SH}
- return new MultiTextEdit();
- }
+ this.createdBaseImports= CharOperation.NO_STRINGS;
+//SH}
+ return new MultiTextEdit();
+ }
- CompilationUnit usedAstRoot= this.astRoot;
- if (usedAstRoot == null) {
- ASTParser parser= ASTParser.newParser(AST.JLS8);
- parser.setSource(this.compilationUnit);
- parser.setFocalPosition(0); // reduced AST
- parser.setResolveBindings(false);
- usedAstRoot= (CompilationUnit) parser.createAST(new SubProgressMonitor(monitor, 1));
- }
+ CompilationUnit usedAstRoot= this.astRoot;
+ if (usedAstRoot == null) {
+ ASTParser parser= ASTParser.newParser(AST.JLS8);
+ parser.setSource(this.compilationUnit);
+ parser.setFocalPosition(0); // reduced AST
+ parser.setResolveBindings(false);
+ usedAstRoot= (CompilationUnit) parser.createAST(subMonitor.split(1));
+ }
- ImportRewriteConfiguration config= buildImportRewriteConfiguration();
+ ImportRewriteConfiguration config= buildImportRewriteConfiguration();
- ImportRewriteAnalyzer computer=
- new ImportRewriteAnalyzer(this.compilationUnit, usedAstRoot, config);
+ ImportRewriteAnalyzer computer=
+ new ImportRewriteAnalyzer(this.compilationUnit, usedAstRoot, config);
- for (String addedImport : this.addedImports) {
- boolean isStatic = STATIC_PREFIX == addedImport.charAt(0);
- String qualifiedName = addedImport.substring(1);
+ for (String addedImport : this.addedImports) {
+ boolean isStatic = STATIC_PREFIX == addedImport.charAt(0);
+ String qualifiedName = addedImport.substring(1);
//{ObjectTeams: base
/* orig:
- computer.addImport(isStatic, qualifiedName);
+ computer.addImport(isStatic, qualifiedName);
:giro */
- boolean isBase = BASE_PREFIX == addedImport.charAt(0);
- computer.addImport(isStatic, isBase, qualifiedName);
+ boolean isBase = BASE_PREFIX == addedImport.charAt(0);
+ computer.addImport(isStatic, isBase, qualifiedName);
// SH}
- }
+ }
- for (String removedImport : this.removedImports) {
- boolean isStatic = STATIC_PREFIX == removedImport.charAt(0);
- String qualifiedName = removedImport.substring(1);
+ for (String removedImport : this.removedImports) {
+ boolean isStatic = STATIC_PREFIX == removedImport.charAt(0);
+ String qualifiedName = removedImport.substring(1);
//{ObjectTeams: base
/* orig:
- computer.removeImport(isStatic, qualifiedName);
+ computer.removeImport(isStatic, qualifiedName);
:giro */
- boolean isBase = BASE_PREFIX == removedImport.charAt(0);
- computer.removeImport(isStatic, isBase, qualifiedName);
+ boolean isBase = BASE_PREFIX == removedImport.charAt(0);
+ computer.removeImport(isStatic, isBase, qualifiedName);
// SH}
- }
+ }
- for (String typeExplicitSimpleName : this.typeExplicitSimpleNames) {
- computer.requireExplicitImport(false, typeExplicitSimpleName);
- }
+ for (String typeExplicitSimpleName : this.typeExplicitSimpleNames) {
+ computer.requireExplicitImport(false, typeExplicitSimpleName);
+ }
- for (String staticExplicitSimpleName : this.staticExplicitSimpleNames) {
- computer.requireExplicitImport(true, staticExplicitSimpleName);
- }
+ for (String staticExplicitSimpleName : this.staticExplicitSimpleNames) {
+ computer.requireExplicitImport(true, staticExplicitSimpleName);
+ }
- ImportRewriteAnalyzer.RewriteResult result= computer.analyzeRewrite(new SubProgressMonitor(monitor, 1));
+ ImportRewriteAnalyzer.RewriteResult result= computer.analyzeRewrite(subMonitor.split(1));
- this.createdImports= result.getCreatedImports();
- this.createdStaticImports= result.getCreatedStaticImports();
+ this.createdImports= result.getCreatedImports();
+ this.createdStaticImports= result.getCreatedStaticImports();
//{ObjectTeams: base
- this.createdBaseImports= result.getCreatedBaseImports();
-// SH}
+ this.createdBaseImports= result.getCreatedBaseImports();
+//SH}
- return result.getTextEdit();
- } finally {
- monitor.done();
- }
+ return result.getTextEdit();
}
private ImportRewriteConfiguration buildImportRewriteConfiguration() {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
index a88db5e10..d3d643b19 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IJavaModelStatusConstants.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,9 +7,6 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
- *
- * TODO missing 2.1 and subsequent contributions
- * COMPILER_FAILURE
*******************************************************************************/
package org.eclipse.jdt.core;
@@ -352,4 +349,11 @@ public interface IJavaModelStatusConstants {
* @since 3.6.4
*/
public static final int OUTPUT_LOCATION_OVERLAPPING_ANOTHER_SOURCE = 1013;
+
+ /**
+ * <p>Status constant indicating that an external annotation path is invalid.</p>
+ * @since 3.12
+ * @see org.eclipse.jdt.core.IClasspathAttribute#EXTERNAL_ANNOTATION_PATH
+ */
+ public static final int CP_INVALID_EXTERNAL_ANNOTATION_PATH = 1014;
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
index 8a1508810..797de3497 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/JavaCore.java
@@ -104,6 +104,7 @@
* - added the following constants:
* COMPILER_CODEGEN_METHOD_PARAMETERS_ATTR
* Harry Terkelsen (het@google.com) - Bug 449262 - Allow the use of third-party Java formatters
+ * Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions
*
*******************************************************************************/
@@ -128,7 +129,7 @@ import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
@@ -1480,7 +1481,7 @@ public final class JavaCore extends Plugin {
* or a value of type <code>java.io.Closeable</code> (compliance<=1.6) and if
* flow analysis shows that the method <code>close()</code> is not invoked locally on that value.</p>
* <dl>
- * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.reportUnclosedCloseable"</code></dd>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.unclosedCloseable"</code></dd>
* <dt>Possible values:</dt><dd><code>{ "error", "warning", "info", "ignore" }</code></dd>
* <dt>Default:</dt><dd><code>"warning"</code></dd>
* </dl>
@@ -1496,7 +1497,7 @@ public final class JavaCore extends Plugin {
* flow analysis shows that the method <code>close()</code> is
* not invoked locally on that value for all execution paths.</p>
* <dl>
- * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.reportPotentiallyUnclosedCloseable"</code></dd>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable"</code></dd>
* <dt>Possible values:</dt><dd><code>{ "error", "warning", "info", "ignore" }</code></dd>
* <dt>Default:</dt><dd><code>"ignore"</code></dd>
* </dl>
@@ -1511,7 +1512,7 @@ public final class JavaCore extends Plugin {
* <code>close()</code> is explicitly invoked on that resource, but the resource is
* not managed by a try-with-resources block.</p>
* <dl>
- * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.reportPotentiallyUnclosedCloseable"</code></dd>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable"</code></dd>
* <dt>Possible values:</dt><dd><code>{ "error", "warning", "info", "ignore" }</code></dd>
* <dt>Default:</dt><dd><code>"ignore"</code></dd>
* </dl>
@@ -1567,6 +1568,29 @@ public final class JavaCore extends Plugin {
*/
public static final String COMPILER_NULLABLE_ANNOTATION_NAME = PLUGIN_ID + ".compiler.annotation.nullable"; //$NON-NLS-1$
/**
+ * Compiler option ID: Names of Secondary Annotation Types for Nullable Types.
+ * <p>This option defines a comma-separated list of fully qualified Java type names
+ * that the compiler may use to perform special null analysis.</p>
+ * <p>The annotation types identified by the names in this list are interpreted in the same way
+ * as the annotation identified by {@link #COMPILER_NULLABLE_ANNOTATION_NAME}.
+ * The intention is to support libraries using different sets of null annotations,
+ * in addition to those used by the current project. Secondary null annotations should not be
+ * used in the project's own source code.</p>
+ * <p>JDT will never actively use any secondary annotation names from this list,
+ * i.e., inferred null annotations and content assist proposals mentioning null annotations
+ * are always rendered using the primary name from {@link #COMPILER_NULLABLE_ANNOTATION_NAME}.</p>
+ * <p>This option only has an effect if the option {@link #COMPILER_ANNOTATION_NULL_ANALYSIS} is enabled.</p>
+ * <dl>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.annotation.nullable.secondary"</code></dd>
+ * <dt>Possible values:</dt><dd>a comma-separated list of legal, fully qualified Java type names;
+ * each name in the list must resolve to an annotation type.</dd>
+ * <dt>Default:</dt><dd><code>""</code></dd>
+ * </dl>
+ * @since 3.12
+ * @category CompilerOptionID
+ */
+ public static final String COMPILER_NULLABLE_ANNOTATION_SECONDARY_NAMES = PLUGIN_ID + ".compiler.annotation.nullable.secondary"; //$NON-NLS-1$
+ /**
* Compiler option ID: Name of Annotation Type for Non-Null Types.
* <p>This option defines a fully qualified Java type name that the compiler may use
* to perform special null analysis.</p>
@@ -1593,6 +1617,29 @@ public final class JavaCore extends Plugin {
*/
public static final String COMPILER_NONNULL_ANNOTATION_NAME = PLUGIN_ID + ".compiler.annotation.nonnull"; //$NON-NLS-1$
/**
+ * Compiler option ID: Names of Secondary Annotation Types for Non-Null Types.
+ * <p>This option defines a comma-separated list of fully qualified Java type names
+ * that the compiler may use to perform special null analysis.</p>
+ * <p>The annotation types identified by the names in this list are interpreted in the same way
+ * as the annotation identified by {@link #COMPILER_NONNULL_ANNOTATION_NAME}.
+ * The intention is to support libraries using different sets of null annotations,
+ * in addition to those used by the current project. Secondary null annotations should not be
+ * used in the project's own source code.</p>
+ * <p>JDT will never actively use any secondary annotation names from this list,
+ * i.e., inferred null annotations and content assist proposals mentioning null annotations
+ * are always rendered using the primary name from {@link #COMPILER_NONNULL_ANNOTATION_NAME}.</p>
+ * <p>This option only has an effect if the option {@link #COMPILER_ANNOTATION_NULL_ANALYSIS} is enabled.</p>
+ * <dl>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.annotation.nonnull.secondary"</code></dd>
+ * <dt>Possible values:</dt><dd>a comma-separated list of legal, fully qualified Java type names;
+ * each name in the list must resolve to an annotation type.</dd>
+ * <dt>Default:</dt><dd><code>""</code></dd>
+ * </dl>
+ * @since 3.12
+ * @category CompilerOptionID
+ */
+ public static final String COMPILER_NONNULL_ANNOTATION_SECONDARY_NAMES = PLUGIN_ID + ".compiler.annotation.nonnull.secondary"; //$NON-NLS-1$
+ /**
* Compiler option ID: Name of Annotation Type to specify a nullness default for unannotated types.
* <p>This option defines a fully qualified Java type name that the compiler may use
* to perform special null analysis.</p>
@@ -1613,6 +1660,26 @@ public final class JavaCore extends Plugin {
*/
public static final String COMPILER_NONNULL_BY_DEFAULT_ANNOTATION_NAME = PLUGIN_ID + ".compiler.annotation.nonnullbydefault"; //$NON-NLS-1$
/**
+ * Compiler option ID: Names of Secondary Annotation Types to specify a nullness default for unannotated types.
+ * <p>This option defines a comma-separated list of fully qualified Java type names
+ * that the compiler may use to perform special null analysis.</p>
+ * <p>The annotation types identified by the names in this list are interpreted in the same way
+ * as the annotation identified by {@link #COMPILER_NONNULL_BY_DEFAULT_ANNOTATION_NAME}.
+ * The intention is to support libraries using different sets of null annotations,
+ * in addition to those used by the current project. Secondary null annotations should not be
+ * used in the project's own source code.</p>
+ * <p>This option only has an effect if the option {@link #COMPILER_ANNOTATION_NULL_ANALYSIS} is enabled.</p>
+ * <dl>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary"</code></dd>
+ * <dt>Possible values:</dt><dd>a comma-separated list of legal, fully qualified Java type names;
+ * each name in the list must resolve to an annotation type.</dd>
+ * <dt>Default:</dt><dd><code>""</code></dd>
+ * </dl>
+ * @since 3.12
+ * @category CompilerOptionID
+ */
+ public static final String COMPILER_NONNULL_BY_DEFAULT_ANNOTATION_SECONDARY_NAMES = PLUGIN_ID + ".compiler.annotation.nonnullbydefault.secondary"; //$NON-NLS-1$
+ /**
* Compiler option ID: Reporting missing default nullness annotation.
* <p>When enabled, the compiler will issue an error or a warning in the following cases:</p>
* <ul>
@@ -2431,6 +2498,19 @@ public final class JavaCore extends Plugin {
*/
public static final String CODEASSIST_CAMEL_CASE_MATCH = PLUGIN_ID + ".codeComplete.camelCaseMatch"; //$NON-NLS-1$
/**
+ * Code assist option ID: Activate Substring Code Completion.
+ * <p>When enabled, completion shows proposals in which the pattern can
+ * be found as a substring in a case-insensitive way.</p>
+ * <dl>
+ * <dt>Option id:</dt><dd><code>"org.eclipse.jdt.core.codeComplete.substringMatch"</code></dd>
+ * <dt>Possible values:</dt><dd><code>{ "enabled", "disabled" }</code></dd>
+ * <dt>Default:</dt><dd><code>"enabled"</code></dd>
+ * </dl>
+ * @since 3.12
+ * @category CodeAssistOptionID
+ */
+ public static final String CODEASSIST_SUBSTRING_MATCH = PLUGIN_ID + ".codeComplete.substringMatch"; //$NON-NLS-1$
+ /**
* Code assist option ID: Automatic Qualification of Implicit Members.
* <p>When active, completion automatically qualifies completion on implicit
* field references and message expressions.</p>
@@ -4088,191 +4168,171 @@ public final class JavaCore extends Plugin {
* @since 3.1
*/
public static void initializeAfterLoad(IProgressMonitor monitor) throws CoreException {
- try {
- if (monitor != null) {
- monitor.beginTask(Messages.javamodel_initialization, 100);
- monitor.subTask(Messages.javamodel_configuring_classpath_containers);
- }
+ SubMonitor mainMonitor = SubMonitor.convert(monitor, Messages.javamodel_initialization, 100);
+ mainMonitor.subTask(Messages.javamodel_configuring_classpath_containers);
- // initialize all containers and variables
- JavaModelManager manager = JavaModelManager.getJavaModelManager();
- SubProgressMonitor subMonitor = null;
- try {
- if (monitor != null) {
- subMonitor = new SubProgressMonitor(monitor, 50); // 50% of the time is spent in initializing containers and variables
- subMonitor.beginTask("", 100); //$NON-NLS-1$
- subMonitor.worked(5); // give feedback to the user that something is happening
- manager.batchContainerInitializationsProgress.initializeAfterLoadMonitor.set(subMonitor);
- }
- if (manager.forceBatchInitializations(true/*initAfterLoad*/)) { // if no other thread has started the batch container initializations
- manager.getClasspathContainer(Path.EMPTY, null); // force the batch initialization
- } else { // else wait for the batch initialization to finish
- while (manager.batchContainerInitializations == JavaModelManager.BATCH_INITIALIZATION_IN_PROGRESS) {
- if (subMonitor != null) {
- subMonitor.subTask(manager.batchContainerInitializationsProgress.subTaskName);
- subMonitor.worked(manager.batchContainerInitializationsProgress.getWorked());
- }
- synchronized(manager) {
- try {
- manager.wait(100);
- } catch (InterruptedException e) {
- // continue
- }
+ // initialize all containers and variables
+ JavaModelManager manager = JavaModelManager.getJavaModelManager();
+ try {
+ SubMonitor subMonitor = mainMonitor.split(50).setWorkRemaining(100); // 50% of the time is spent in initializing containers and variables
+ subMonitor.worked(5); // give feedback to the user that something is happening
+ manager.batchContainerInitializationsProgress.initializeAfterLoadMonitor.set(subMonitor);
+ if (manager.forceBatchInitializations(true/*initAfterLoad*/)) { // if no other thread has started the batch container initializations
+ manager.getClasspathContainer(Path.EMPTY, null); // force the batch initialization
+ } else { // else wait for the batch initialization to finish
+ while (manager.batchContainerInitializations == JavaModelManager.BATCH_INITIALIZATION_IN_PROGRESS) {
+ subMonitor.subTask(manager.batchContainerInitializationsProgress.subTaskName);
+ subMonitor.worked(manager.batchContainerInitializationsProgress.getWorked());
+ synchronized(manager) {
+ try {
+ manager.wait(100);
+ } catch (InterruptedException e) {
+ // continue
}
}
}
- } finally {
- if (subMonitor != null)
- subMonitor.done();
- manager.batchContainerInitializationsProgress.initializeAfterLoadMonitor.set(null);
}
+ } finally {
+ manager.batchContainerInitializationsProgress.initializeAfterLoadMonitor.set(null);
+ }
- // avoid leaking source attachment properties (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=183413 )
- // and recreate links for external folders if needed
- if (monitor != null)
- monitor.subTask(Messages.javamodel_resetting_source_attachment_properties);
- final IJavaProject[] projects = manager.getJavaModel().getJavaProjects();
- HashSet visitedPaths = new HashSet();
- ExternalFoldersManager externalFoldersManager = JavaModelManager.getExternalManager();
- for (int i = 0, length = projects.length; i < length; i++) {
- JavaProject javaProject = (JavaProject) projects[i];
- IClasspathEntry[] classpath;
- try {
- classpath = javaProject.getResolvedClasspath();
- } catch (JavaModelException e) {
- // project no longer exist: ignore
- continue;
- }
- if (classpath != null) {
- for (int j = 0, length2 = classpath.length; j < length2; j++) {
- IClasspathEntry entry = classpath[j];
- if (entry.getSourceAttachmentPath() != null) {
- IPath entryPath = entry.getPath();
- if (visitedPaths.add(entryPath)) {
- Util.setSourceAttachmentProperty(entryPath, null);
- }
+ // avoid leaking source attachment properties (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=183413 )
+ // and recreate links for external folders if needed
+ mainMonitor.subTask(Messages.javamodel_resetting_source_attachment_properties);
+ final IJavaProject[] projects = manager.getJavaModel().getJavaProjects();
+ HashSet visitedPaths = new HashSet();
+ ExternalFoldersManager externalFoldersManager = JavaModelManager.getExternalManager();
+ for (int i = 0, length = projects.length; i < length; i++) {
+ JavaProject javaProject = (JavaProject) projects[i];
+ IClasspathEntry[] classpath;
+ try {
+ classpath = javaProject.getResolvedClasspath();
+ } catch (JavaModelException e) {
+ // project no longer exist: ignore
+ continue;
+ }
+ if (classpath != null) {
+ for (int j = 0, length2 = classpath.length; j < length2; j++) {
+ IClasspathEntry entry = classpath[j];
+ if (entry.getSourceAttachmentPath() != null) {
+ IPath entryPath = entry.getPath();
+ if (visitedPaths.add(entryPath)) {
+ Util.setSourceAttachmentProperty(entryPath, null);
}
- // else source might have been attached by IPackageFragmentRoot#attachSource(...), we keep it
- if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
- IPath entryPath = entry.getPath();
- if (ExternalFoldersManager.isExternalFolderPath(entryPath) && externalFoldersManager.getFolder(entryPath) == null) {
- externalFoldersManager.addFolder(entryPath, true);
- }
+ }
+ // else source might have been attached by IPackageFragmentRoot#attachSource(...), we keep it
+ if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+ IPath entryPath = entry.getPath();
+ if (ExternalFoldersManager.isExternalFolderPath(entryPath) && externalFoldersManager.getFolder(entryPath) == null) {
+ externalFoldersManager.addFolder(entryPath, true);
}
}
}
}
- try {
- externalFoldersManager.createPendingFolders(monitor);
- }
- catch(JavaModelException jme) {
- // Creation of external folder project failed. Log it and continue;
- Util.log(jme, "Error while processing external folders"); //$NON-NLS-1$
- }
+ }
+ try {
+ externalFoldersManager.createPendingFolders(mainMonitor.split(1));
+ }
+ catch(JavaModelException jme) {
+ // Creation of external folder project failed. Log it and continue;
+ Util.log(jme, "Error while processing external folders"); //$NON-NLS-1$
+ }
- // ensure external jars are refreshed (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=93668)
- // before search is initialized (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=405051)
- final JavaModel model = manager.getJavaModel();
- try {
- if (monitor != null)
- monitor.subTask(Messages.javamodel_refreshing_external_jars);
- model.refreshExternalArchives(
- null/*refresh all projects*/,
- monitor == null ? null : new SubProgressMonitor(monitor, 1) // 1% of the time is spent in jar refresh
- );
- } catch (JavaModelException e) {
- // refreshing failed: ignore
- }
+ // ensure external jars are refreshed (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=93668)
+ // before search is initialized (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=405051)
+ final JavaModel model = manager.getJavaModel();
+ try {
+ mainMonitor.subTask(Messages.javamodel_refreshing_external_jars);
+ model.refreshExternalArchives(
+ null/*refresh all projects*/,
+ mainMonitor.split(1) // 1% of the time is spent in jar refresh
+ );
+ } catch (JavaModelException e) {
+ // refreshing failed: ignore
+ }
- // initialize delta state
- if (monitor != null)
- monitor.subTask(Messages.javamodel_initializing_delta_state);
- manager.deltaState.rootsAreStale = true; // in case it was already initialized before we cleaned up the source attachment properties
- manager.deltaState.initializeRoots(true/*initAfteLoad*/);
-
- // dummy query for waiting until the indexes are ready
- if (monitor != null)
- monitor.subTask(Messages.javamodel_configuring_searchengine);
- SearchEngine engine = new SearchEngine();
- IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
- try {
- engine.searchAllTypeNames(
- null,
- SearchPattern.R_EXACT_MATCH,
- "!@$#!@".toCharArray(), //$NON-NLS-1$
- SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE,
- IJavaSearchConstants.CLASS,
- scope,
- new TypeNameRequestor() {
- public void acceptType(
- int modifiers,
- char[] packageName,
- char[] simpleTypeName,
- char[][] enclosingTypeNames,
- String path) {
- // no type to accept
- }
- },
- // will not activate index query caches if indexes are not ready, since it would take to long
- // to wait until indexes are fully rebuild
- IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH,
- monitor == null ? null : new SubProgressMonitor(monitor, 49) // 49% of the time is spent in the dummy search
- );
- } catch (JavaModelException e) {
- // /search failed: ignore
- } catch (OperationCanceledException e) {
- if (monitor != null && monitor.isCanceled())
- throw e;
- // else indexes were not ready: catch the exception so that jars are still refreshed
- }
+ // initialize delta state
+ mainMonitor.subTask(Messages.javamodel_initializing_delta_state);
+ manager.deltaState.rootsAreStale = true; // in case it was already initialized before we cleaned up the source attachment properties
+ manager.deltaState.initializeRoots(true/*initAfteLoad*/);
- // check if the build state version number has changed since last session
- // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=98969)
- if (monitor != null)
- monitor.subTask(Messages.javamodel_getting_build_state_number);
- QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID, "stateVersionNumber"); //$NON-NLS-1$
- IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
- String versionNumber = null;
- try {
- versionNumber = root.getPersistentProperty(qName);
- } catch (CoreException e) {
- // could not read version number: consider it is new
- }
- String newVersionNumber = Byte.toString(State.VERSION);
- if (!newVersionNumber.equals(versionNumber)) {
- // build state version number has changed: touch every projects to force a rebuild
- if (JavaBuilder.DEBUG)
- System.out.println("Build state version number has changed"); //$NON-NLS-1$
- IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
- public void run(IProgressMonitor progressMonitor2) throws CoreException {
- for (int i = 0, length = projects.length; i < length; i++) {
- IJavaProject project = projects[i];
- try {
- if (JavaBuilder.DEBUG)
- System.out.println("Touching " + project.getElementName()); //$NON-NLS-1$
- new ClasspathValidation((JavaProject) project).validate(); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=287164
- project.getProject().touch(progressMonitor2);
- } catch (CoreException e) {
- // could not touch this project: ignore
- }
+ // dummy query for waiting until the indexes are ready
+ mainMonitor.subTask(Messages.javamodel_configuring_searchengine);
+ SearchEngine engine = new SearchEngine();
+ IJavaSearchScope scope = SearchEngine.createWorkspaceScope();
+ try {
+ engine.searchAllTypeNames(
+ null,
+ SearchPattern.R_EXACT_MATCH,
+ "!@$#!@".toCharArray(), //$NON-NLS-1$
+ SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE,
+ IJavaSearchConstants.CLASS,
+ scope,
+ new TypeNameRequestor() {
+ public void acceptType(
+ int modifiers,
+ char[] packageName,
+ char[] simpleTypeName,
+ char[][] enclosingTypeNames,
+ String path) {
+ // no type to accept
+ }
+ },
+ // will not activate index query caches if indexes are not ready, since it would take to long
+ // to wait until indexes are fully rebuild
+ IJavaSearchConstants.CANCEL_IF_NOT_READY_TO_SEARCH,
+ mainMonitor.split(47) // 47% of the time is spent in the dummy search
+ );
+ } catch (JavaModelException e) {
+ // /search failed: ignore
+ } catch (OperationCanceledException e) {
+ if (mainMonitor.isCanceled())
+ throw e;
+ // else indexes were not ready: catch the exception so that jars are still refreshed
+ }
+
+ // check if the build state version number has changed since last session
+ // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=98969)
+ mainMonitor.subTask(Messages.javamodel_getting_build_state_number);
+ QualifiedName qName = new QualifiedName(JavaCore.PLUGIN_ID, "stateVersionNumber"); //$NON-NLS-1$
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+ String versionNumber = null;
+ try {
+ versionNumber = root.getPersistentProperty(qName);
+ } catch (CoreException e) {
+ // could not read version number: consider it is new
+ }
+ String newVersionNumber = Byte.toString(State.VERSION);
+ if (!newVersionNumber.equals(versionNumber)) {
+ // build state version number has changed: touch every projects to force a rebuild
+ if (JavaBuilder.DEBUG)
+ System.out.println("Build state version number has changed"); //$NON-NLS-1$
+ IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
+ public void run(IProgressMonitor progressMonitor2) throws CoreException {
+ for (int i = 0, length = projects.length; i < length; i++) {
+ IJavaProject project = projects[i];
+ try {
+ if (JavaBuilder.DEBUG)
+ System.out.println("Touching " + project.getElementName()); //$NON-NLS-1$
+ new ClasspathValidation((JavaProject) project).validate(); // https://bugs.eclipse.org/bugs/show_bug.cgi?id=287164
+ project.getProject().touch(progressMonitor2);
+ } catch (CoreException e) {
+ // could not touch this project: ignore
}
}
- };
- if (monitor != null)
- monitor.subTask(Messages.javamodel_building_after_upgrade);
- try {
- ResourcesPlugin.getWorkspace().run(runnable, monitor);
- } catch (CoreException e) {
- // could not touch all projects
- }
- try {
- root.setPersistentProperty(qName, newVersionNumber);
- } catch (CoreException e) {
- Util.log(e, "Could not persist build state version number"); //$NON-NLS-1$
}
+ };
+ mainMonitor.subTask(Messages.javamodel_building_after_upgrade);
+ try {
+ ResourcesPlugin.getWorkspace().run(runnable, mainMonitor.split(1));
+ } catch (CoreException e) {
+ // could not touch all projects
+ }
+ try {
+ root.setPersistentProperty(qName, newVersionNumber);
+ } catch (CoreException e) {
+ Util.log(e, "Could not persist build state version number"); //$NON-NLS-1$
}
- } finally {
- if (monitor != null) monitor.done();
}
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
index e86c4a544..b1f54b720 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java
@@ -376,7 +376,7 @@ private IBinaryType getJarBinaryTypeInfo(PackageFragment pkg, boolean fullyIniti
IClasspathEntry entry = javaProject.getClasspathEntryFor(getPath());
if (entry != null) {
IProject project = javaProject.getProject();
- IPath externalAnnotationPath = ClasspathEntry.getExternalAnnotationPath(entry, project, false);
+ IPath externalAnnotationPath = ClasspathEntry.getExternalAnnotationPath(entry, project, false); // unresolved for use in ExternalAnnotationTracker
if (externalAnnotationPath != null)
setupExternalAnnotationProvider(project, externalAnnotationPath, annotationZip, reader,
entryName.substring(0, entryName.length() - SuffixConstants.SUFFIX_CLASS.length));
@@ -396,11 +396,14 @@ private void setupExternalAnnotationProvider(IProject project, final IPath exter
{
// try resolve path within the workspace:
IWorkspaceRoot root = project.getWorkspace().getRoot();
- IResource resource = externalAnnotationPath.segmentCount() == 1
- ? root.getProject(externalAnnotationPath.lastSegment())
- : root.getFolder(externalAnnotationPath);
- if (!resource.exists())
- resource = root.getFile(externalAnnotationPath);
+ IResource resource;
+ if (externalAnnotationPath.segmentCount() == 1) {
+ resource = root.getProject(externalAnnotationPath.lastSegment());
+ } else {
+ resource = root.getFolder(externalAnnotationPath);
+ if (!resource.exists())
+ resource = root.getFile(externalAnnotationPath);
+ }
String resolvedPath;
if (resource.exists()) {
if (resource.isVirtual()) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
index a003b2bf5..08acbd600 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClasspathEntry.java
@@ -35,6 +35,7 @@ import java.util.zip.ZipFile;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
@@ -47,6 +48,7 @@ import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathContainer;
import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaModelMarker;
import org.eclipse.jdt.core.IJavaModelStatus;
import org.eclipse.jdt.core.IJavaModelStatusConstants;
import org.eclipse.jdt.core.IJavaProject;
@@ -1285,15 +1287,13 @@ public class ClasspathEntry implements IClasspathEntry {
return annotationPath;
// try Workspace-absolute:
- IProject targetProject = project.getWorkspace().getRoot().getProject(annotationPath.segment(0));
- if (targetProject.exists()) {
- if (annotationPath.segmentCount() > 1)
- return targetProject.getLocation().append(annotationPath.removeFirstSegments(1));
- else
- return targetProject.getLocation();
+ IResource resource = project.getWorkspace().getRoot().findMember(annotationPath);
+ if (resource != null) {
+ return resource.getLocation();
+ } else if (new File(annotationPath.toOSString()).exists()) { // absolute, not in workspace, must be Filesystem-absolute
+ return annotationPath;
}
- // absolute, not in workspace, must be Filesystem-absolute:
- return annotationPath;
+ invalidExternalAnnotationPath(project);
} else {
// try Variable (always resolved):
IPath resolved = JavaCore.getResolvedVariablePath(annotationPath);
@@ -1302,10 +1302,14 @@ public class ClasspathEntry implements IClasspathEntry {
// Project-relative:
if (project != null) {
- if (resolve)
- return project.getLocation().append(annotationPath);
- else
+ if (resolve) {
+ IResource member = project.findMember(annotationPath);
+ if (member != null)
+ return member.getLocation();
+ invalidExternalAnnotationPath(project);
+ } else {
return new Path(project.getName()).append(annotationPath).makeAbsolute();
+ }
}
}
}
@@ -1327,7 +1331,42 @@ public class ClasspathEntry implements IClasspathEntry {
}
return null;
}
-
+
+ private static void invalidExternalAnnotationPath(IProject project) {
+ try {
+ IMarker[] markers = project.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
+ for (int i = 0, l = markers.length; i < l; i++) {
+ if (markers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR)
+ return; // one marker is enough
+ }
+ } catch (CoreException ce) {
+ return;
+ }
+ // no buildpath marker yet, trigger validation to create one:
+ new ClasspathValidation((JavaProject) JavaCore.create(project)).validate();
+ }
+
+ private IJavaModelStatus validateExternalAnnotationPath(IJavaProject javaProject, IPath annotationPath) {
+ IProject project = javaProject.getProject();
+ if (annotationPath.isAbsolute()) {
+ if (project.getWorkspace().getRoot().exists(annotationPath) // workspace absolute
+ || new File(annotationPath.toOSString()).exists()) // file system abolute
+ {
+ return null;
+ }
+ } else {
+ if (JavaCore.getResolvedVariablePath(annotationPath) != null // variable (relative)
+ || project.exists(annotationPath)) // project relative
+ {
+ return null;
+ }
+ }
+ return new JavaModelStatus(IJavaModelStatusConstants.CP_INVALID_EXTERNAL_ANNOTATION_PATH,
+ javaProject,
+ Messages.bind(Messages.classpath_invalidExternalAnnotationPath,
+ new String[] { annotationPath.toString(), project.getName(), this.path.toString()}));
+ }
+
public IClasspathEntry getReferencingEntry() {
return this.referencingEntry;
}
@@ -2029,6 +2068,14 @@ public class ClasspathEntry implements IClasspathEntry {
break;
}
}
+ if (status == null) {
+ String annotationPath = getRawExternalAnnotationPath(entry);
+ if (annotationPath != null) {
+ status = ((ClasspathEntry) entry).validateExternalAnnotationPath(project, new Path(annotationPath));
+ if (status != null)
+ return status;
+ }
+ }
}
IClasspathContainer container = JavaModelManager.getJavaModelManager().getClasspathContainer(path, project);
// container retrieval is performing validation check on container entry kinds.
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java
index cf9aa67c4..1633475bb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ExternalFoldersManager.java
@@ -64,14 +64,14 @@ public class ExternalFoldersManager {
getFolders();
}
}
-
+
public static synchronized ExternalFoldersManager getExternalFoldersManager() {
if (MANAGER == null) {
MANAGER = new ExternalFoldersManager();
}
return MANAGER;
}
-
+
/**
* Returns a set of external paths to external folders referred to on the given classpath.
* Returns <code>null</code> if there are none.
@@ -152,8 +152,8 @@ public class ExternalFoldersManager {
knownFolders.put(externalFolderPath, result);
return result;
}
-
- /**
+
+ /**
* Try to remove the argument from the list of folders pending for creation.
* @param externalPath to link to
* @return true if the argument was found in the list of pending folders and could be removed from it.
@@ -171,7 +171,7 @@ public class ExternalFoldersManager {
private IFolder createLinkFolder(IPath externalFolderPath, boolean refreshIfExistAlready,
IProject externalFoldersProject, IProgressMonitor monitor) throws CoreException {
-
+
IFolder result = addFolder(externalFolderPath, externalFoldersProject, false);
if (!result.exists())
result.createLink(externalFolderPath, IResource.ALLOW_MISSING_LOCAL, monitor);
@@ -184,7 +184,7 @@ public class ExternalFoldersManager {
synchronized (this) {
if (this.pendingFolders == null || this.pendingFolders.isEmpty()) return;
}
-
+
IProject externalFoldersProject = null;
try {
externalFoldersProject = createExternalFoldersProject(monitor);
@@ -209,7 +209,7 @@ public class ExternalFoldersManager {
}
}
}
-
+
public void cleanUp(IProgressMonitor monitor) throws CoreException {
ArrayList toDelete = getFoldersToCleanUp(monitor);
if (toDelete == null)
@@ -275,7 +275,7 @@ public class ExternalFoldersManager {
project.open(monitor);
} catch (CoreException e1) {
if (e1.getStatus().getCode() == IResourceStatus.FAILED_READ_METADATA) {
- // workspace was moved
+ // workspace was moved
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=241400 and https://bugs.eclipse.org/bugs/show_bug.cgi?id=252571 )
project.delete(false/*don't delete content*/, true/*force*/, monitor);
createExternalFoldersProject(project, monitor);
@@ -353,7 +353,7 @@ public class ExternalFoldersManager {
}
return this.folders;
}
-
+
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=313153
// Use the same RefreshJob if the job is still available
private void runRefreshJob(Collection paths) {
@@ -391,15 +391,15 @@ public class ExternalFoldersManager {
continue;
HashSet foldersInProject = getExternalFolders(((JavaProject) JavaCore.create(sourceProjects[index])).getResolvedClasspath());
-
+
if (foldersInProject == null || foldersInProject.size() == 0)
continue;
if (externalFolders == null)
externalFolders = new HashSet();
-
+
externalFolders.addAll(foldersInProject);
}
- if (externalFolders == null)
+ if (externalFolders == null)
return;
runRefreshJob(externalFolders);
@@ -419,7 +419,7 @@ public class ExternalFoldersManager {
HashSet externalFolders = getExternalFolders(((JavaProject) JavaCore.create(source)).getResolvedClasspath());
if (externalFolders == null)
return;
-
+
runRefreshJob(externalFolders);
} catch (CoreException e) {
Util.log(e, "Exception while refreshing external project"); //$NON-NLS-1$
@@ -441,18 +441,18 @@ public class ExternalFoldersManager {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
setRule(workspace.getRuleFactory().refreshRule(workspace.getRoot()));
}
-
+
public boolean belongsTo(Object family) {
return family == ResourcesPlugin.FAMILY_MANUAL_REFRESH;
}
-
+
/*
- * Add the collection of paths to be refreshed to the already
- * existing list of paths.
+ * Add the collection of paths to be refreshed to the already
+ * existing list of paths.
*/
public void addFoldersToRefresh(Collection paths) {
if (!paths.isEmpty() && this.externalFolders == null) {
- this.externalFolders = new Vector();
+ this.externalFolders = new Vector();
}
Iterator it = paths.iterator();
while(it.hasNext()) {
@@ -462,10 +462,10 @@ public class ExternalFoldersManager {
}
}
}
-
+
protected IStatus run(IProgressMonitor pm) {
try {
- if (this.externalFolders == null)
+ if (this.externalFolders == null)
return Status.OK_STATUS;
IPath externalPath = null;
for (int index = 0; index < this.externalFolders.size(); index++ ) {
@@ -487,5 +487,5 @@ public class ExternalFoldersManager {
return Status.OK_STATUS;
}
}
-
+
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
index 28812d770..2b1f88191 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaCorePreferenceInitializer.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -8,6 +8,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Harry Terkelsen (het@google.com) - Bug 449262 - Allow the use of third-party Java formatters
+ * Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions
*******************************************************************************/
package org.eclipse.jdt.internal.core;
@@ -93,6 +94,7 @@ public class JavaCorePreferenceInitializer extends AbstractPreferenceInitializer
defaultOptionsMap.put(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, JavaCore.ENABLED);
defaultOptionsMap.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED);
defaultOptionsMap.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH, JavaCore.ENABLED);
+ defaultOptionsMap.put(JavaCore.CODEASSIST_SUBSTRING_MATCH, JavaCore.ENABLED);
defaultOptionsMap.put(JavaCore.CODEASSIST_SUGGEST_STATIC_IMPORTS, JavaCore.ENABLED);
// Time out for parameter names
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
index 045973d22..a176f42d5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java
@@ -18,6 +18,7 @@
* Thirumala Reddy Mutchukota <thirumala@google.com> - Contribution to bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=411423
* Terry Parker <tparker@google.com> - [performance] Low hit rates in JavaModel caches - https://bugs.eclipse.org/421165
* Terry Parker <tparker@google.com> - Enable the Java model caches to recover from IO errors - https://bugs.eclipse.org/455042
+ * Gábor Kövesdán - Contribution for Bug 350000 - [content assist] Include non-prefix matches in auto-complete suggestions
*******************************************************************************/
package org.eclipse.jdt.internal.core;
@@ -2279,6 +2280,7 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
defaultOptionsMap.put(JavaCore.CODEASSIST_FORBIDDEN_REFERENCE_CHECK, JavaCore.ENABLED);
defaultOptionsMap.put(JavaCore.CODEASSIST_DISCOURAGED_REFERENCE_CHECK, JavaCore.DISABLED);
defaultOptionsMap.put(JavaCore.CODEASSIST_CAMEL_CASE_MATCH, JavaCore.ENABLED);
+ defaultOptionsMap.put(JavaCore.CODEASSIST_SUBSTRING_MATCH, JavaCore.ENABLED);
defaultOptionsMap.put(JavaCore.CODEASSIST_SUGGEST_STATIC_IMPORTS, JavaCore.ENABLED);
// Time out for parameter names
@@ -3070,22 +3072,12 @@ public class JavaModelManager implements ISaveParticipant, IContentTypeChangeLis
void touchProjects(final IProject[] projectsToTouch, IProgressMonitor progressMonitor) throws JavaModelException {
WorkspaceJob touchJob = new WorkspaceJob(Messages.synchronizing_projects_job) {
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
- try {
- if (monitor != null) {
- monitor.beginTask("", projectsToTouch.length); //$NON-NLS-1$
- }
- for (IProject iProject : projectsToTouch) {
- IProgressMonitor subMonitor = monitor == null ? null: new SubProgressMonitor(monitor, 1);
- if (JavaBuilder.DEBUG) {
- System.out.println("Touching project " + iProject.getName()); //$NON-NLS-1$
- }
- iProject.touch(subMonitor);
- }
- }
- finally {
- if (monitor != null) {
- monitor.done();
+ SubMonitor subMonitor = SubMonitor.convert(monitor, projectsToTouch.length);
+ for (IProject iProject : projectsToTouch) {
+ if (JavaBuilder.DEBUG) {
+ System.out.println("Touching project " + iProject.getName()); //$NON-NLS-1$
}
+ iProject.touch(subMonitor.split(1));
}
return Status.OK_STATUS;
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java
index 176079ead..66ccb7566 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelOperation.java
@@ -96,7 +96,7 @@ public abstract class JavaModelOperation implements IWorkspaceRunnable, IProgres
/**
* The progress monitor passed into this operation
*/
- public IProgressMonitor progressMonitor= null;
+ public SubMonitor progressMonitor= SubMonitor.convert(null);
/**
* A flag indicating whether this operation is nested.
*/
@@ -515,11 +515,7 @@ public abstract class JavaModelOperation implements IWorkspaceRunnable, IProgres
* Creates and returns a subprogress monitor if appropriate.
*/
protected IProgressMonitor getSubProgressMonitor(int workAmount) {
- IProgressMonitor sub = null;
- if (this.progressMonitor != null) {
- sub = new SubProgressMonitor(this.progressMonitor, workAmount, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
- }
- return sub;
+ return this.progressMonitor.split(workAmount);
}
/**
@@ -576,17 +572,14 @@ public abstract class JavaModelOperation implements IWorkspaceRunnable, IProgres
* Convenience method to move resources
*/
protected void moveResources(IResource[] resources, IPath container) throws JavaModelException {
- IProgressMonitor subProgressMonitor = null;
- if (this.progressMonitor != null) {
- subProgressMonitor = new SubProgressMonitor(this.progressMonitor, resources.length, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
- }
+ SubMonitor subProgressMonitor = this.progressMonitor.newChild(resources.length);
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
try {
for (int i = 0, length = resources.length; i < length; i++) {
IResource resource = resources[i];
IPath destination = container.append(resource.getName());
if (root.findMember(destination) == null) {
- resource.move(destination, false, subProgressMonitor);
+ resource.move(destination, false, subProgressMonitor.split(1));
}
}
setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
@@ -717,7 +710,7 @@ public abstract class JavaModelOperation implements IWorkspaceRunnable, IProgres
DeltaProcessor deltaProcessor = manager.getDeltaProcessor();
int previousDeltaCount = deltaProcessor.javaModelDeltas.size();
try {
- this.progressMonitor = monitor;
+ this.progressMonitor = SubMonitor.convert(monitor);
pushOperation(this);
try {
if (canModifyRoots()) {
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
index 5d00b8130..7c3fd11b2 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/JavaBuilder.java
@@ -652,11 +652,20 @@ private int initializeBuilder(int kind, boolean forBuild) throws CoreException {
return kind;
}
-private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p) throws CoreException {
- IMarker[] markers = p.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
- for (int i = 0, l = markers.length; i < l; i++)
- if (markers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR)
+private boolean isClasspathBroken(JavaProject jProj, boolean tryRepair) throws CoreException {
+ IMarker[] markers = jProj.getProject().findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
+ for (int i = 0, l = markers.length; i < l; i++) {
+ if (markers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR) {
+ if (tryRepair) {
+ Object code = markers[i].getAttribute(IJavaModelMarker.ID);
+ if (code instanceof Integer && ((Integer)code) == IJavaModelStatusConstants.CP_INVALID_EXTERNAL_ANNOTATION_PATH) {
+ new ClasspathValidation(jProj).validate();
+ return isClasspathBroken(jProj, false);
+ }
+ }
return true;
+ }
+ }
return false;
}
@@ -670,7 +679,7 @@ private boolean isWorthBuilding() throws CoreException {
}
// Abort build only if there are classpath errors
- if (isClasspathBroken(this.javaProject.getRawClasspath(), this.currentProject)) {
+ if (isClasspathBroken(this.javaProject, true)) {
if (DEBUG)
System.out.println("JavaBuilder: Aborted build because project has classpath errors (incomplete or involved in cycle)"); //$NON-NLS-1$
@@ -721,7 +730,7 @@ private boolean isWorthBuilding() throws CoreException {
marker.setAttributes(
new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
new Object[] {
- isClasspathBroken(prereq.getRawClasspath(), p)
+ isClasspathBroken(prereq, true)
? Messages.bind(Messages.build_prereqProjectHasClasspathProblems, p.getName())
: Messages.bind(Messages.build_prereqProjectMustBeRebuilt, p.getName()),
new Integer(IMarker.SEVERITY_ERROR),
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
index 578adbdd4..e13711348 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/IndexBasedHierarchyBuilder.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -10,17 +10,31 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.hierarchy;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.core.runtime.SubProgressMonitor;
-import org.eclipse.jdt.core.*;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IPackageFragmentRoot;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.core.search.*;
+import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchParticipant;
+import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
import org.eclipse.jdt.internal.compiler.env.IBinaryType;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
@@ -29,7 +43,14 @@ import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
-import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.ClassFile;
+import org.eclipse.jdt.internal.core.IPathRequestor;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.Member;
+import org.eclipse.jdt.internal.core.Openable;
+import org.eclipse.jdt.internal.core.PackageFragment;
+import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.internal.core.search.IndexQueryRequestor;
import org.eclipse.jdt.internal.core.search.JavaSearchParticipant;
import org.eclipse.jdt.internal.core.search.SubTypeSearchJob;
@@ -113,10 +134,7 @@ public void build(boolean computeSubtypes) {
IType focusType = getType();
boolean focusIsObject = focusType.getElementName().equals(new String(IIndexConstants.OBJECT));
int amountOfWorkForSubtypes = focusIsObject ? 5 : 80; // percentage of work needed to get possible subtypes
- IProgressMonitor possibleSubtypesMonitor =
- this.hierarchy.progressMonitor == null ?
- null :
- new SubProgressMonitor(this.hierarchy.progressMonitor, amountOfWorkForSubtypes);
+ SubMonitor possibleSubtypesMonitor = this.hierarchy.progressMonitor.split(amountOfWorkForSubtypes);
HashSet localTypes = new HashSet(10); // contains the paths that have potential subtypes that are local/anonymous types
String[] allPossibleSubtypes;
if (((Member)focusType).getOuterMostLocalContext() == null) {
@@ -127,10 +145,7 @@ public void build(boolean computeSubtypes) {
allPossibleSubtypes = CharOperation.NO_STRINGS;
}
if (allPossibleSubtypes != null) {
- IProgressMonitor buildMonitor =
- this.hierarchy.progressMonitor == null ?
- null :
- new SubProgressMonitor(this.hierarchy.progressMonitor, 100 - amountOfWorkForSubtypes);
+ SubMonitor buildMonitor = this.hierarchy.progressMonitor.split(100 - amountOfWorkForSubtypes);
this.hierarchy.initialize(allPossibleSubtypes.length);
buildFromPotentialSubtypes(allPossibleSubtypes, localTypes, buildMonitor);
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java
index 70118f576..3a4305fcb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/RegionBasedHierarchyBuilder.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -16,7 +16,6 @@ import java.util.Iterator;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
@@ -47,17 +46,9 @@ public void build(boolean computeSubtypes) {
manager.cacheZipFiles(this);
if (this.hierarchy.focusType == null || computeSubtypes) {
- IProgressMonitor typeInRegionMonitor =
- this.hierarchy.progressMonitor == null ?
- null :
- new SubProgressMonitor(this.hierarchy.progressMonitor, 30);
- HashMap allOpenablesInRegion = determineOpenablesInRegion(typeInRegionMonitor);
+ HashMap allOpenablesInRegion = determineOpenablesInRegion(this.hierarchy.progressMonitor.split(30));
this.hierarchy.initialize(allOpenablesInRegion.size());
- IProgressMonitor buildMonitor =
- this.hierarchy.progressMonitor == null ?
- null :
- new SubProgressMonitor(this.hierarchy.progressMonitor, 70);
- createTypeHierarchyBasedOnRegion(allOpenablesInRegion, buildMonitor);
+ createTypeHierarchyBasedOnRegion(allOpenablesInRegion, this.hierarchy.progressMonitor.split(70));
((RegionBasedTypeHierarchy)this.hierarchy).pruneDeadBranches();
} else {
this.hierarchy.initialize(1);
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
index 0b100f673..42f1479de 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/hierarchy/TypeHierarchy.java
@@ -28,6 +28,7 @@ import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
@@ -92,7 +93,7 @@ public class TypeHierarchy implements ITypeHierarchy, IElementChangedListener {
/**
* The progress monitor to report work completed too.
*/
- protected IProgressMonitor progressMonitor = null;
+ protected SubMonitor progressMonitor = SubMonitor.convert(null);
/**
* Change listeners - null if no one is listening.
@@ -1253,14 +1254,11 @@ protected boolean packageRegionContainsSamePackageFragment(PackageFragment eleme
*/
public synchronized void refresh(IProgressMonitor monitor) throws JavaModelException {
try {
- this.progressMonitor = monitor;
- if (monitor != null) {
- monitor.beginTask(
- this.focusType != null ?
- Messages.bind(Messages.hierarchy_creatingOnType, this.focusType.getFullyQualifiedName()) :
- Messages.hierarchy_creating,
- 100);
- }
+ this.progressMonitor = SubMonitor.convert(monitor,
+ this.focusType != null ?
+ Messages.bind(Messages.hierarchy_creatingOnType, this.focusType.getFullyQualifiedName()) :
+ Messages.hierarchy_creating,
+ 100);
long start = -1;
if (DEBUG) {
start = System.currentTimeMillis();
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
index ceb402f1c..0303e70fe 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java
@@ -185,6 +185,7 @@ public final class Messages extends NLS {
public static String classpath_incompatibleLibraryJDKLevelInContainer;
public static String classpath_duplicateEntryExtraAttribute;
public static String classpath_deprecated_variable;
+ public static String classpath_invalidExternalAnnotationPath;
public static String file_notFound;
public static String file_badFormat;
public static String path_nullPath;
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
index bf3c64606..724696c15 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2000, 2014 IBM Corporation and others.
+# Copyright (c) 2000, 2015 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
@@ -181,6 +181,7 @@ classpath_incompatibleLibraryJDKLevel = Incompatible .class files version in req
classpath_incompatibleLibraryJDKLevelInContainer = Incompatible .class files version in required binaries. Project ''{0}'' is targeting a {1} runtime, but is compiled against ''{2}'' (from the {3}) which requires a {4} runtime
classpath_duplicateEntryExtraAttribute = Duplicate extra attribute: ''{0}'' in classpath entry ''{1}'' for project ''{2}''
classpath_deprecated_variable = Classpath variable ''{0}'' in project ''{1}'' is deprecated: {2}
+classpath_invalidExternalAnnotationPath = Invalid external annotation path: ''{0}'' in project ''{1}'', for classpath entry ''{2}''
### miscellaneous
buffer_closed=Buffer is closed
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
index e28b2d2c8..77c371e94 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/core/search/SearchEngine.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -435,6 +435,18 @@ public class SearchEngine {
}
/**
+ * Create a method name match on a given method with specific modifiers.
+ *
+ * @param method The Java model handle of the method
+ * @param modifiers Modifiers of the method
+ * @return A non-null match on the given method.
+ * @since 3.12
+ */
+ public static MethodNameMatch createMethodNameMatch(IMethod method, int modifiers) {
+ return BasicSearchEngine.createMethodNameMatch(method, modifiers);
+ }
+
+ /**
* Returns a Java search scope with the workspace as the only limit.
*
* @return a new workspace scope
@@ -586,7 +598,11 @@ public class SearchEngine {
/**
* Searches for all method declarations in the given scope. Accepted matches will be returned by
- * {@link MethodNameRequestor#acceptMethod}
+ * {@link MethodNameRequestor#acceptMethod}.
+ * <p>
+ * Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
+ * comment is removed.
+ * </p>
*
* @param packageName the full name of the package of the searched types, or a prefix for this
* package, or a wild-carded string for this package.
@@ -642,6 +658,11 @@ public class SearchEngine {
* <p>
* Provided {@link MethodNameMatchRequestor} requestor will collect the {@link MethodNameMatch}
* matches found during the search.
+
+ * </p>
+ * <p>
+ * Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
+ * comment is removed.
* </p>
*
* @param packageName the full name of the package of the searched types, or a prefix for this
@@ -694,6 +715,152 @@ public class SearchEngine {
}
/**
+ * Searches for all method declarations in the given scope. Accepted matches will be returned by
+ * {@link MethodNameRequestor#acceptMethod}.
+ * <p>
+ * Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
+ * comment is removed.
+ * </p>
+ *
+ * @param qualifier qualifier including package name and qualified type name
+ * May be <code>null</code>, then any qualifier name is accepted.
+ * @param qualifierMatchRule match rule for the qualifier and can be one of
+ * * <ul>
+ * <li>{@link SearchPattern#R_EXACT_MATCH} if the package name and type
+ * name are the full names of the types of the searched methods.</li>
+ * <li>{@link SearchPattern#R_PREFIX_MATCH} if the package name and type
+ * name are prefixes of the names of the types of searched methods.</li>
+ * <li>{@link SearchPattern#R_PATTERN_MATCH} if the package name and
+ * type name contain wild-cards.</li>
+ * <li>{@link SearchPattern#R_CAMELCASE_MATCH} if the package name and types are
+ * camel case of the package and type of searched methods.</li>
+ * <li>{@link SearchPattern#R_CAMELCASE_SAME_PART_COUNT_MATCH}
+ * if the package name and type names are camel case with same part count of the
+ * package and types of searched methods.</li>
+ * </ul>
+ * @param methodName the method name searched for.
+ * @param methodMatchRule match rule for the method name and can be one of
+ * <ul>
+ * <li>{@link SearchPattern#R_EXACT_MATCH} if the method name searched
+ * is exact.</li>
+ * <li>{@link SearchPattern#R_PREFIX_MATCH} if method
+ * name is prefix of the names of the searched methods.</li>
+ * <li>{@link SearchPattern#R_PATTERN_MATCH} if the method name
+ * contains wild-cards.</li>
+ * <li>{@link SearchPattern#R_CAMELCASE_MATCH} if the method name is a
+ * camel case of the searched method name.</li>
+ * <li>{@link SearchPattern#R_CAMELCASE_SAME_PART_COUNT_MATCH}
+ * if the method name is a camel case with same part count of the searched
+ * methods name.</li>
+ * </ul>
+ * @param scope the scope to search in
+ * @param nameRequestor the requestor that collects the results of the search.
+ * @param waitingPolicy one of
+ * <ul>
+ * <li>{@link IJavaSearchConstants#FORCE_IMMEDIATE_SEARCH} if the search should start immediately</li>
+ * <li>{@link IJavaSearchConstants#CANCEL_IF_NOT_READY_TO_SEARCH} if the search should be cancelled if the
+ * underlying indexer has not finished indexing the workspace</li>
+ * <li>{@link IJavaSearchConstants#WAIT_UNTIL_READY_TO_SEARCH} if the search should wait for the
+ * underlying indexer to finish indexing the workspace</li>
+ * </ul>
+ * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
+ * monitor is provided
+ * @exception JavaModelException if the search failed.
+ *
+ * @since 3.12
+ */
+ public void searchAllMethodNames(
+ final char[] qualifier,
+ final int qualifierMatchRule,
+ final char[] methodName,
+ final int methodMatchRule,
+ IJavaSearchScope scope,
+ final MethodNameRequestor nameRequestor,
+ int waitingPolicy,
+ IProgressMonitor progressMonitor) throws JavaModelException {
+ MethodNameRequestorWrapper requestorWrapper = new MethodNameRequestorWrapper(nameRequestor);
+ this.basicEngine.searchAllMethodNames(
+ qualifier, qualifierMatchRule,
+ methodName, methodMatchRule,
+ scope, requestorWrapper,
+ waitingPolicy, progressMonitor);
+ }
+
+ /**
+ * Searches for all method declarations in the given scope.
+ * <p>
+ * Provided {@link MethodNameMatchRequestor} requestor will collect the {@link MethodNameMatch}
+ * matches found during the search.
+ * </p>
+ * <p>
+ * Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
+ * comment is removed.
+ * </p>
+ *
+ * @param qualifier qualifier including package name and qualified type name
+ * May be <code>null</code>, then any qualifier name is accepted.
+ * @param qualifierMatchRule match rule for the qualifier and can be one of
+ * * <ul>
+ * <li>{@link SearchPattern#R_EXACT_MATCH} if the package name and type
+ * name are the full names of the types of the searched methods.</li>
+ * <li>{@link SearchPattern#R_PREFIX_MATCH} if the package name and type
+ * name are prefixes of the names of the types of searched methods.</li>
+ * <li>{@link SearchPattern#R_PATTERN_MATCH} if the package name and
+ * type name contain wild-cards.</li>
+ * <li>{@link SearchPattern#R_CAMELCASE_MATCH} if the package name and types are
+ * camel case of the package and type of searched methods.</li>
+ * <li>{@link SearchPattern#R_CAMELCASE_SAME_PART_COUNT_MATCH}
+ * if the package name and type names are camel case with same part count of the
+ * package and types of searched methods.</li>
+ * </ul>
+ * @param methodName the method name searched for.
+ * @param methodMatchRule match rule for the method name and can be one of
+ * <ul>
+ * <li>{@link SearchPattern#R_EXACT_MATCH} if the method name searched
+ * is exact.</li>
+ * <li>{@link SearchPattern#R_PREFIX_MATCH} if method
+ * name is prefix of the names of the searched methods.</li>
+ * <li>{@link SearchPattern#R_PATTERN_MATCH} if the method name
+ * contains wild-cards.</li>
+ * <li>{@link SearchPattern#R_CAMELCASE_MATCH} if the method name is a
+ * camel case of the searched method name.</li>
+ * <li>{@link SearchPattern#R_CAMELCASE_SAME_PART_COUNT_MATCH}
+ * if the method name is a camel case with same part count of the searched
+ * methods name.</li>
+ * </ul>
+ * @param scope the scope to search in
+ * @param nameRequestor the {@link MethodNameMatchRequestor}
+ * @param waitingPolicy one of
+ * <ul>
+ * <li>{@link IJavaSearchConstants#FORCE_IMMEDIATE_SEARCH} if the search should start immediately</li>
+ * <li>{@link IJavaSearchConstants#CANCEL_IF_NOT_READY_TO_SEARCH} if the search should be cancelled if the
+ * underlying indexer has not finished indexing the workspace</li>
+ * <li>{@link IJavaSearchConstants#WAIT_UNTIL_READY_TO_SEARCH} if the search should wait for the
+ * underlying indexer to finish indexing the workspace</li>
+ * </ul>
+ * @param progressMonitor the progress monitor to report progress to, or <code>null</code> if no progress
+ * monitor is provided
+ * @exception JavaModelException if the search failed.
+ *
+ * @since 3.12
+ */
+ public void searchAllMethodNames(
+ final char[] qualifier,
+ final int qualifierMatchRule,
+ final char[] methodName,
+ final int methodMatchRule,
+ IJavaSearchScope scope,
+ final MethodNameMatchRequestor nameRequestor,
+ int waitingPolicy,
+ IProgressMonitor progressMonitor) throws JavaModelException {
+ MethodNameMatchRequestorWrapper requestorWrapper = new MethodNameMatchRequestorWrapper(nameRequestor, scope);
+ this.basicEngine.searchAllMethodNames(
+ qualifier, qualifierMatchRule,
+ methodName, methodMatchRule,
+ scope, requestorWrapper,
+ waitingPolicy, progressMonitor);
+ }
+ /**
* Searches for all top-level types and member types in the given scope.
* The search can be selecting specific types (given a package exact full name or
* a type name with specific match mode).
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
index 82039f215..989136b65 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/index/DiskIndex.java
@@ -49,9 +49,9 @@ char separator = Index.DEFAULT_SEPARATOR;
//{ObjectTeams: add a suffix for distinction:
/* orig:
-public static final String SIGNATURE= "INDEX VERSION 1.128"; //$NON-NLS-1$
+public static final String SIGNATURE= "INDEX VERSION 1.129"; //$NON-NLS-1$
:giro */
-public static final String SIGNATURE= "INDEX VERSION 1.128 OT2"; //$NON-NLS-1$
+public static final String SIGNATURE= "INDEX VERSION 1.129 OT2"; //$NON-NLS-1$
// SH}
private static final char[] SIGNATURE_CHARS = SIGNATURE.toCharArray();
public static boolean DEBUG = false;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
index fc154da0c..7f1f16db4 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/BasicSearchEngine.java
@@ -173,6 +173,13 @@ public class BasicSearchEngine {
}
/**
+ * @see SearchEngine#createMethodNameMatch(IMethod, int) for detailed comment.
+ */
+ public static MethodNameMatch createMethodNameMatch(IMethod method, int modifiers) {
+ return new JavaSearchMethodNameMatch(method, modifiers);
+ }
+
+ /**
* @see SearchEngine#createWorkspaceScope() for detailed comment.
*/
public static IJavaSearchScope createWorkspaceScope() {
@@ -188,7 +195,6 @@ public class BasicSearchEngine {
* @param requestor a callback object to which each match is reported
*/
void findMatches(SearchPattern pattern, SearchParticipant[] participants, IJavaSearchScope scope, SearchRequestor requestor, IProgressMonitor monitor) throws CoreException {
- if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
try {
if (VERBOSE) {
Util.verbose("Searching for pattern: " + pattern.toString()); //$NON-NLS-1$
@@ -201,27 +207,25 @@ public class BasicSearchEngine {
/* initialize progress monitor */
int length = participants.length;
- if (monitor != null)
- monitor.beginTask(Messages.engine_searching, 100 * length);
+ SubMonitor loopMonitor = SubMonitor.convert(monitor, Messages.engine_searching, length);
IndexManager indexManager = JavaModelManager.getIndexManager();
requestor.beginReporting();
for (int i = 0; i < length; i++) {
- if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
+ SubMonitor iterationMonitor = loopMonitor.split(1).setWorkRemaining(100);
SearchParticipant participant = participants[i];
try {
- if (monitor != null) monitor.subTask(Messages.bind(Messages.engine_searching_indexing, new String[] {participant.getDescription()}));
+ iterationMonitor.subTask(Messages.bind(Messages.engine_searching_indexing, new String[] {participant.getDescription()}));
participant.beginSearching();
requestor.enterParticipant(participant);
PathCollector pathCollector = new PathCollector();
indexManager.performConcurrentJob(
new PatternSearchJob(pattern, participant, scope, pathCollector),
IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
- monitor==null ? null : new SubProgressMonitor(monitor, 50));
- if (monitor != null && monitor.isCanceled()) throw new OperationCanceledException();
+ iterationMonitor.split(50));
// locate index matches if any (note that all search matches could have been issued during index querying)
- if (monitor != null) monitor.subTask(Messages.bind(Messages.engine_searching_matching, new String[] {participant.getDescription()}));
+ iterationMonitor.subTask(Messages.bind(Messages.engine_searching_matching, new String[] {participant.getDescription()}));
String[] indexMatchPaths = pathCollector.getPaths();
if (indexMatchPaths != null) {
pathCollector = null; // release
@@ -231,7 +235,7 @@ public class BasicSearchEngine {
indexMatches[j] = participant.getDocument(indexMatchPaths[j]);
}
SearchDocument[] matches = MatchLocator.addWorkingCopies(pattern, indexMatches, getWorkingCopies(), participant);
- participant.locateMatches(matches, pattern, scope, requestor, monitor==null ? null : new SubProgressMonitor(monitor, 50));
+ participant.locateMatches(matches, pattern, scope, requestor, iterationMonitor.split(50));
}
} finally {
requestor.exitParticipant(participant);
@@ -240,8 +244,6 @@ public class BasicSearchEngine {
}
} finally {
requestor.endReporting();
- if (monitor != null)
- monitor.done();
}
}
/**
@@ -549,6 +551,22 @@ boolean match(char[] patternName, int matchRule, char[] name) {
}
+ boolean match(char[] patternFusedQualifier, int matchRuleFusedQualifier,
+ char[] patternMethodName, int methodMatchRule,
+ char[] packageName, char[] declaringQualifier, char[] declaringSimpleName, char[] methodName) {
+
+ char[] q = packageName != null ? packageName : CharOperation.NO_CHAR;
+ if (declaringQualifier != null && declaringQualifier.length > 0) {
+ q = q.length > 0 ? CharOperation.concat(q, declaringQualifier, '.') : declaringQualifier;
+ }
+ if (declaringSimpleName != null && declaringSimpleName.length > 0) {
+ q = q.length > 0 ? CharOperation.concat(q, declaringSimpleName, '.') : declaringSimpleName;
+ }
+
+ return match(patternFusedQualifier, matchRuleFusedQualifier, q) &&
+ match(patternMethodName, methodMatchRule, methodName);
+
+ }
/**
* Searches for matches of a given search pattern. Search patterns can be created using helper
* methods (from a String pattern or a Java element) and encapsulate the description of what is
@@ -682,10 +700,347 @@ boolean match(char[] patternName, int matchRule, char[] name) {
}
};
- try {
- if (progressMonitor != null) {
- progressMonitor.beginTask(Messages.engine_searching, 1000);
+ SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
+ // add type names from indexes
+ indexManager.performConcurrentJob(
+ new PatternSearchJob(
+ pattern,
+ getDefaultSearchParticipant(), // Java search only
+ scope,
+ searchRequestor),
+ waitingPolicy,
+ subMonitor.split(Math.max(1000-copiesLength, 0)));
+
+ // add type names from working copies
+ if (copies != null) {
+ for (int i = 0; i < copiesLength; i++) {
+ SubMonitor iterationMonitor = subMonitor.split(1);
+ final ICompilationUnit workingCopy = copies[i];
+ if (scope instanceof HierarchyScope) {
+ if (!((HierarchyScope)scope).encloses(workingCopy, iterationMonitor)) continue;
+ } else {
+ if (!scope.encloses(workingCopy)) continue;
+ }
+
+ final String path = workingCopy.getPath().toString();
+ if (workingCopy.isConsistent()) {
+ IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
+ char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
+ IType[] allTypes = workingCopy.getAllTypes();
+ for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
+ IType type = allTypes[j];
+ char[] simpleName = type.getElementName().toCharArray();
+ if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, simpleName) && !type.isMember()) {
+
+ int extraFlags = ExtraFlags.getExtraFlags(type);
+
+ boolean hasConstructor = false;
+
+ IMethod[] methods = type.getMethods();
+ for (int k = 0; k < methods.length; k++) {
+ IMethod method = methods[k];
+ if (method.isConstructor()) {
+ hasConstructor = true;
+
+ String[] stringParameterNames = method.getParameterNames();
+ String[] stringParameterTypes = method.getParameterTypes();
+ int length = stringParameterNames.length;
+ char[][] parameterNames = new char[length][];
+ char[][] parameterTypes = new char[length][];
+ for (int l = 0; l < length; l++) {
+ parameterNames[l] = stringParameterNames[l].toCharArray();
+ parameterTypes[l] = Signature.toCharArray(Signature.getTypeErasure(stringParameterTypes[l]).toCharArray());
+ }
+
+ nameRequestor.acceptConstructor(
+ method.getFlags(),
+ simpleName,
+ parameterNames.length,
+ null,// signature is not used for source type
+ parameterTypes,
+ parameterNames,
+ type.getFlags(),
+ packageDeclaration,
+ extraFlags,
+ path,
+ null);
+ }
+ }
+
+ if (!hasConstructor) {
+ nameRequestor.acceptConstructor(
+ Flags.AccPublic,
+ simpleName,
+ -1,
+ null, // signature is not used for source type
+ CharOperation.NO_CHAR_CHAR,
+ CharOperation.NO_CHAR_CHAR,
+ type.getFlags(),
+ packageDeclaration,
+ extraFlags,
+ path,
+ null);
+ }
+ }
+ }
+ } else {
+ Parser basicParser = getParser();
+ org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
+ CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
+ CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
+ if (parsedUnit != null) {
+ final char[] packageDeclaration = parsedUnit.currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
+ class AllConstructorDeclarationsVisitor extends ASTVisitor {
+ private TypeDeclaration[] declaringTypes = new TypeDeclaration[0];
+ private int declaringTypesPtr = -1;
+
+ private void endVisit(TypeDeclaration typeDeclaration) {
+ if (!hasConstructor(typeDeclaration) && typeDeclaration.enclosingType == null) {
+
+ if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, typeDeclaration.name)) {
+ nameRequestor.acceptConstructor(
+ Flags.AccPublic,
+ typeName,
+ -1,
+ null, // signature is not used for source type
+ CharOperation.NO_CHAR_CHAR,
+ CharOperation.NO_CHAR_CHAR,
+ typeDeclaration.modifiers,
+ packageDeclaration,
+ ExtraFlags.getExtraFlags(typeDeclaration),
+ path,
+ null);
+ }
+ }
+
+ this.declaringTypes[this.declaringTypesPtr] = null;
+ this.declaringTypesPtr--;
+ }
+
+ public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
+ endVisit(typeDeclaration);
+ }
+
+ public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
+ endVisit(memberTypeDeclaration);
+ }
+
+ private boolean hasConstructor(TypeDeclaration typeDeclaration) {
+ AbstractMethodDeclaration[] methods = typeDeclaration.methods;
+ int length = methods == null ? 0 : methods.length;
+ for (int j = 0; j < length; j++) {
+ if (methods[j].isConstructor()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope classScope) {
+ TypeDeclaration typeDeclaration = this.declaringTypes[this.declaringTypesPtr];
+ if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, typeDeclaration.name)) {
+ Argument[] arguments = constructorDeclaration.arguments;
+ int length = arguments == null ? 0 : arguments.length;
+ char[][] parameterNames = new char[length][];
+ char[][] parameterTypes = new char[length][];
+ for (int l = 0; l < length; l++) {
+ Argument argument = arguments[l];
+ parameterNames[l] = argument.name;
+ if (argument.type instanceof SingleTypeReference) {
+ parameterTypes[l] = ((SingleTypeReference)argument.type).token;
+//{ObjectTeams: one more kind of type reference: (note that TypeAnchorReference cannot occur as an argument type)
+ } else if (argument.type instanceof LiftingTypeReference) {
+ parameterTypes[l] = CharOperation.concatWith(((LiftingTypeReference)argument.type).baseTokens, '.');
+//SH}
+ } else {
+ parameterTypes[l] = CharOperation.concatWith(((QualifiedTypeReference)argument.type).tokens, '.');
+ }
+ }
+
+ TypeDeclaration enclosing = typeDeclaration.enclosingType;
+ char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+ while (enclosing != null) {
+ enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
+ if ((enclosing.bits & ASTNode.IsMemberType) != 0) {
+ enclosing = enclosing.enclosingType;
+ } else {
+ enclosing = null;
+ }
+ }
+
+ nameRequestor.acceptConstructor(
+ constructorDeclaration.modifiers,
+ typeName,
+ parameterNames.length,
+ null, // signature is not used for source type
+ parameterTypes,
+ parameterNames,
+ typeDeclaration.modifiers,
+ packageDeclaration,
+ ExtraFlags.getExtraFlags(typeDeclaration),
+ path,
+ null);
+ }
+ return false; // no need to find constructors from local/anonymous type
+ }
+ public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
+ return false;
+ }
+
+ private boolean visit(TypeDeclaration typeDeclaration) {
+ if(this.declaringTypes.length <= ++this.declaringTypesPtr) {
+ int length = this.declaringTypesPtr;
+ System.arraycopy(this.declaringTypes, 0, this.declaringTypes = new TypeDeclaration[length * 2 + 1], 0, length);
+ }
+ this.declaringTypes[this.declaringTypesPtr] = typeDeclaration;
+ return true;
+ }
+
+ public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
+ return visit(typeDeclaration);
+ }
+
+ public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
+ return visit(memberTypeDeclaration);
+ }
+ }
+ parsedUnit.traverse(new AllConstructorDeclarationsVisitor(), parsedUnit.scope);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Searches for all method declarations in the given scope.
+ * * <p>
+ * Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
+ * comment is removed.
+ * </p>
+ *
+ * @see SearchEngine#searchAllMethodNames(char[], int, char[], int, IJavaSearchScope, MethodNameMatchRequestor, int, IProgressMonitor)
+ * for detailed comments
+ */
+ public void searchAllMethodNames(
+ final char[] qualifier,
+ final int qualifierMatchRule,
+ final char[] methodName,
+ final int methodMatchRule,
+ IJavaSearchScope scope,
+ final IRestrictedAccessMethodRequestor nameRequestor,
+ int waitingPolicy,
+ IProgressMonitor progressMonitor) throws JavaModelException {
+
+ // Validate match rule first
+ final int validatedMethodMatchRule = SearchPattern.validateMatchRule(methodName == null ? null : new String (methodName), methodMatchRule);
+ // Debug
+ if (VERBOSE) {
+ Util.verbose("BasicSearchEngine.searchAllMethodDeclarations(char[] qualifier, "//$NON-NLS-1$
+ + "char[] methodName, int methodMatchRule, IJavaSearchScope, IRestrictedAccessConstructorRequestor, int waitingPolicy, IProgressMonitor)"); //$NON-NLS-1$
+ Util.verbose(" - qualifier name: "+(qualifier==null?"null":new String(qualifier))); //$NON-NLS-1$ //$NON-NLS-2$
+ Util.verbose(" - method name: "+(methodName==null?"null":new String(methodName))); //$NON-NLS-1$ //$NON-NLS-2$
+ Util.verbose(" - method match rule: "+getMatchRuleString(methodMatchRule)); //$NON-NLS-1$
+ if (validatedMethodMatchRule != methodMatchRule) {
+ Util.verbose(" - validated method match rule: "+getMatchRuleString(validatedMethodMatchRule)); //$NON-NLS-1$
+ }
+ Util.verbose(" - scope: "+scope); //$NON-NLS-1$
+ }
+ if (validatedMethodMatchRule == -1) return; // invalid match rule => return no results
+
+ // Create pattern
+ IndexManager indexManager = JavaModelManager.getIndexManager();
+ final MethodDeclarationPattern pattern = new MethodDeclarationPattern(qualifier, methodName, methodMatchRule);
+
+ // Get working copy path(s). Store in a single string in case of only one to optimize comparison in requestor
+ final HashSet workingCopyPaths = new HashSet();
+ String workingCopyPath = null;
+ ICompilationUnit[] copies = getWorkingCopies();
+ final int copiesLength = copies == null ? 0 : copies.length;
+ if (copies != null) {
+ if (copiesLength == 1) {
+ workingCopyPath = copies[0].getPath().toString();
+ } else {
+ for (int i = 0; i < copiesLength; i++) {
+ ICompilationUnit workingCopy = copies[i];
+ workingCopyPaths.add(workingCopy.getPath().toString());
+ }
+ }
}
+ final String singleWkcpPath = workingCopyPath;
+
+ // Index requestor
+ IndexQueryRequestor searchRequestor = new IndexQueryRequestor(){
+ public boolean acceptIndexMatch(String documentPath, SearchPattern indexRecord, SearchParticipant participant, AccessRuleSet access) {
+ MethodDeclarationPattern record = (MethodDeclarationPattern)indexRecord;
+
+ if ((record.extraFlags & ExtraFlags.IsLocalType) != 0) {
+ return true; // filter out local and anonymous classes
+ }
+ switch (copiesLength) {
+ case 0:
+ break;
+ case 1:
+ if (singleWkcpPath.equals(documentPath)) {
+ return true; // filter out *the* working copy
+ }
+ break;
+ default:
+ if (workingCopyPaths.contains(documentPath)) {
+ return true; // filter out working copies
+ }
+ break;
+ }
+
+ // Accept document path
+ AccessRestriction accessRestriction = null;
+ if (access != null) {
+ // Compute document relative path
+ int pkgLength = (record.declaringPackageName==null || record.declaringPackageName.length==0) ? 0 : record.declaringPackageName.length+1;
+ int qualificationLength = (record.declaringQualification == null || record.declaringQualification.length == 0) ? 0 : record.declaringQualification.length;
+ int nameLength = record.declaringSimpleName==null ? 0 : record.declaringSimpleName.length;
+ char[] path = new char[pkgLength + qualificationLength + nameLength];
+ int pos = 0;
+ if (pkgLength > 0) {
+ System.arraycopy(record.declaringPackageName, 0, path, pos, pkgLength-1);
+ CharOperation.replace(path, '.', '/');
+ path[pkgLength-1] = '/';
+ pos += pkgLength;
+ }
+ if (qualificationLength > 0) {
+ System.arraycopy(record.declaringQualification, 0, path, pos, qualificationLength);
+ }
+ if (nameLength > 0) {
+ System.arraycopy(record.declaringSimpleName, 0, path, pos, nameLength);
+ pos += nameLength;
+ }
+ // Update access restriction if path is not empty
+ if (pos > 0) {
+ accessRestriction = access.getViolatedRestriction(path);
+ }
+ }
+ if (match(qualifier, qualifierMatchRule, methodName, methodMatchRule,
+ record.declaringPackageName, record.declaringQualification, record.declaringSimpleName, record.selector)) {
+ nameRequestor.acceptMethod(
+ record.selector,
+ record.parameterCount,
+ record.declaringQualification,
+ record.declaringSimpleName,
+ record.declaringTypeModifiers,
+ record.declaringPackageName,
+ record.signature,
+ record.parameterTypes,
+ record.parameterNames,
+ record.returnSimpleName,
+ record.modifiers,
+ documentPath,
+ accessRestriction,
+ -1 /* method index not applicable as there is no IType here */);
+ }
+ return true;
+ }
+ };
+
+ SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
// add type names from indexes
indexManager.performConcurrentJob(
new PatternSearchJob(
@@ -694,78 +1049,35 @@ boolean match(char[] patternName, int matchRule, char[] name) {
scope,
searchRequestor),
waitingPolicy,
- progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 1000-copiesLength));
+ subMonitor.split(Math.max(1000-copiesLength, 0)));
// add type names from working copies
if (copies != null) {
for (int i = 0; i < copiesLength; i++) {
+ SubMonitor iterationMonitor = subMonitor.split(1);
final ICompilationUnit workingCopy = copies[i];
if (scope instanceof HierarchyScope) {
- if (!((HierarchyScope)scope).encloses(workingCopy, progressMonitor)) continue;
+ if (!((HierarchyScope)scope).encloses(workingCopy, iterationMonitor)) continue;
} else {
if (!scope.encloses(workingCopy)) continue;
}
-
+
final String path = workingCopy.getPath().toString();
if (workingCopy.isConsistent()) {
IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
+
IType[] allTypes = workingCopy.getAllTypes();
for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
IType type = allTypes[j];
- char[] simpleName = type.getElementName().toCharArray();
- if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, simpleName) && !type.isMember()) {
-
- int extraFlags = ExtraFlags.getExtraFlags(type);
-
- boolean hasConstructor = false;
-
- IMethod[] methods = type.getMethods();
- for (int k = 0; k < methods.length; k++) {
- IMethod method = methods[k];
- if (method.isConstructor()) {
- hasConstructor = true;
-
- String[] stringParameterNames = method.getParameterNames();
- String[] stringParameterTypes = method.getParameterTypes();
- int length = stringParameterNames.length;
- char[][] parameterNames = new char[length][];
- char[][] parameterTypes = new char[length][];
- for (int l = 0; l < length; l++) {
- parameterNames[l] = stringParameterNames[l].toCharArray();
- parameterTypes[l] = Signature.toCharArray(Signature.getTypeErasure(stringParameterTypes[l]).toCharArray());
- }
-
- nameRequestor.acceptConstructor(
- method.getFlags(),
- simpleName,
- parameterNames.length,
- null,// signature is not used for source type
- parameterTypes,
- parameterNames,
- type.getFlags(),
- packageDeclaration,
- extraFlags,
- path,
- null);
- }
- }
-
- if (!hasConstructor) {
- nameRequestor.acceptConstructor(
- Flags.AccPublic,
- simpleName,
- -1,
- null, // signature is not used for source type
- CharOperation.NO_CHAR_CHAR,
- CharOperation.NO_CHAR_CHAR,
- type.getFlags(),
- packageDeclaration,
- extraFlags,
- path,
- null);
- }
- }
+ IJavaElement parent = type.getParent();
+ char[] rDeclaringQualification = parent instanceof IType ? ((IType) parent).getTypeQualifiedName('.').toCharArray() : CharOperation.NO_CHAR;
+ char[] rSimpleName = type.getElementName().toCharArray();
+ char[] q = CharOperation.concatNonEmpty(packageDeclaration, '.', rDeclaringQualification, '.', rSimpleName);
+ if (!match(qualifier, qualifierMatchRule, q))
+ continue;
+ reportMatchingMethods(methodName, methodMatchRule, nameRequestor, path,
+ packageDeclaration, type, rDeclaringQualification, rSimpleName);
}
} else {
Parser basicParser = getParser();
@@ -774,136 +1086,98 @@ boolean match(char[] patternName, int matchRule, char[] name) {
CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
if (parsedUnit != null) {
final char[] packageDeclaration = parsedUnit.currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
- class AllConstructorDeclarationsVisitor extends ASTVisitor {
- private TypeDeclaration[] declaringTypes = new TypeDeclaration[0];
- private int declaringTypesPtr = -1;
-
- private void endVisit(TypeDeclaration typeDeclaration) {
- if (!hasConstructor(typeDeclaration) && typeDeclaration.enclosingType == null) {
+ class AllMethodDeclarationVisitor extends ASTVisitor {
+
+ class TypeInfo {
+ public TypeDeclaration typeDecl;
+ public IType type;
+ public boolean visitMethods;
+ public char[] enclosingTypeName;
- if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, typeDeclaration.name)) {
- nameRequestor.acceptConstructor(
- Flags.AccPublic,
- typeName,
- -1,
- null, // signature is not used for source type
- CharOperation.NO_CHAR_CHAR,
- CharOperation.NO_CHAR_CHAR,
- typeDeclaration.modifiers,
- packageDeclaration,
- ExtraFlags.getExtraFlags(typeDeclaration),
- path,
- null);
+ TypeInfo(TypeDeclaration typeDecl, boolean visitMethods, char[] enclosingTypeName) {
+ this.typeDecl = typeDecl;
+ this.type = workingCopy.getType(new String(typeDecl.name));
+ this.visitMethods = visitMethods;
+ this.enclosingTypeName = enclosingTypeName;
+ }
+ }
+ Stack<TypeInfo> typeInfoStack = new Stack<>();
+ IType getCurrentType() {
+ int l = this.typeInfoStack.size();
+ if (l <= 0) return null;
+ TypeInfo typeInfo = this.typeInfoStack.get(0);
+ IType type = typeInfo.type;
+ if (type == null) {
+ TypeInfo ti = this.typeInfoStack.get(0);
+ ti.type = ti.type == null ? workingCopy.getType(new String(ti.typeDecl.name)) : ti.type;
+ type = ti.type;
+ for (int j = 1; j < l && type != null; ++j) {
+ ti = this.typeInfoStack.get(j);
+ if (ti.type == null) {
+ ti.type = type.getType(new String(ti.typeDecl.name));
+ }
+ type = ti.type;
}
}
-
- this.declaringTypes[this.declaringTypesPtr] = null;
- this.declaringTypesPtr--;
+ return type;
+ }
+
+ private void addStackEntry(TypeDeclaration typeDeclaration, char[] enclosingTypeName) {
+ char[] q = CharOperation.concatNonEmpty(packageDeclaration, '.', enclosingTypeName, '.', typeDeclaration.name);
+ boolean visitMethods = match(qualifier, qualifierMatchRule, q);
+ this.typeInfoStack.push(new TypeInfo(typeDeclaration, visitMethods, enclosingTypeName));
}
-
public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
- endVisit(typeDeclaration);
+ this.typeInfoStack.pop();
}
-
public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
- endVisit(memberTypeDeclaration);
+ this.typeInfoStack.pop();
}
-
- private boolean hasConstructor(TypeDeclaration typeDeclaration) {
- AbstractMethodDeclaration[] methods = typeDeclaration.methods;
- int length = methods == null ? 0 : methods.length;
- for (int j = 0; j < length; j++) {
- if (methods[j].isConstructor()) {
- return true;
- }
+ public boolean visit(MethodDeclaration methodDeclaration, ClassScope classScope) {
+ TypeInfo typeInfo = this.typeInfoStack.peek();
+ if (typeInfo.visitMethods &&
+ match(methodName, methodMatchRule, methodDeclaration.selector)) {
+ reportMatchingMethod(path, packageDeclaration,
+ typeInfo.enclosingTypeName,
+ typeInfo.typeDecl,
+ methodDeclaration,
+ getCurrentType(),
+ nameRequestor);
}
- return false;
- }
- public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope classScope) {
- TypeDeclaration typeDeclaration = this.declaringTypes[this.declaringTypesPtr];
- if (match(NoSuffix, packageName, pkgMatchRule, typeName, validatedTypeMatchRule, 0/*no kind*/, packageDeclaration, typeDeclaration.name)) {
- Argument[] arguments = constructorDeclaration.arguments;
- int length = arguments == null ? 0 : arguments.length;
- char[][] parameterNames = new char[length][];
- char[][] parameterTypes = new char[length][];
- for (int l = 0; l < length; l++) {
- Argument argument = arguments[l];
- parameterNames[l] = argument.name;
- if (argument.type instanceof SingleTypeReference) {
- parameterTypes[l] = ((SingleTypeReference)argument.type).token;
-//{ObjectTeams: one more kind of type reference: (note that TypeAnchorReference cannot occur as an argument type)
- } else if (argument.type instanceof LiftingTypeReference) {
- parameterTypes[l] = CharOperation.concatWith(((LiftingTypeReference)argument.type).baseTokens, '.');
-// SH}
- } else {
- parameterTypes[l] = CharOperation.concatWith(((QualifiedTypeReference)argument.type).tokens, '.');
- }
- }
-
- TypeDeclaration enclosing = typeDeclaration.enclosingType;
- char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
- while (enclosing != null) {
- enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
- if ((enclosing.bits & ASTNode.IsMemberType) != 0) {
- enclosing = enclosing.enclosingType;
- } else {
- enclosing = null;
- }
- }
-
- nameRequestor.acceptConstructor(
- constructorDeclaration.modifiers,
- typeName,
- parameterNames.length,
- null, // signature is not used for source type
- parameterTypes,
- parameterNames,
- typeDeclaration.modifiers,
- packageDeclaration,
- ExtraFlags.getExtraFlags(typeDeclaration),
- path,
- null);
- }
- return false; // no need to find constructors from local/anonymous type
+ return false; // no need to find methods from local/anonymous type
}
public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
- return false;
+ return false; // do not visit local/anonymous types
}
-
- private boolean visit(TypeDeclaration typeDeclaration) {
- if(this.declaringTypes.length <= ++this.declaringTypesPtr) {
- int length = this.declaringTypesPtr;
- System.arraycopy(this.declaringTypes, 0, this.declaringTypes = new TypeDeclaration[length * 2 + 1], 0, length);
- }
- this.declaringTypes[this.declaringTypesPtr] = typeDeclaration;
- return true;
- }
-
public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
- return visit(typeDeclaration);
+ addStackEntry(typeDeclaration, CharOperation.NO_CHAR);
+ return true;
}
-
public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
- return visit(memberTypeDeclaration);
+ TypeInfo typeInfo = this.typeInfoStack.peek();
+ addStackEntry(memberTypeDeclaration, typeInfo.enclosingTypeName == CharOperation.NO_CHAR ? typeInfo.typeDecl.name :
+ CharOperation.concat(typeInfo.enclosingTypeName, typeInfo.typeDecl.name, '.'));
+ return true;
}
}
- parsedUnit.traverse(new AllConstructorDeclarationsVisitor(), parsedUnit.scope);
+ parsedUnit.traverse(new AllMethodDeclarationVisitor(), parsedUnit.scope);
}
}
- if (progressMonitor != null) {
- if (progressMonitor.isCanceled()) throw new OperationCanceledException();
- progressMonitor.worked(1);
- }
}
}
- } finally {
- if (progressMonitor != null) {
- progressMonitor.done();
- }
}
- }
+ /**
+ * Searches for all method declarations in the given scope.
+ * * <p>
+ * Warning: This API is in experimental phase and may be modified/removed. Do not use this until this
+ * comment is removed.
+ * </p>
+ *
+ * @see SearchEngine#searchAllMethodNames(char[], int, char[], int, char[], int, char[], int, IJavaSearchScope, MethodNameMatchRequestor, int, IProgressMonitor)
+ * for detailed comments
+ */
public void searchAllMethodNames(
final char[] packageName,
final int pkgMatchRule,
@@ -1029,146 +1303,135 @@ boolean match(char[] patternName, int matchRule, char[] name) {
}
};
- try {
- if (progressMonitor != null) {
- progressMonitor.beginTask(Messages.engine_searching, 1000);
- }
- // add type names from indexes
- indexManager.performConcurrentJob(
- new PatternSearchJob(
- pattern,
- getDefaultSearchParticipant(), // Java search only
- scope,
- searchRequestor),
- waitingPolicy,
- progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 1000-copiesLength));
+ SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
+ // add type names from indexes
+ indexManager.performConcurrentJob(
+ new PatternSearchJob(
+ pattern,
+ getDefaultSearchParticipant(), // Java search only
+ scope,
+ searchRequestor),
+ waitingPolicy,
+ subMonitor.split(Math.max(1000-copiesLength, 0)));
- // add type names from working copies
- if (copies != null) {
- boolean isPkgCaseSensitive = (pkgMatchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
- for (int i = 0; i < copiesLength; i++) {
- final ICompilationUnit workingCopy = copies[i];
- if (scope instanceof HierarchyScope) {
- if (!((HierarchyScope)scope).encloses(workingCopy, progressMonitor)) continue;
- } else {
- if (!scope.encloses(workingCopy)) continue;
- }
+ // add type names from working copies
+ if (copies != null) {
+ boolean isPkgCaseSensitive = (pkgMatchRule & SearchPattern.R_CASE_SENSITIVE) != 0;
+ for (int i = 0; i < copiesLength; i++) {
+ SubMonitor iterationMonitor = subMonitor.split(1);
+ final ICompilationUnit workingCopy = copies[i];
+ if (scope instanceof HierarchyScope) {
+ if (!((HierarchyScope)scope).encloses(workingCopy, iterationMonitor)) continue;
+ } else {
+ if (!scope.encloses(workingCopy)) continue;
+ }
- final String path = workingCopy.getPath().toString();
- if (workingCopy.isConsistent()) {
- IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
- char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
- if (packageName != null && !CharOperation.equals(packageName, packageDeclaration, isPkgCaseSensitive))
+ final String path = workingCopy.getPath().toString();
+ if (workingCopy.isConsistent()) {
+ IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
+ char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
+ if (packageName != null && !CharOperation.equals(packageName, packageDeclaration, isPkgCaseSensitive))
+ continue;
+
+ IType[] allTypes = workingCopy.getAllTypes();
+ for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
+ IType type = allTypes[j];
+ IJavaElement parent = type.getParent();
+ char[] rDeclaringQualification = parent instanceof IType ? ((IType) parent).getTypeQualifiedName('.').toCharArray() : CharOperation.NO_CHAR;
+ char[] rSimpleName = type.getElementName().toCharArray();
+ if (!match(declaringQualification, declQualificationMatchRule, rDeclaringQualification) ||
+ !match(declaringSimpleName, declSimpleNameMatchRule, rSimpleName))
continue;
-
- IType[] allTypes = workingCopy.getAllTypes();
- for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
- IType type = allTypes[j];
- IJavaElement parent = type.getParent();
- char[] rDeclaringQualification = parent instanceof IType ? ((IType) parent).getTypeQualifiedName('.').toCharArray() : CharOperation.NO_CHAR;
- char[] rSimpleName = type.getElementName().toCharArray();
- if (!match(declaringQualification, declQualificationMatchRule, rDeclaringQualification) ||
- !match(declaringSimpleName, declSimpleNameMatchRule, rSimpleName))
- continue;
- reportMatchingMethods(methodName, methodMatchRule, nameRequestor, path,
- packageDeclaration, type, rDeclaringQualification, rSimpleName);
- }
- } else {
- Parser basicParser = getParser();
- org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
- CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
- CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
- if (parsedUnit != null) {
- final char[] packageDeclaration = parsedUnit.currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
- class AllMethodDeclarationVisitor extends ASTVisitor {
-
- class TypeInfo {
- public TypeDeclaration typeDecl;
- public IType type;
- public boolean visitMethods;
- public char[] enclosingTypeName;
-
- TypeInfo(TypeDeclaration typeDecl, boolean visitMethods, char[] enclosingTypeName) {
- this.typeDecl = typeDecl;
- this.type = workingCopy.getType(new String(typeDecl.name));
- this.visitMethods = visitMethods;
- this.enclosingTypeName = enclosingTypeName;
- }
+ reportMatchingMethods(methodName, methodMatchRule, nameRequestor, path,
+ packageDeclaration, type, rDeclaringQualification, rSimpleName);
+ }
+ } else {
+ Parser basicParser = getParser();
+ org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
+ CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
+ CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
+ if (parsedUnit != null) {
+ final char[] packageDeclaration = parsedUnit.currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
+ class AllMethodDeclarationVisitor extends ASTVisitor {
+
+ class TypeInfo {
+ public TypeDeclaration typeDecl;
+ public IType type;
+ public boolean visitMethods;
+ public char[] enclosingTypeName;
+
+ TypeInfo(TypeDeclaration typeDecl, boolean visitMethods, char[] enclosingTypeName) {
+ this.typeDecl = typeDecl;
+ this.type = workingCopy.getType(new String(typeDecl.name));
+ this.visitMethods = visitMethods;
+ this.enclosingTypeName = enclosingTypeName;
}
- Stack<TypeInfo> typeInfoStack = new Stack<>();
- IType getCurrentType() {
- int l = this.typeInfoStack.size();
- if (l <= 0) return null;
- TypeInfo typeInfo = this.typeInfoStack.get(0);
- IType type = typeInfo.type;
- if (type == null) {
- TypeInfo ti = this.typeInfoStack.get(0);
- ti.type = ti.type == null ? workingCopy.getType(new String(ti.typeDecl.name)) : ti.type;
- type = ti.type;
- for (int j = 1; j < l && type != null; ++j) {
- ti = this.typeInfoStack.get(j);
- if (ti.type == null) {
- ti.type = type.getType(new String(ti.typeDecl.name));
- }
- type = ti.type;
+ }
+ Stack<TypeInfo> typeInfoStack = new Stack<>();
+ IType getCurrentType() {
+ int l = this.typeInfoStack.size();
+ if (l <= 0) return null;
+ TypeInfo typeInfo = this.typeInfoStack.get(0);
+ IType type = typeInfo.type;
+ if (type == null) {
+ TypeInfo ti = this.typeInfoStack.get(0);
+ ti.type = ti.type == null ? workingCopy.getType(new String(ti.typeDecl.name)) : ti.type;
+ type = ti.type;
+ for (int j = 1; j < l && type != null; ++j) {
+ ti = this.typeInfoStack.get(j);
+ if (ti.type == null) {
+ ti.type = type.getType(new String(ti.typeDecl.name));
}
+ type = ti.type;
}
- return type;
}
+ return type;
+ }
- private void addStackEntry(TypeDeclaration typeDeclaration, char[] enclosingTypeName) {
- boolean visitMethods = match(declaringQualification, declQualificationMatchRule, enclosingTypeName) &&
- match(declaringSimpleName, declSimpleNameMatchRule, typeDeclaration.name);
- this.typeInfoStack.push(new TypeInfo(typeDeclaration, visitMethods, enclosingTypeName));
- }
- public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
- this.typeInfoStack.pop();
- }
- public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
- this.typeInfoStack.pop();
- }
- public boolean visit(MethodDeclaration methodDeclaration, ClassScope classScope) {
- TypeInfo typeInfo = this.typeInfoStack.peek();
- if (typeInfo.visitMethods &&
- match(methodName, methodMatchRule, methodDeclaration.selector)) {
- reportMatchingMethod(path, packageDeclaration,
- typeInfo.enclosingTypeName,
- typeInfo.typeDecl,
- methodDeclaration,
- getCurrentType(),
- nameRequestor);
- }
-
- return false; // no need to find methods from local/anonymous type
- }
- public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
- return false; // do not visit local/anonymous types
- }
- public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
- addStackEntry(typeDeclaration, CharOperation.NO_CHAR);
- return true;
- }
- public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
- TypeInfo typeInfo = this.typeInfoStack.peek();
- addStackEntry(memberTypeDeclaration, typeInfo.enclosingTypeName == CharOperation.NO_CHAR ? typeInfo.typeDecl.name :
- CharOperation.concat(typeInfo.enclosingTypeName, typeInfo.typeDecl.name, '.'));
- return true;
+ private void addStackEntry(TypeDeclaration typeDeclaration, char[] enclosingTypeName) {
+ boolean visitMethods = match(declaringQualification, declQualificationMatchRule, enclosingTypeName) &&
+ match(declaringSimpleName, declSimpleNameMatchRule, typeDeclaration.name);
+ this.typeInfoStack.push(new TypeInfo(typeDeclaration, visitMethods, enclosingTypeName));
+ }
+ public void endVisit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
+ this.typeInfoStack.pop();
+ }
+ public void endVisit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
+ this.typeInfoStack.pop();
+ }
+ public boolean visit(MethodDeclaration methodDeclaration, ClassScope classScope) {
+ TypeInfo typeInfo = this.typeInfoStack.peek();
+ if (typeInfo.visitMethods &&
+ match(methodName, methodMatchRule, methodDeclaration.selector)) {
+ reportMatchingMethod(path, packageDeclaration,
+ typeInfo.enclosingTypeName,
+ typeInfo.typeDecl,
+ methodDeclaration,
+ getCurrentType(),
+ nameRequestor);
}
+
+ return false; // no need to find methods from local/anonymous type
+ }
+ public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
+ return false; // do not visit local/anonymous types
+ }
+ public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope s) {
+ addStackEntry(typeDeclaration, CharOperation.NO_CHAR);
+ return true;
+ }
+ public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope s) {
+ TypeInfo typeInfo = this.typeInfoStack.peek();
+ addStackEntry(memberTypeDeclaration, typeInfo.enclosingTypeName == CharOperation.NO_CHAR ? typeInfo.typeDecl.name :
+ CharOperation.concat(typeInfo.enclosingTypeName, typeInfo.typeDecl.name, '.'));
+ return true;
}
- if (match(packageName, pkgMatchRule, packageDeclaration))
- parsedUnit.traverse(new AllMethodDeclarationVisitor(), parsedUnit.scope);
}
- }
- if (progressMonitor != null) {
- if (progressMonitor.isCanceled()) throw new OperationCanceledException();
- progressMonitor.worked(1);
+ if (match(packageName, pkgMatchRule, packageDeclaration))
+ parsedUnit.traverse(new AllMethodDeclarationVisitor(), parsedUnit.scope);
}
}
}
- } finally {
- if (progressMonitor != null) {
- progressMonitor.done();
- }
}
}
@@ -1372,9 +1635,7 @@ boolean match(char[] patternName, int matchRule, char[] name) {
// add type names from indexes
try {
- if (progressMonitor != null) {
- progressMonitor.beginTask(Messages.engine_searching, 100);
- }
+ SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 100);
indexManager.performConcurrentJob(
new PatternSearchJob(
pattern,
@@ -1384,13 +1645,9 @@ boolean match(char[] patternName, int matchRule, char[] name) {
waitForIndexes
? IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH
: IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH,
- progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 100));
+ subMonitor.split(100));
} catch (OperationCanceledException oce) {
// do nothing
- } finally {
- if (progressMonitor != null) {
- progressMonitor.done();
- }
}
}
@@ -1544,125 +1801,114 @@ boolean match(char[] patternName, int matchRule, char[] name) {
}
};
- try {
- if (progressMonitor != null) {
- progressMonitor.beginTask(Messages.engine_searching, 1000);
- }
- // add type names from indexes
- indexManager.performConcurrentJob(
- new PatternSearchJob(
- pattern,
- getDefaultSearchParticipant(), // Java search only
- scope,
- searchRequestor),
- waitingPolicy,
- progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 1000-copiesLength));
-
- // add type names from working copies
- if (copies != null) {
- for (int i = 0; i < copiesLength; i++) {
- final ICompilationUnit workingCopy = copies[i];
- if (scope instanceof HierarchyScope) {
- if (!((HierarchyScope)scope).encloses(workingCopy, progressMonitor)) continue;
- } else {
- if (!scope.encloses(workingCopy)) continue;
- }
- final String path = workingCopy.getPath().toString();
- if (workingCopy.isConsistent()) {
- IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
- char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
- IType[] allTypes = workingCopy.getAllTypes();
- for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
- IType type = allTypes[j];
- IJavaElement parent = type.getParent();
- char[][] enclosingTypeNames;
- if (parent instanceof IType) {
- char[] parentQualifiedName = ((IType)parent).getTypeQualifiedName('.').toCharArray();
- enclosingTypeNames = CharOperation.splitOn('.', parentQualifiedName);
+ SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 1000);
+ // add type names from indexes
+ indexManager.performConcurrentJob(
+ new PatternSearchJob(
+ pattern,
+ getDefaultSearchParticipant(), // Java search only
+ scope,
+ searchRequestor),
+ waitingPolicy,
+ subMonitor.split(Math.max(1000-copiesLength, 0)));
+
+ // add type names from working copies
+ if (copies != null) {
+ for (int i = 0; i < copiesLength; i++) {
+ SubMonitor iterationMonitor = subMonitor.split(i);
+ final ICompilationUnit workingCopy = copies[i];
+ if (scope instanceof HierarchyScope) {
+ if (!((HierarchyScope)scope).encloses(workingCopy, iterationMonitor)) continue;
+ } else {
+ if (!scope.encloses(workingCopy)) continue;
+ }
+ final String path = workingCopy.getPath().toString();
+ if (workingCopy.isConsistent()) {
+ IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
+ char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
+ IType[] allTypes = workingCopy.getAllTypes();
+ for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
+ IType type = allTypes[j];
+ IJavaElement parent = type.getParent();
+ char[][] enclosingTypeNames;
+ if (parent instanceof IType) {
+ char[] parentQualifiedName = ((IType)parent).getTypeQualifiedName('.').toCharArray();
+ enclosingTypeNames = CharOperation.splitOn('.', parentQualifiedName);
+ } else {
+ enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+ }
+ char[] simpleName = type.getElementName().toCharArray();
+ int kind;
+ if (type.isEnum()) {
+ kind = TypeDeclaration.ENUM_DECL;
+ } else if (type.isAnnotation()) {
+ kind = TypeDeclaration.ANNOTATION_TYPE_DECL;
+ } else if (type.isClass()) {
+ kind = TypeDeclaration.CLASS_DECL;
+ } else /*if (type.isInterface())*/ {
+ kind = TypeDeclaration.INTERFACE_DECL;
+ }
+ if (match(typeSuffix, packageName, packageMatchRule, typeName, validatedTypeMatchRule, kind, packageDeclaration, simpleName)) {
+ if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
+ ((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, type.getFlags()));
} else {
- enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+ nameRequestor.acceptType(type.getFlags(), packageDeclaration, simpleName, enclosingTypeNames, path, null);
}
- char[] simpleName = type.getElementName().toCharArray();
- int kind;
- if (type.isEnum()) {
- kind = TypeDeclaration.ENUM_DECL;
- } else if (type.isAnnotation()) {
- kind = TypeDeclaration.ANNOTATION_TYPE_DECL;
- } else if (type.isClass()) {
- kind = TypeDeclaration.CLASS_DECL;
- } else /*if (type.isInterface())*/ {
- kind = TypeDeclaration.INTERFACE_DECL;
+ }
+ }
+ } else {
+ Parser basicParser = getParser();
+ org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
+ CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
+ CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
+ if (parsedUnit != null) {
+ final char[] packageDeclaration = parsedUnit.currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
+ class AllTypeDeclarationsVisitor extends ASTVisitor {
+ public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
+ return false; // no local/anonymous type
}
- if (match(typeSuffix, packageName, packageMatchRule, typeName, validatedTypeMatchRule, kind, packageDeclaration, simpleName)) {
- if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
- ((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, type.getFlags()));
- } else {
- nameRequestor.acceptType(type.getFlags(), packageDeclaration, simpleName, enclosingTypeNames, path, null);
+ public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
+ if (match(typeSuffix, packageName, packageMatchRule, typeName, validatedTypeMatchRule, TypeDeclaration.kind(typeDeclaration.modifiers), packageDeclaration, typeDeclaration.name)) {
+ if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
+ IType type = workingCopy.getType(new String(typeName));
+ ((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, typeDeclaration.modifiers));
+ } else {
+ nameRequestor.acceptType(typeDeclaration.modifiers, packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path, null);
+ }
}
+ return true;
}
- }
- } else {
- Parser basicParser = getParser();
- org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
- CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
- CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
- if (parsedUnit != null) {
- final char[] packageDeclaration = parsedUnit.currentPackage == null ? CharOperation.NO_CHAR : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
- class AllTypeDeclarationsVisitor extends ASTVisitor {
- public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
- return false; // no local/anonymous type
- }
- public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
- if (match(typeSuffix, packageName, packageMatchRule, typeName, validatedTypeMatchRule, TypeDeclaration.kind(typeDeclaration.modifiers), packageDeclaration, typeDeclaration.name)) {
- if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
- IType type = workingCopy.getType(new String(typeName));
- ((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, typeDeclaration.modifiers));
+ public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
+ if (match(typeSuffix, packageName, packageMatchRule, typeName, validatedTypeMatchRule, TypeDeclaration.kind(memberTypeDeclaration.modifiers), packageDeclaration, memberTypeDeclaration.name)) {
+ // compute enclosing type names
+ TypeDeclaration enclosing = memberTypeDeclaration.enclosingType;
+ char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+ while (enclosing != null) {
+ enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
+ if ((enclosing.bits & ASTNode.IsMemberType) != 0) {
+ enclosing = enclosing.enclosingType;
} else {
- nameRequestor.acceptType(typeDeclaration.modifiers, packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path, null);
+ enclosing = null;
}
}
- return true;
- }
- public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
- if (match(typeSuffix, packageName, packageMatchRule, typeName, validatedTypeMatchRule, TypeDeclaration.kind(memberTypeDeclaration.modifiers), packageDeclaration, memberTypeDeclaration.name)) {
- // compute enclosing type names
- TypeDeclaration enclosing = memberTypeDeclaration.enclosingType;
- char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
- while (enclosing != null) {
- enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
- if ((enclosing.bits & ASTNode.IsMemberType) != 0) {
- enclosing = enclosing.enclosingType;
- } else {
- enclosing = null;
- }
- }
- // report
- if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
- IType type = workingCopy.getType(new String(enclosingTypeNames[0]));
- for (int j=1, l=enclosingTypeNames.length; j<l; j++) {
- type = type.getType(new String(enclosingTypeNames[j]));
- }
- ((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, 0));
- } else {
- nameRequestor.acceptType(memberTypeDeclaration.modifiers, packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path, null);
+ // report
+ if (nameRequestor instanceof TypeNameMatchRequestorWrapper) {
+ IType type = workingCopy.getType(new String(enclosingTypeNames[0]));
+ for (int j=1, l=enclosingTypeNames.length; j<l; j++) {
+ type = type.getType(new String(enclosingTypeNames[j]));
}
+ ((TypeNameMatchRequestorWrapper)nameRequestor).requestor.acceptTypeNameMatch(new JavaSearchTypeNameMatch(type, 0));
+ } else {
+ nameRequestor.acceptType(memberTypeDeclaration.modifiers, packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path, null);
}
- return true;
}
+ return true;
}
- parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
}
- }
- if (progressMonitor != null) {
- if (progressMonitor.isCanceled()) throw new OperationCanceledException();
- progressMonitor.worked(1);
+ parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
}
}
}
- } finally {
- if (progressMonitor != null) {
- progressMonitor.done();
- }
}
}
@@ -1794,108 +2040,100 @@ boolean match(char[] patternName, int matchRule, char[] name) {
}
};
- try {
- if (progressMonitor != null) {
- progressMonitor.beginTask(Messages.engine_searching, 100);
- }
- // add type names from indexes
- indexManager.performConcurrentJob(
- new PatternSearchJob(
- pattern,
- getDefaultSearchParticipant(), // Java search only
- scope,
- searchRequestor),
- waitingPolicy,
- progressMonitor == null ? null : new SubProgressMonitor(progressMonitor, 100));
-
- // add type names from working copies
- if (copies != null) {
- for (int i = 0, length = copies.length; i < length; i++) {
- ICompilationUnit workingCopy = copies[i];
- final String path = workingCopy.getPath().toString();
- if (workingCopy.isConsistent()) {
- IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
- char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
- IType[] allTypes = workingCopy.getAllTypes();
- for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
- IType type = allTypes[j];
- IJavaElement parent = type.getParent();
- char[][] enclosingTypeNames;
- char[] qualification = packageDeclaration;
- if (parent instanceof IType) {
- char[] parentQualifiedName = ((IType)parent).getTypeQualifiedName('.').toCharArray();
- enclosingTypeNames = CharOperation.splitOn('.', parentQualifiedName);
- qualification = CharOperation.concat(qualification, parentQualifiedName);
- } else {
- enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
- }
- char[] simpleName = type.getElementName().toCharArray();
- char suffix = IIndexConstants.TYPE_SUFFIX;
- if (type.isClass()) {
- suffix = IIndexConstants.CLASS_SUFFIX;
- } else if (type.isInterface()) {
- suffix = IIndexConstants.INTERFACE_SUFFIX;
- } else if (type.isEnum()) {
- suffix = IIndexConstants.ENUM_SUFFIX;
- } else if (type.isAnnotation()) {
- suffix = IIndexConstants.ANNOTATION_TYPE_SUFFIX;
- }
- if (pattern.matchesDecodedKey(new QualifiedTypeDeclarationPattern(qualification, simpleName, suffix, matchRule))) {
- nameRequestor.acceptType(type.getFlags(), packageDeclaration, simpleName, enclosingTypeNames, path, null);
- }
+ SubMonitor subMonitor = SubMonitor.convert(progressMonitor, Messages.engine_searching, 100);
+ // add type names from indexes
+ indexManager.performConcurrentJob(
+ new PatternSearchJob(
+ pattern,
+ getDefaultSearchParticipant(), // Java search only
+ scope,
+ searchRequestor),
+ waitingPolicy,
+ subMonitor.split(100));
+
+ // add type names from working copies
+ if (copies != null) {
+ for (int i = 0, length = copies.length; i < length; i++) {
+ ICompilationUnit workingCopy = copies[i];
+ final String path = workingCopy.getPath().toString();
+ if (workingCopy.isConsistent()) {
+ IPackageDeclaration[] packageDeclarations = workingCopy.getPackageDeclarations();
+ char[] packageDeclaration = packageDeclarations.length == 0 ? CharOperation.NO_CHAR : packageDeclarations[0].getElementName().toCharArray();
+ IType[] allTypes = workingCopy.getAllTypes();
+ for (int j = 0, allTypesLength = allTypes.length; j < allTypesLength; j++) {
+ IType type = allTypes[j];
+ IJavaElement parent = type.getParent();
+ char[][] enclosingTypeNames;
+ char[] qualification = packageDeclaration;
+ if (parent instanceof IType) {
+ char[] parentQualifiedName = ((IType)parent).getTypeQualifiedName('.').toCharArray();
+ enclosingTypeNames = CharOperation.splitOn('.', parentQualifiedName);
+ qualification = CharOperation.concat(qualification, parentQualifiedName);
+ } else {
+ enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
}
- } else {
- Parser basicParser = getParser();
- org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
- CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
- CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
- if (parsedUnit != null) {
- final char[] packageDeclaration = parsedUnit.currentPackage == null
- ? CharOperation.NO_CHAR
- : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
- class AllTypeDeclarationsVisitor extends ASTVisitor {
- public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
- return false; // no local/anonymous type
+ char[] simpleName = type.getElementName().toCharArray();
+ char suffix = IIndexConstants.TYPE_SUFFIX;
+ if (type.isClass()) {
+ suffix = IIndexConstants.CLASS_SUFFIX;
+ } else if (type.isInterface()) {
+ suffix = IIndexConstants.INTERFACE_SUFFIX;
+ } else if (type.isEnum()) {
+ suffix = IIndexConstants.ENUM_SUFFIX;
+ } else if (type.isAnnotation()) {
+ suffix = IIndexConstants.ANNOTATION_TYPE_SUFFIX;
+ }
+ if (pattern.matchesDecodedKey(new QualifiedTypeDeclarationPattern(qualification, simpleName, suffix, matchRule))) {
+ nameRequestor.acceptType(type.getFlags(), packageDeclaration, simpleName, enclosingTypeNames, path, null);
+ }
+ }
+ } else {
+ Parser basicParser = getParser();
+ org.eclipse.jdt.internal.compiler.env.ICompilationUnit unit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) workingCopy;
+ CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.compilerOptions.maxProblemsPerUnit);
+ CompilationUnitDeclaration parsedUnit = basicParser.dietParse(unit, compilationUnitResult);
+ if (parsedUnit != null) {
+ final char[] packageDeclaration = parsedUnit.currentPackage == null
+ ? CharOperation.NO_CHAR
+ : CharOperation.concatWith(parsedUnit.currentPackage.getImportName(), '.');
+ class AllTypeDeclarationsVisitor extends ASTVisitor {
+ public boolean visit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
+ return false; // no local/anonymous type
+ }
+ public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
+ SearchPattern decodedPattern =
+ new QualifiedTypeDeclarationPattern(packageDeclaration, typeDeclaration.name, convertTypeKind(TypeDeclaration.kind(typeDeclaration.modifiers)), matchRule);
+ if (pattern.matchesDecodedKey(decodedPattern)) {
+ nameRequestor.acceptType(typeDeclaration.modifiers, packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path, null);
}
- public boolean visit(TypeDeclaration typeDeclaration, CompilationUnitScope compilationUnitScope) {
- SearchPattern decodedPattern =
- new QualifiedTypeDeclarationPattern(packageDeclaration, typeDeclaration.name, convertTypeKind(TypeDeclaration.kind(typeDeclaration.modifiers)), matchRule);
- if (pattern.matchesDecodedKey(decodedPattern)) {
- nameRequestor.acceptType(typeDeclaration.modifiers, packageDeclaration, typeDeclaration.name, CharOperation.NO_CHAR_CHAR, path, null);
+ return true;
+ }
+ public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
+ // compute enclosing type names
+ char[] qualification = packageDeclaration;
+ TypeDeclaration enclosing = memberTypeDeclaration.enclosingType;
+ char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
+ while (enclosing != null) {
+ qualification = CharOperation.concat(qualification, enclosing.name, '.');
+ enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
+ if ((enclosing.bits & ASTNode.IsMemberType) != 0) {
+ enclosing = enclosing.enclosingType;
+ } else {
+ enclosing = null;
}
- return true;
}
- public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
- // compute enclosing type names
- char[] qualification = packageDeclaration;
- TypeDeclaration enclosing = memberTypeDeclaration.enclosingType;
- char[][] enclosingTypeNames = CharOperation.NO_CHAR_CHAR;
- while (enclosing != null) {
- qualification = CharOperation.concat(qualification, enclosing.name, '.');
- enclosingTypeNames = CharOperation.arrayConcat(new char[][] {enclosing.name}, enclosingTypeNames);
- if ((enclosing.bits & ASTNode.IsMemberType) != 0) {
- enclosing = enclosing.enclosingType;
- } else {
- enclosing = null;
- }
- }
- SearchPattern decodedPattern =
- new QualifiedTypeDeclarationPattern(qualification, memberTypeDeclaration.name, convertTypeKind(TypeDeclaration.kind(memberTypeDeclaration.modifiers)), matchRule);
- if (pattern.matchesDecodedKey(decodedPattern)) {
- nameRequestor.acceptType(memberTypeDeclaration.modifiers, packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path, null);
- }
- return true;
+ SearchPattern decodedPattern =
+ new QualifiedTypeDeclarationPattern(qualification, memberTypeDeclaration.name, convertTypeKind(TypeDeclaration.kind(memberTypeDeclaration.modifiers)), matchRule);
+ if (pattern.matchesDecodedKey(decodedPattern)) {
+ nameRequestor.acceptType(memberTypeDeclaration.modifiers, packageDeclaration, memberTypeDeclaration.name, enclosingTypeNames, path, null);
}
+ return true;
}
- parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
}
+ parsedUnit.traverse(new AllTypeDeclarationsVisitor(), parsedUnit.scope);
}
}
}
- } finally {
- if (progressMonitor != null) {
- progressMonitor.done();
- }
}
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameMatchRequestorWrapper.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameMatchRequestorWrapper.java
index 7d4b26230..4cd69335f 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameMatchRequestorWrapper.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/MethodNameMatchRequestorWrapper.java
@@ -13,6 +13,7 @@ package org.eclipse.jdt.internal.core.search;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.MethodNameMatchRequestor;
@@ -68,7 +69,23 @@ public class MethodNameMatchRequestorWrapper extends NameMatchRequestorWrapper i
if (type == null) return;
if (!(!(this.scope instanceof HierarchyScope) || ((HierarchyScope) this.scope).enclosesFineGrained(type))) return;
parameterTypes = parameterTypes == null ? CharOperation.NO_CHAR_CHAR : parameterTypes;
- IMethod method = type.getMethod(new String(methodName), CharOperation.toStrings(parameterTypes));
+ String[] paramTypeSigs = CharOperation.NO_STRINGS;
+ if (signature != null) {
+ char[][] parTypes = Signature.getParameterTypes(signature);
+ if (parTypes.length > 0) {
+ for (int i = 0, l = parTypes.length; i < l; ++i) {
+ CharOperation.replace(parTypes[i], '/', '.');
+ }
+ }
+ paramTypeSigs = CharOperation.toStrings(parTypes);
+ } else if (parameterTypes.length > 0) {
+ int l = parameterTypes.length;
+ paramTypeSigs = new String[l];
+ for (int i = 0; i < l; ++i) {
+ paramTypeSigs[i] = Signature.createTypeSignature(parameterTypes[i], false);
+ }
+ }
+ IMethod method = type.getMethod(new String(methodName), paramTypeSigs);
this.requestor.acceptMethodNameMatch(new JavaSearchMethodNameMatch(method, modifiers));
}
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
index 4ff4e6336..1c6233951 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/BinaryIndexer.java
@@ -757,7 +757,8 @@ public class BinaryIndexer extends AbstractIndexer implements SuffixConstants {
extraFlags);
} else {
if (!method.isClinit()) {
- addMethodDeclaration(method.getSelector(), parameterTypes, returnType, exceptionTypes);
+ char[] selector = method.getSelector();
+ addMethodDeclaration(selector, parameterTypes, returnType, exceptionTypes);
char[] signature = method.getGenericSignature();
if (signature == null) {
signature = descriptor;
@@ -766,7 +767,7 @@ public class BinaryIndexer extends AbstractIndexer implements SuffixConstants {
addMethodDeclaration(
name,
null,
- method.getSelector(),
+ selector,
parameterTypes == null ? 0 : parameterTypes.length,
signature,
parameterTypes,
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java
index 607936809..f9594cbe4 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/MethodDeclarationPattern.java
@@ -26,6 +26,7 @@ public class MethodDeclarationPattern extends MethodPattern {
public char[] signature;
public char[][] parameterTypes;
public char[][] parameterNames;
+ public char[] fusedDeclaringQualifier = null; // TODO: do we need this; cleanup?
/**
* Method Declaration entries are encoded as described
*
@@ -57,107 +58,43 @@ public class MethodDeclarationPattern extends MethodPattern {
char[] parameterNamesChars = null;
- countChars = argCount < 10 ? COUNTS[argCount]: ("/" + String.valueOf(argCount)).toCharArray(); //$NON-NLS-1$
+ countChars = argCount < 10 ? new char[] {COUNTS[argCount][1]}: String.valueOf(argCount).toCharArray();
if (argCount > 0) {
if (signature == null) {
if (parameterTypes != null && parameterTypes.length == argCount) {
- char[][] parameterTypeErasures = new char[argCount][];
- for (int i = 0; i < parameterTypes.length; i++) {
- parameterTypeErasures[i] = getTypeErasure(parameterTypes[i]);
- }
- parameterTypesChars = CharOperation.concatWith(parameterTypeErasures, PARAMETER_SEPARATOR);
+ parameterTypesChars = CharOperation.concatWith(parameterTypes, PARAMETER_SEPARATOR);
}
} else {
extraFlags |= ExtraFlags.ParameterTypesStoredAsSignature;
}
-
if (parameterNames != null && parameterNames.length == argCount) {
parameterNamesChars = CharOperation.concatWith(parameterNames, PARAMETER_SEPARATOR);
}
}
- char[] returnTypeChars = returnType == null ? CharOperation.NO_CHAR : getTypeErasure(returnType);
-
-
- int typeNameLength = typeName == null ? 0 : typeName.length;
- int qualifierLength = declaringQualification == null ? 0 : declaringQualification.length;
- int methodNameLength = methodName == null ? 0 : methodName.length;
- int packageNameLength = packageName == null ? 0 : packageName.length;
- int countCharsLength = countChars.length;
- int parameterTypesLength = signature == null ? (parameterTypesChars == null ? 0 : parameterTypesChars.length): signature.length;
- int parameterNamesLength = parameterNamesChars == null ? 0 : parameterNamesChars.length;
- int returnTypeLength = returnTypeChars.length;
-
- int resultLength = methodNameLength + countCharsLength + qualifierLength + typeNameLength + 2 /* type modifiers */
- + packageNameLength + parameterTypesLength + parameterNamesLength + returnTypeLength + 2 /* modifiers*/ + 9; // SEPARATOR = 9
- char[] result = new char[resultLength];
-
- int pos = 0;
- if (methodNameLength > 0) {
- System.arraycopy(methodName, 0, result, pos, methodNameLength);
- pos += methodNameLength;
- }
- if (countCharsLength > 0) {
- System.arraycopy(countChars, 0, result, pos, countCharsLength);
- pos += countCharsLength;
- }
- result[pos++] = SEPARATOR;
- if (qualifierLength > 0) {
- System.arraycopy(declaringQualification, 0, result, pos, qualifierLength);
- pos += qualifierLength;
- }
- result[pos++] = SEPARATOR;
-
- if (typeNameLength > 0) {
- System.arraycopy(typeName, 0, result, pos, typeNameLength);
- pos += typeNameLength;
- }
-
-
+ char[] returnTypeChars = returnType == null ? CharOperation.NO_CHAR : getTypeErasure(returnType);
int typeModifiersWithExtraFlags = typeModifiers | encodeExtraFlags(extraFlags);
- result[pos++] = SEPARATOR;
- result[pos++] = (char) typeModifiersWithExtraFlags;
- result[pos++] = (char) (typeModifiersWithExtraFlags>>16);
+ int entryIndex = 0;
+ int numEntries = 10;
+ char [][] tmp = new char[numEntries][];
- result[pos++] = SEPARATOR;
- if (packageNameLength > 0) {
- System.arraycopy(packageName, 0, result, pos, packageNameLength);
- pos += packageNameLength;
- }
+ tmp[entryIndex++] = methodName != null ? methodName : CharOperation.NO_CHAR;
+ tmp[entryIndex++] = countChars;
+ tmp[entryIndex++] = declaringQualification != null ? declaringQualification : CharOperation.NO_CHAR;
+ tmp[entryIndex++] = typeName != null ? typeName : CharOperation.NO_CHAR;
+ tmp[entryIndex++] = new char[] {(char) typeModifiersWithExtraFlags, (char) (typeModifiersWithExtraFlags>>16)};
+ tmp[entryIndex++] = packageName != null ? packageName : CharOperation.NO_CHAR;
if (argCount == 0) {
- result[pos++] = SEPARATOR;
- result[pos++] = SEPARATOR;
- result[pos++] = SEPARATOR;
+ tmp[entryIndex++] = CharOperation.NO_CHAR;
+ tmp[entryIndex++] = CharOperation.NO_CHAR;
} else if (argCount > 0) {
- result[pos++] = SEPARATOR;
- if (parameterTypesLength > 0) {
- if (signature == null) {
- System.arraycopy(parameterTypesChars, 0, result, pos, parameterTypesLength);
- } else {
- System.arraycopy(CharOperation.replaceOnCopy(signature, SEPARATOR, '\\'), 0, result, pos, parameterTypesLength);
- }
- pos += parameterTypesLength;
- }
-
- result[pos++] = SEPARATOR;
- if (parameterNamesLength > 0) {
- System.arraycopy(parameterNamesChars, 0, result, pos, parameterNamesLength);
- pos += parameterNamesLength;
- }
-
- result[pos++] = SEPARATOR;
+ tmp[entryIndex++] = signature != null ? CharOperation.replaceOnCopy(signature, SEPARATOR, '\\') : parameterTypesChars != null ? parameterTypesChars : CharOperation.NO_CHAR;
+ tmp[entryIndex++] = parameterNamesChars != null ? parameterNamesChars : CharOperation.NO_CHAR;
}
- result[pos++] = (char) modifiers;
- result[pos++] = (char) (modifiers>>16);
- result[pos++] = SEPARATOR;
-
- if (returnTypeLength > 0) {
- System.arraycopy(returnTypeChars, 0, result, pos, returnTypeLength);
- pos += returnTypeLength;
- }
- result[pos++] = SEPARATOR;
- return result;
+ tmp[entryIndex++] = new char[] {(char) modifiers, (char) (modifiers>>16)};
+ tmp[entryIndex] = returnTypeChars;
+ return CharOperation.concatWithAll(tmp, '/');
}
private static int encodeExtraFlags(int extraFlags) {
@@ -222,6 +159,16 @@ public MethodDeclarationPattern(
this.declaringPackageName = declaringPackageName;
}
+public MethodDeclarationPattern(
+ char[] declaringQualifier,
+ char[] methodName,
+ int matchRule) {
+ super(methodName, CharOperation.NO_CHAR, CharOperation.NO_CHAR,
+ null, null, null, null, null,
+ IJavaSearchConstants.DECLARATIONS, matchRule);
+ this.fusedDeclaringQualifier = declaringQualifier;
+}
+
public MethodDeclarationPattern(int matchRule) {
super(matchRule);
}
@@ -290,7 +237,7 @@ public void decodeIndexKey(char[] key) {
this.signature = CharOperation.subarray(key, start, slash);
CharOperation.replace(this.signature , '\\', SEPARATOR);
} else {
- this.parameterTypes = CharOperation.splitOn(PARAMETER_SEPARATOR, key, start, slash);
+ this.parameterTypes = CharOperation.splitOnWithEnclosures(PARAMETER_SEPARATOR, '<', '>', key, start, slash);
}
start = slash + 1;
slash = CharOperation.indexOf(SEPARATOR, key, start);
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java
index 86d15ff91..68ceb6994 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/matching/SuperTypeNamesCollector.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -14,7 +14,7 @@
package org.eclipse.jdt.internal.core.search.matching;
import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.search.*;
@@ -283,15 +283,14 @@ protected String[] getPathsOfDeclaringType() {
return true;
}
};
-
+ SubMonitor subMonitor = SubMonitor.convert(this.progressMonitor, 100);
indexManager.performConcurrentJob(
new PatternSearchJob(
searchPattern,
new JavaSearchParticipant(),
scope,
searchRequestor),
- IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH,
- this.progressMonitor == null ? null : new SubProgressMonitor(this.progressMonitor, 100));
+ IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, subMonitor.split(100));
return pathCollector.getPaths();
}
public char[][][] getSamePackageSuperTypeNames() {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
index 00b8d52d0..4626c37e0 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/processing/JobManager.java
@@ -27,14 +27,14 @@ public abstract class JobManager implements Runnable {
protected Thread processingThread;
protected Job progressJob;
- /* counter indicating whether job execution is enabled or not, disabled if <= 0
+ /* counter indicating whether job execution is enabled or not, disabled if <= 0
it cannot go beyond 1 */
private int enableCount = 1;
public static boolean VERBOSE = false;
/* flag indicating that the activation has completed */
public boolean activated = false;
-
+
private int awaitingClients = 0;
/**
@@ -154,7 +154,7 @@ public abstract class JobManager implements Runnable {
}
/**
* This API is allowing to run one job in concurrence with background processing.
- * Indeed since other jobs are performed in background, resource sharing might be
+ * Indeed since other jobs are performed in background, resource sharing might be
* an issue.Therefore, this functionality allows a given job to be run without
* colliding with background ones.
* Note: multiple thread might attempt to perform concurrent jobs at the same time,
@@ -175,116 +175,102 @@ public abstract class JobManager implements Runnable {
boolean status = IJob.FAILED;
try {
- int concurrentJobWork = 100;
- if (progress != null)
- progress.beginTask("", concurrentJobWork); //$NON-NLS-1$
+ SubMonitor subMonitor = SubMonitor.convert(progress);
if (awaitingJobsCount() > 0) {
switch (waitingPolicy) {
-
+
case IJob.ForceImmediate :
if (VERBOSE)
Util.verbose("-> NOT READY - forcing immediate - " + searchJob);//$NON-NLS-1$
try {
disable(); // pause indexing
- status = searchJob.execute(progress == null ? null : new SubProgressMonitor(progress, concurrentJobWork));
+ status = searchJob.execute(subMonitor);
} finally {
enable();
}
if (VERBOSE)
Util.verbose("FINISHED concurrent job - " + searchJob); //$NON-NLS-1$
return status;
-
+
case IJob.CancelIfNotReady :
if (VERBOSE)
Util.verbose("-> NOT READY - cancelling - " + searchJob); //$NON-NLS-1$
if (VERBOSE)
Util.verbose("CANCELED concurrent job - " + searchJob); //$NON-NLS-1$
throw new OperationCanceledException();
-
+
case IJob.WaitUntilReady :
- IProgressMonitor subProgress = null;
+ int totalWork = 1000;
+ SubMonitor subProgress = subMonitor.setWorkRemaining(10).split(8).setWorkRemaining(totalWork);
+ // use local variable to avoid potential NPE (see bug 20435 NPE when searching java method
+ // and bug 42760 NullPointerException in JobManager when searching)
+ Thread t = this.processingThread;
+ int originalPriority = t == null ? -1 : t.getPriority();
try {
- int totalWork = 1000;
- if (progress != null) {
- subProgress = new SubProgressMonitor(progress, concurrentJobWork * 8 / 10);
- subProgress.beginTask("", totalWork); //$NON-NLS-1$
- concurrentJobWork = concurrentJobWork * 2 / 10;
+ if (t != null)
+ t.setPriority(Thread.currentThread().getPriority());
+ synchronized(this) {
+ this.awaitingClients++;
}
- // use local variable to avoid potential NPE (see bug 20435 NPE when searching java method
- // and bug 42760 NullPointerException in JobManager when searching)
- Thread t = this.processingThread;
- int originalPriority = t == null ? -1 : t.getPriority();
- try {
- if (t != null)
- t.setPriority(Thread.currentThread().getPriority());
- synchronized(this) {
- this.awaitingClients++;
- }
- IJob previousJob = null;
- int awaitingJobsCount;
- int lastJobsCount = totalWork;
- float lastWorked = 0;
- float totalWorked = 0;
- while ((awaitingJobsCount = awaitingJobsCount()) > 0) {
- if ((subProgress != null && subProgress.isCanceled())
- || this.processingThread == null)
- throw new OperationCanceledException();
- IJob currentJob = currentJob();
- // currentJob can be null when jobs have been added to the queue but job manager is not enabled
- if (currentJob != null && currentJob != previousJob) {
- if (VERBOSE)
- Util.verbose("-> NOT READY - waiting until ready - " + searchJob);//$NON-NLS-1$
- if (subProgress != null) {
- String indexing = Messages.bind(Messages.jobmanager_filesToIndex, currentJob.getJobFamily(), Integer.toString(awaitingJobsCount));
- subProgress.subTask(indexing);
- // ratio of the amount of work relative to the total work
- float ratio = awaitingJobsCount < totalWork ? 1 : ((float) totalWork) / awaitingJobsCount;
- if (lastJobsCount > awaitingJobsCount) {
- totalWorked += (lastJobsCount - awaitingJobsCount) * ratio;
- } else {
- // more jobs were added, just increment by the ratio
- totalWorked += ratio;
- }
- if (totalWorked - lastWorked >= 1) {
- subProgress.worked((int) (totalWorked - lastWorked));
- lastWorked = totalWorked;
- }
- lastJobsCount = awaitingJobsCount;
+ IJob previousJob = null;
+ int awaitingJobsCount;
+ int lastJobsCount = totalWork;
+ float lastWorked = 0;
+ float totalWorked = 0;
+ while ((awaitingJobsCount = awaitingJobsCount()) > 0) {
+ if ((subProgress != null && subProgress.isCanceled())
+ || this.processingThread == null)
+ throw new OperationCanceledException();
+ IJob currentJob = currentJob();
+ // currentJob can be null when jobs have been added to the queue but job manager is not enabled
+ if (currentJob != null && currentJob != previousJob) {
+ if (VERBOSE)
+ Util.verbose("-> NOT READY - waiting until ready - " + searchJob);//$NON-NLS-1$
+ if (subProgress != null) {
+ String indexing = Messages.bind(Messages.jobmanager_filesToIndex, currentJob.getJobFamily(), Integer.toString(awaitingJobsCount));
+ subProgress.subTask(indexing);
+ // ratio of the amount of work relative to the total work
+ float ratio = awaitingJobsCount < totalWork ? 1 : ((float) totalWork) / awaitingJobsCount;
+ if (lastJobsCount > awaitingJobsCount) {
+ totalWorked += (lastJobsCount - awaitingJobsCount) * ratio;
+ } else {
+ // more jobs were added, just increment by the ratio
+ totalWorked += ratio;
}
- previousJob = currentJob;
- }
- try {
- if (VERBOSE)
- Util.verbose("-> GOING TO SLEEP - " + searchJob);//$NON-NLS-1$
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // ignore
+ if (totalWorked - lastWorked >= 1) {
+ subProgress.worked((int) (totalWorked - lastWorked));
+ lastWorked = totalWorked;
+ }
+ lastJobsCount = awaitingJobsCount;
}
+ previousJob = currentJob;
}
- } finally {
- synchronized(this) {
- this.awaitingClients--;
+ try {
+ if (VERBOSE)
+ Util.verbose("-> GOING TO SLEEP - " + searchJob);//$NON-NLS-1$
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ // ignore
}
- if (t != null && originalPriority > -1 && t.isAlive())
- t.setPriority(originalPriority);
}
} finally {
- if (subProgress != null)
- subProgress.done();
+ synchronized(this) {
+ this.awaitingClients--;
+ }
+ if (t != null && originalPriority > -1 && t.isAlive())
+ t.setPriority(originalPriority);
}
}
}
- status = searchJob.execute(progress == null ? null : new SubProgressMonitor(progress, concurrentJobWork));
+ status = searchJob.execute(subMonitor);
} finally {
- if (progress != null)
- progress.done();
if (VERBOSE)
Util.verbose("FINISHED concurrent job - " + searchJob); //$NON-NLS-1$
}
return status;
}
public abstract String processName();
-
+
public synchronized void request(IJob job) {
job.ensureReadyToRun();
@@ -299,7 +285,7 @@ public abstract class JobManager implements Runnable {
for (int i = this.jobStart; i < size; i++)
this.awaitingJobs[i] = null;
} else {
- System.arraycopy(this.awaitingJobs, this.jobStart, this.awaitingJobs = new IJob[size * 2], 0, this.jobEnd);
+ System.arraycopy(this.awaitingJobs, this.jobStart, this.awaitingJobs = new IJob[size * 2], 0, this.jobEnd);
}
this.jobStart = 0;
}
@@ -324,7 +310,7 @@ public abstract class JobManager implements Runnable {
this.processingThread = new Thread(this, processName());
this.processingThread.setDaemon(true);
// less prioritary by default, priority is raised if clients are actively waiting on it
- this.processingThread.setPriority(Thread.NORM_PRIORITY-1);
+ this.processingThread.setPriority(Thread.NORM_PRIORITY-1);
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=296343
// set the context loader to avoid leaking the current context loader
this.processingThread.setContextClassLoader(this.getClass().getClassLoader());
@@ -350,7 +336,7 @@ public abstract class JobManager implements Runnable {
.append(Messages.bind(Messages.jobmanager_filesToIndex, job.getJobFamily(), Integer.toString(awaitingJobsCount())))
.toString();
monitor.subTask(taskName);
- setName(taskName);
+ setName(taskName);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
@@ -419,7 +405,7 @@ public abstract class JobManager implements Runnable {
if (this.processingThread != null) { // if not shutting down
// log exception
Util.log(e, "Background Indexer Crash Recovery"); //$NON-NLS-1$
-
+
// keep job manager alive
discardJobs(null);
this.processingThread = null;
@@ -430,7 +416,7 @@ public abstract class JobManager implements Runnable {
if (this.processingThread != null && !(e instanceof ThreadDeath)) {
// log exception
Util.log(e, "Background Indexer Crash Recovery"); //$NON-NLS-1$
-
+
// keep job manager alive
discardJobs(null);
this.processingThread = null;
@@ -477,5 +463,5 @@ public abstract class JobManager implements Runnable {
buffer.append(i).append(" - job["+i+"]: ").append(this.awaitingJobs[this.jobStart+i]).append('\n'); //$NON-NLS-1$ //$NON-NLS-2$
}
return buffer.toString();
- }
+ }
}

Back to the top