Upgrade to neon.2 75dbfad0
diff --git a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/BuildJarIndex.java b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/BuildJarIndex.java
index cd7238a..fcb9685 100644
--- a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/BuildJarIndex.java
+++ b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/BuildJarIndex.java
@@ -48,7 +48,7 @@
try {
JavaIndexer.generateIndexForJar(this.jarPath, this.indexPath);
} catch (IOException e) {
- throw new BuildException(AntAdapterMessages.getString("buildJarIndex.ioexception.occured", e.getLocalizedMessage())); //$NON-NLS-1$
+ throw new BuildException(AntAdapterMessages.getString("buildJarIndex.ioexception.occured", e.getLocalizedMessage()), e); //$NON-NLS-1$
}
}
diff --git a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/CheckDebugAttributes.java b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/CheckDebugAttributes.java
index b6617d7..28488d8 100644
--- a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/CheckDebugAttributes.java
+++ b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/CheckDebugAttributes.java
@@ -60,7 +60,7 @@
try {
jarFile = new ZipFile(this.file);
} catch (ZipException e) {
- throw new BuildException(AntAdapterMessages.getString("checkDebugAttributes.file.argument.must.be.a.classfile.or.a.jarfile")); //$NON-NLS-1$
+ throw new BuildException(AntAdapterMessages.getString("checkDebugAttributes.file.argument.must.be.a.classfile.or.a.jarfile"), e); //$NON-NLS-1$
} finally {
if (jarFile != null) {
jarFile.close();
@@ -78,7 +78,7 @@
getProject().setUserProperty(this.property, "has debug"); //$NON-NLS-1$
}
} catch (IOException e) {
- throw new BuildException(AntAdapterMessages.getString("checkDebugAttributes.ioexception.occured") + this.file); //$NON-NLS-1$
+ throw new BuildException(AntAdapterMessages.getString("checkDebugAttributes.ioexception.occured") + this.file, e); //$NON-NLS-1$
}
}
diff --git a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java
index c2bdf71..507f55d 100644
--- a/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java
+++ b/org.eclipse.jdt.core/antadapter/org/eclipse/jdt/core/JDTCompilerAdapter.java
@@ -84,7 +84,7 @@
}
return resultValue;
} catch (ClassNotFoundException cnfe) {
- throw new BuildException(AntAdapterMessages.getString("ant.jdtadapter.error.cannotFindJDTCompiler")); //$NON-NLS-1$
+ throw new BuildException(AntAdapterMessages.getString("ant.jdtadapter.error.cannotFindJDTCompiler"), cnfe); //$NON-NLS-1$
} catch (Exception ex) {
throw new BuildException(ex);
}
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
index 6f5c2a5..b0ac625 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/model/TypesImpl.java
@@ -8,6 +8,7 @@
* Contributors:
* Walter Harley - initial API and implementation
* IBM Corporation - fix for 342598, 382590
+ * Jean-Marie Henaff <jmhenaff@google.com> (Google) - Bug 481555
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.apt.model;
@@ -74,62 +75,124 @@
}
@Override
- public TypeMirror asMemberOf(DeclaredType containing, Element element) {
-// throw new UnsupportedOperationException("NYI: TypesImpl.asMemberOf(" + containing + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- ElementImpl elementImpl = (ElementImpl) element;
- DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing;
- ReferenceBinding referenceBinding = (ReferenceBinding) declaredTypeImpl._binding;
- switch(element.getKind()) {
- case CONSTRUCTOR :
- case METHOD :
- MethodBinding methodBinding = (MethodBinding) elementImpl._binding;
- while (referenceBinding != null) {
- for (MethodBinding method : referenceBinding.methods()) {
- if (CharOperation.equals(method.selector, methodBinding.selector) &&
- (method.original() == methodBinding || method.areParameterErasuresEqual(methodBinding))) {
- return this._env.getFactory().newTypeMirror(method);
- }
- }
- referenceBinding = referenceBinding.superclass();
- }
- break;
- case FIELD :
- case ENUM_CONSTANT:
- FieldBinding fieldBinding = (FieldBinding) elementImpl._binding;
- while (referenceBinding != null) {
- for (FieldBinding field : referenceBinding.fields()) {
- if (CharOperation.equals(field.name, fieldBinding.name)) {
- return this._env.getFactory().newTypeMirror(field);
- }
- }
- referenceBinding = referenceBinding.superclass();
- }
- break;
- case ENUM :
- case ANNOTATION_TYPE :
- case INTERFACE :
- case CLASS :
- ReferenceBinding elementBinding = (ReferenceBinding) elementImpl._binding;
- while (referenceBinding != null) {
- // If referenceBinding is a ParameterizedTypeBinding, this will return only ParameterizedTypeBindings
- // for member types, even if the member happens to be a static nested class. That's probably a bug;
- // static nested classes are not parameterized by their outer class.
- for (ReferenceBinding memberReferenceBinding : referenceBinding.memberTypes()) {
- if (CharOperation.equals(elementBinding.compoundName, memberReferenceBinding.compoundName)) {
- return this._env.getFactory().newTypeMirror(memberReferenceBinding);
- }
- }
- referenceBinding = referenceBinding.superclass();
- }
- break;
- default:
- throw new IllegalArgumentException("element " + element + //$NON-NLS-1$
- " has unrecognized element kind " + element.getKind()); //$NON-NLS-1$
- }
- throw new IllegalArgumentException("element " + element + //$NON-NLS-1$
- " is not a member of the containing type " + containing + //$NON-NLS-1$
- " nor any of its superclasses"); //$NON-NLS-1$
- }
+ public TypeMirror asMemberOf(DeclaredType containing, Element element) {
+ // throw new UnsupportedOperationException("NYI: TypesImpl.asMemberOf("
+ // + containing + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ // //$NON-NLS-3$
+ ElementImpl elementImpl = (ElementImpl) element;
+ DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing;
+ ReferenceBinding referenceBinding = (ReferenceBinding) declaredTypeImpl._binding;
+ TypeMirror typeMirror;
+
+ switch (element.getKind()) {
+ case CONSTRUCTOR:
+ case METHOD:
+ typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
+ @Override
+ public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
+ MethodBinding methodBinding = ((MethodBinding) memberBinding);
+ for (MethodBinding method : typeBinding.methods()) {
+ if (CharOperation.equals(method.selector, methodBinding.selector)
+ && (method.original() == methodBinding
+ || method.areParameterErasuresEqual(methodBinding))) {
+ return TypesImpl.this._env.getFactory().newTypeMirror(method);
+ }
+ }
+ return null;
+ }
+ });
+
+ if (typeMirror != null) {
+ return typeMirror;
+ }
+ break;
+ case FIELD:
+ case ENUM_CONSTANT:
+ typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
+ @Override
+ public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
+ FieldBinding fieldBinding = (FieldBinding) memberBinding;
+ for (FieldBinding field : typeBinding.fields()) {
+ if (CharOperation.equals(field.name, fieldBinding.name)) {
+ return TypesImpl.this._env.getFactory().newTypeMirror(field);
+ }
+ }
+ return null;
+ }
+ });
+
+ if (typeMirror != null) {
+ return typeMirror;
+ }
+ break;
+ case ENUM:
+ case ANNOTATION_TYPE:
+ case INTERFACE:
+ case CLASS:
+
+ typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
+ @Override
+ public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
+ ReferenceBinding elementBinding = (ReferenceBinding) memberBinding;
+ // If referenceBinding is a ParameterizedTypeBinding, this
+ // will return only ParameterizedTypeBindings
+ // for member types, even if the member happens to be a
+ // static nested class. That's probably a bug;
+ // static nested classes are not parameterized by their
+ // outer class.
+ for (ReferenceBinding memberReferenceBinding : typeBinding.memberTypes()) {
+ if (CharOperation.equals(elementBinding.compoundName, memberReferenceBinding.compoundName)) {
+ return TypesImpl.this._env.getFactory().newTypeMirror(memberReferenceBinding);
+ }
+ }
+ return null;
+ }
+ });
+
+ if (typeMirror != null) {
+ return typeMirror;
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("element " + element + //$NON-NLS-1$
+ " has unrecognized element kind " + element.getKind()); //$NON-NLS-1$
+ }
+ throw new IllegalArgumentException("element " + element + //$NON-NLS-1$
+ " is not a member of the containing type " + containing + //$NON-NLS-1$
+ " nor any of its superclasses"); //$NON-NLS-1$
+ }
+
+ private static interface MemberInTypeFinder {
+ TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding);
+ }
+
+ private TypeMirror findMemberInHierarchy(ReferenceBinding typeBinding, Binding memberBinding,
+ MemberInTypeFinder finder) {
+ TypeMirror result = null;
+
+ if (typeBinding == null) {
+ return null;
+ }
+
+ result = finder.find(typeBinding, memberBinding);
+ if (result != null) {
+ return result;
+ }
+
+ result = findMemberInHierarchy(typeBinding.superclass(), memberBinding, finder);
+ if (result != null) {
+ return result;
+ }
+
+ for (ReferenceBinding superInterface : typeBinding.superInterfaces()) {
+ result = findMemberInHierarchy(superInterface, memberBinding, finder);
+ if (result != null) {
+ return result;
+ }
+ }
+
+ return null;
+ }
@Override
public TypeElement boxedClass(PrimitiveType p) {
diff --git a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
index 96bd353..2319696 100644
--- a/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
+++ b/org.eclipse.jdt.core/apt/org/eclipse/jdt/internal/compiler/apt/util/EclipseFileManager.java
@@ -452,7 +452,7 @@
}
uri2 = new URI(uri.getScheme(), uri.getHost(), path, uri.getFragment());
} catch (URISyntaxException e) {
- throw new IllegalArgumentException("invalid sibling");//$NON-NLS-1$
+ throw new IllegalArgumentException("invalid sibling", e);//$NON-NLS-1$
}
return new EclipseFileObject(className, uri2, kind, this.charset);
} else {
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 e1d1283..2bfd704 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
@@ -1223,9 +1223,9 @@
this.log.println("# " + dateFormat.format(date));//$NON-NLS-1$
}
} catch (FileNotFoundException e) {
- throw new IllegalArgumentException(this.main.bind("configure.cannotOpenLog", logFileName)); //$NON-NLS-1$
+ throw new IllegalArgumentException(this.main.bind("configure.cannotOpenLog", logFileName), e); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
- throw new IllegalArgumentException(this.main.bind("configure.cannotOpenLogInvalidEncoding", logFileName)); //$NON-NLS-1$
+ throw new IllegalArgumentException(this.main.bind("configure.cannotOpenLogInvalidEncoding", logFileName), e); //$NON-NLS-1$
}
}
private void startLoggingExtraProblems(int count) {
@@ -1955,7 +1955,7 @@
new InputStreamReader(new ByteArrayInputStream(new byte[0]), customEncoding);
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException(
- this.bind("configure.unsupportedEncoding", customEncoding)); //$NON-NLS-1$
+ this.bind("configure.unsupportedEncoding", customEncoding), e); //$NON-NLS-1$
}
}
currentArg = currentArg.substring(0, encodingStart - 1);
@@ -2547,7 +2547,7 @@
throw new IllegalArgumentException(this.bind("configure.repetition", currentArg)); //$NON-NLS-1$
}
} catch (NumberFormatException e) {
- throw new IllegalArgumentException(this.bind("configure.repetition", currentArg)); //$NON-NLS-1$
+ throw new IllegalArgumentException(this.bind("configure.repetition", currentArg), e); //$NON-NLS-1$
}
mode = DEFAULT;
continue;
@@ -2559,7 +2559,7 @@
}
this.options.put(CompilerOptions.OPTION_MaxProblemPerUnit, currentArg);
} catch (NumberFormatException e) {
- throw new IllegalArgumentException(this.bind("configure.maxProblems", currentArg)); //$NON-NLS-1$
+ throw new IllegalArgumentException(this.bind("configure.maxProblems", currentArg), e); //$NON-NLS-1$
}
mode = DEFAULT;
continue;
@@ -2609,7 +2609,7 @@
new InputStreamReader(new ByteArrayInputStream(new byte[0]), currentArg);
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException(
- this.bind("configure.unsupportedEncoding", currentArg)); //$NON-NLS-1$
+ this.bind("configure.unsupportedEncoding", currentArg), e); //$NON-NLS-1$
}
specifiedEncodings.add(currentArg);
this.options.put(CompilerOptions.OPTION_Encoding, currentArg);
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 7eafeee..23b3817 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 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
@@ -9,9 +9,12 @@
* 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
+ * Stefan Xenos <sxenos@gmail.com> (Google) - Bug 501283 - Lots of hash collisions during indexing
*******************************************************************************/
package org.eclipse.jdt.core.compiler;
+import java.util.Arrays;
+
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
/**
@@ -2281,19 +2284,9 @@
*
* @param array the array for which a hashcode is required
* @return the hashcode
- * @throws NullPointerException if array is null
*/
public static final int hashCode(char[] array) {
- int length = array.length;
- int hash = length == 0 ? 31 : array[0];
- if (length < 8) {
- for (int i = length; --i > 0;)
- hash = (hash * 31) + array[i];
- } else {
- // 8 characters is enough to compute a decent hash code, don't waste time examining every character
- for (int i = length - 1, last = i > 16 ? i - 16 : 0; i > last; i -= 2)
- hash = (hash * 31) + array[i];
- }
+ int hash = Arrays.hashCode(array);
return hash & 0x7FFFFFFF;
}
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 671edcf..c0d8ebd 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
@@ -1894,6 +1894,12 @@
int IllegalDefaultModifierSpecification = MethodRelated + 1058;
/** @since 3.13 */
int CannotInferInvocationType = TypeRelated + 1059;
+
+ /** @since 3.13 */
+ int TypeAnnotationAtQualifiedName = Internal + Syntax + 1060;
+
+ /** @since 3.13 */
+ int NullAnnotationAtQualifyingType = Internal + Syntax + 1061;
/** @since 3.10 */
int GenericInferenceError = 1100; // FIXME: This is just a stop-gap measure, be more specific via https://bugs.eclipse.org/404675
@@ -1901,4 +1907,6 @@
/** @deprecated - problem is no longer generated (implementation issue has been resolved)
* @since 3.10 */
int LambdaShapeComputationError = 1101;
+ /** @since 3.13 */
+ int ProblemNotAnalysed = 1102;
}
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 12639ff..5d4fb85 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
@@ -695,8 +695,11 @@
} else {
updatedArgumentType = argument.resolveType(scope);
}
- if (updatedArgumentType != null && updatedArgumentType.kind() != Binding.POLY_TYPE)
+ if (updatedArgumentType != null && updatedArgumentType.kind() != Binding.POLY_TYPE) {
argumentTypes[i] = updatedArgumentType;
+ if (candidateMethod.isPolymorphic())
+ candidateMethod.parameters[i] = updatedArgumentType;
+ }
}
}
}
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 9606e2b..9f06279 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
@@ -644,7 +644,7 @@
// no need to check annotation usage if missing
return;
}
- if (! isAnnotationTargetAllowed(repeatingAnnotation, scope, containerAnnotationType, repeatingAnnotation.recipient.kind())) {
+ if (isAnnotationTargetAllowed(repeatingAnnotation, scope, containerAnnotationType, repeatingAnnotation.recipient.kind()) != AnnotationTargetAllowed.YES) {
scope.problemReporter().disallowedTargetForContainerAnnotation(repeatingAnnotation, containerAnnotationType);
}
}
@@ -961,63 +961,71 @@
return this.resolvedType;
}
- private static boolean isAnnotationTargetAllowed(Binding recipient, BlockScope scope, TypeBinding annotationType, int kind, long metaTagBits) {
+ public enum AnnotationTargetAllowed {
+ YES, TYPE_ANNOTATION_ON_QUALIFIED_NAME, NO;
+ }
+
+ private static AnnotationTargetAllowed isAnnotationTargetAllowed(Binding recipient, BlockScope scope, TypeBinding annotationType, int kind, long metaTagBits) {
switch (kind) {
case Binding.PACKAGE :
if ((metaTagBits & TagBits.AnnotationForPackage) != 0)
- return true;
+ return AnnotationTargetAllowed.YES;
else if (scope.compilerOptions().sourceLevel <= ClassFileConstants.JDK1_6) {
SourceTypeBinding sourceType = (SourceTypeBinding) recipient;
if (CharOperation.equals(sourceType.sourceName, TypeConstants.PACKAGE_INFO_NAME))
- return true;
+ return AnnotationTargetAllowed.YES;
}
break;
case Binding.TYPE_USE :
if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
// jsr 308
- return true;
+ return AnnotationTargetAllowed.YES;
}
if (scope.compilerOptions().sourceLevel < ClassFileConstants.JDK1_8) {
// already reported as syntax error; don't report secondary problems
- return true;
+ return AnnotationTargetAllowed.YES;
}
break;
case Binding.TYPE :
case Binding.GENERIC_TYPE :
if (((ReferenceBinding)recipient).isAnnotationType()) {
if ((metaTagBits & (TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0)
- return true;
+ return AnnotationTargetAllowed.YES;
} else if ((metaTagBits & (TagBits.AnnotationForType | TagBits.AnnotationForTypeUse)) != 0) {
- return true;
+ return AnnotationTargetAllowed.YES;
} else if ((metaTagBits & TagBits.AnnotationForPackage) != 0) {
if (CharOperation.equals(((ReferenceBinding) recipient).sourceName, TypeConstants.PACKAGE_INFO_NAME))
- return true;
+ return AnnotationTargetAllowed.YES;
}
break;
case Binding.METHOD :
MethodBinding methodBinding = (MethodBinding) recipient;
if (methodBinding.isConstructor()) {
if ((metaTagBits & (TagBits.AnnotationForConstructor | TagBits.AnnotationForTypeUse)) != 0)
- return true;
+ return AnnotationTargetAllowed.YES;
} else if ((metaTagBits & TagBits.AnnotationForMethod) != 0) {
- return true;
+ return AnnotationTargetAllowed.YES;
} else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
SourceTypeBinding sourceType = (SourceTypeBinding) methodBinding.declaringClass;
MethodDeclaration methodDecl = (MethodDeclaration) sourceType.scope.referenceContext.declarationOf(methodBinding);
if (isTypeUseCompatible(methodDecl.returnType, scope)) {
- return true;
+ return AnnotationTargetAllowed.YES;
+ } else {
+ return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME;
}
}
break;
case Binding.FIELD :
if ((metaTagBits & TagBits.AnnotationForField) != 0) {
- return true;
+ return AnnotationTargetAllowed.YES;
} else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
FieldBinding sourceField = (FieldBinding) recipient;
SourceTypeBinding sourceType = (SourceTypeBinding) sourceField.declaringClass;
FieldDeclaration fieldDeclaration = sourceType.scope.referenceContext.declarationOf(sourceField);
if (isTypeUseCompatible(fieldDeclaration.type, scope)) {
- return true;
+ return AnnotationTargetAllowed.YES;
+ } else {
+ return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME;
}
}
break;
@@ -1025,27 +1033,31 @@
LocalVariableBinding localVariableBinding = (LocalVariableBinding) recipient;
if ((localVariableBinding.tagBits & TagBits.IsArgument) != 0) {
if ((metaTagBits & TagBits.AnnotationForParameter) != 0) {
- return true;
+ return AnnotationTargetAllowed.YES;
} else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) {
- return true;
+ return AnnotationTargetAllowed.YES;
+ } else {
+ return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME;
}
}
} else if ((annotationType.tagBits & TagBits.AnnotationForLocalVariable) != 0) {
- return true;
+ return AnnotationTargetAllowed.YES;
} else if ((metaTagBits & TagBits.AnnotationForTypeUse) != 0) {
if (isTypeUseCompatible(localVariableBinding.declaration.type, scope)) {
- return true;
+ return AnnotationTargetAllowed.YES;
+ } else {
+ return AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME;
}
}
break;
case Binding.TYPE_PARAMETER : // jsr308
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=391196
if ((metaTagBits & (TagBits.AnnotationForTypeParameter | TagBits.AnnotationForTypeUse)) != 0) {
- return true;
+ return AnnotationTargetAllowed.YES;
}
}
- return false;
+ return AnnotationTargetAllowed.NO;
}
public static boolean isAnnotationTargetAllowed(BlockScope scope, TypeBinding annotationType, Binding recipient) {
@@ -1053,10 +1065,10 @@
if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) {
return true;
}
- return isAnnotationTargetAllowed(recipient, scope, annotationType, recipient.kind(), metaTagBits);
+ return isAnnotationTargetAllowed(recipient, scope, annotationType, recipient.kind(), metaTagBits)==AnnotationTargetAllowed.YES;
}
- static boolean isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) {
+ static AnnotationTargetAllowed isAnnotationTargetAllowed(Annotation annotation, BlockScope scope, TypeBinding annotationType, int kind) {
long metaTagBits = annotationType.getAnnotationTagBits(); // could be forward reference
if ((metaTagBits & TagBits.AnnotationTargetMASK) == 0) {
@@ -1064,7 +1076,7 @@
if (kind == Binding.TYPE_PARAMETER || kind == Binding.TYPE_USE) {
scope.problemReporter().explitAnnotationTargetRequired(annotation);
}
- return true;
+ return AnnotationTargetAllowed.YES;
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=391201
@@ -1091,8 +1103,13 @@
// no need to check annotation usage if missing
return;
}
- if (! isAnnotationTargetAllowed(annotation, scope, annotationType, kind)) {
+ AnnotationTargetAllowed annotationTargetAllowed = isAnnotationTargetAllowed(annotation, scope, annotationType, kind);
+ if (annotationTargetAllowed != AnnotationTargetAllowed.YES) {
+ if(annotationTargetAllowed == AnnotationTargetAllowed.TYPE_ANNOTATION_ON_QUALIFIED_NAME) {
+ scope.problemReporter().typeAnnotationAtQualifiedName(annotation);
+ } else {
scope.problemReporter().disallowedTargetForAnnotation(annotation);
+ }
if (recipient instanceof TypeBinding)
((TypeBinding)recipient).tagBits &= ~tagBitsToRevert;
}
@@ -1161,7 +1178,7 @@
continue nextAnnotation;
} else {
if (annotation.hasNullBit(TypeIds.BitNonNullAnnotation|TypeIds.BitNullableAnnotation)) {
- scope.problemReporter().nullAnnotationUnsupportedLocation(annotation);
+ scope.problemReporter().nullAnnotationAtQualifyingType(annotation);
continue nextAnnotation;
}
}
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 00b8bea..1c7dafb 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
@@ -267,6 +267,9 @@
}
public boolean checkNPE(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, int ttlForFieldCheck) {
+ if((this.resolvedType.tagBits & TagBits.AnnotationNonNull) != 0) {
+ return true;
+ }
checkNPEbyUnboxing(scope, flowContext, flowInfo);
return this.expression.checkNPE(scope, flowContext, flowInfo, ttlForFieldCheck);
}
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 895ea19..acb079b 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
@@ -299,22 +299,28 @@
Constant cst = inits[iToken].constant;
if (cst != Constant.NotAConstant && cst.typeID() == TypeIds.T_JavaLangString) {
IrritantSet tokenIrritants = CompilerOptions.warningTokenToIrritants(cst.stringValue());
- if (tokenIrritants != null
- && !tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all")
- && options.isAnyEnabled(tokenIrritants) // if irritant is effectively enabled
- && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem
- if (unusedWarningTokenIsWarning) {
- int start = value.sourceStart, end = value.sourceEnd;
- nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) {
- long position = this.suppressWarningScopePositions[jSuppress];
- int startSuppress = (int) (position >>> 32);
- int endSuppress = (int) position;
- if (start < startSuppress) continue nextSuppress;
- if (end > endSuppress) continue nextSuppress;
- if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all?
+ if (tokenIrritants != null) {
+ if (!tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all")
+ && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem
+ if (unusedWarningTokenIsWarning) {
+ int start = value.sourceStart, end = value.sourceEnd;
+ nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) {
+ long position = this.suppressWarningScopePositions[jSuppress];
+ int startSuppress = (int) (position >>> 32);
+ int endSuppress = (int) position;
+ if (start < startSuppress) continue nextSuppress;
+ if (end > endSuppress) continue nextSuppress;
+ if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all?
+ }
+ }
+ int id = options.getIgnoredIrritant(tokenIrritants);
+ if (id > 0) {
+ String key = CompilerOptions.optionKeyFromIrritant(id);
+ this.scope.problemReporter().problemNotAnalysed(inits[iToken], key);
+ } else {
+ this.scope.problemReporter().unusedWarningToken(inits[iToken]);
}
}
- this.scope.problemReporter().unusedWarningToken(inits[iToken]);
}
}
}
@@ -323,22 +329,28 @@
Constant cst = value.constant;
if (cst != Constant.NotAConstant && cst.typeID() == T_JavaLangString) {
IrritantSet tokenIrritants = CompilerOptions.warningTokenToIrritants(cst.stringValue());
- if (tokenIrritants != null
- && !tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all")
- && options.isAnyEnabled(tokenIrritants) // if irritant is effectively enabled
- && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem
- if (unusedWarningTokenIsWarning) {
- int start = value.sourceStart, end = value.sourceEnd;
- nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) {
- long position = this.suppressWarningScopePositions[jSuppress];
- int startSuppress = (int) (position >>> 32);
- int endSuppress = (int) position;
- if (start < startSuppress) continue nextSuppress;
- if (end > endSuppress) continue nextSuppress;
- if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all?
+ if (tokenIrritants != null) {
+ if (!tokenIrritants.areAllSet() // no complaint against @SuppressWarnings("all")
+ && (foundIrritants[iSuppress] == null || !foundIrritants[iSuppress].isAnySet(tokenIrritants))) { // if irritant had no matching problem
+ if (unusedWarningTokenIsWarning) {
+ int start = value.sourceStart, end = value.sourceEnd;
+ nextSuppress: for (int jSuppress = iSuppress - 1; jSuppress >= 0; jSuppress--) {
+ long position = this.suppressWarningScopePositions[jSuppress];
+ int startSuppress = (int) (position >>> 32);
+ int endSuppress = (int) position;
+ if (start < startSuppress) continue nextSuppress;
+ if (end > endSuppress) continue nextSuppress;
+ if (this.suppressWarningIrritants[jSuppress].areAllSet()) break pairLoop; // suppress all?
+ }
+ }
+ int id = options.getIgnoredIrritant(tokenIrritants);
+ if (id > 0) {
+ String key = CompilerOptions.optionKeyFromIrritant(id);
+ this.scope.problemReporter().problemNotAnalysed(value, key);
+ } else {
+ this.scope.problemReporter().unusedWarningToken(value);
}
}
- this.scope.problemReporter().unusedWarningToken(value);
}
}
}
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 ff0850e..789c72d 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
@@ -670,13 +670,13 @@
// Answer the signature return type, answers PolyTypeBinding if a poly expression and there is no target type
// Base type promotion
if (this.constant != Constant.NotAConstant) {
- this.constant = Constant.NotAConstant;
- long sourceLevel = scope.compilerOptions().sourceLevel;
- boolean receiverCast = false;
- if (this.receiver instanceof CastExpression) {
- this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
- receiverCast = true;
- }
+ this.constant = Constant.NotAConstant;
+ long sourceLevel = scope.compilerOptions().sourceLevel;
+ boolean receiverCast = false;
+ if (this.receiver instanceof CastExpression) {
+ this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
+ receiverCast = true;
+ }
// AspectJ Extension: commenting this out for now. An InterTypeScope has been observed
// to have an already resolved receiver
// if (this.receiver.resolvedType != null)
@@ -689,8 +689,11 @@
this.receiverIsType = this.receiver instanceof NameReference && (((NameReference) this.receiver).bits & Binding.TYPE) != 0;
if (receiverCast && this.actualReceiverType != null) {
// due to change of declaring class with receiver type, only identity cast should be notified
- if (TypeBinding.equalsEquals(((CastExpression)this.receiver).expression.resolvedType, this.actualReceiverType)) {
- scope.problemReporter().unnecessaryCast((CastExpression)this.receiver);
+ TypeBinding resolvedType2 = ((CastExpression)this.receiver).expression.resolvedType;
+ if (TypeBinding.equalsEquals(resolvedType2, this.actualReceiverType)) {
+ if (!scope.environment().usesNullTypeAnnotations() || !NullAnnotationMatching.analyse(this.actualReceiverType, resolvedType2, -1).isAnyMismatch()) {
+ scope.problemReporter().unnecessaryCast((CastExpression)this.receiver);
+ }
}
}
// resolve type arguments (for generic constructor call)
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
index 537bcbe..b10f83e 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/QualifiedTypeReference.java
@@ -75,8 +75,15 @@
for (int j = 0; j < i; j++) {
Annotation[] qualifierAnnot = this.annotations[j];
if (qualifierAnnot != null && qualifierAnnot.length > 0) {
- scope.problemReporter().misplacedTypeAnnotations(qualifierAnnot[0], qualifierAnnot[qualifierAnnot.length - 1]);
- this.annotations[j] = null;
+ if (j == 0) {
+ for (int k = 0; k < qualifierAnnot.length; k++) {
+ scope.problemReporter().typeAnnotationAtQualifiedName(qualifierAnnot[k]);
+ }
+ } else {
+ scope.problemReporter().misplacedTypeAnnotations(qualifierAnnot[0],
+ qualifierAnnot[qualifierAnnot.length - 1]);
+ this.annotations[j] = null;
+ }
}
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
index 004ddaf..3a2af2c 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ReferenceExpression.java
@@ -239,7 +239,7 @@
}
// Process the lambda, taking care not to double report diagnostics. Don't expect any from resolve, Any from code generation should surface, but not those from flow analysis.
- implicitLambda.resolve(currentScope);
+ implicitLambda.resolveType(currentScope, true);
IErrorHandlingPolicy oldPolicy = currentScope.problemReporter().switchErrorHandlingPolicy(silentErrorHandlingPolicy);
try {
implicitLambda.analyseCode(currentScope,
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 cf7b55c..fd6da1b 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
@@ -586,7 +586,8 @@
if (an == NULLABLE || an == NONNULL)
start++;
}
- int end = wrapperWithStart(start).computeEnd();
+ SignatureWrapper wrapper1 = wrapperWithStart(start);
+ int end = wrapper1.skipAngleContents(wrapper1.computeEnd());
return end;
}
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 30dbbfc..6e1f66d 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
@@ -2730,7 +2730,7 @@
invoke(Opcodes.OPC_invokevirtual, 1, 1,
ConstantPool.JavaLangInvokeSerializedLambdaConstantPoolName,
ConstantPool.GetCapturedArg, ConstantPool.GetCapturedArgSignature);
- checkcast(isLambda ? mb.declaringClass : ((ReferenceExpression)funcEx).receiverType);
+ checkcast(mb.declaringClass);
sig.append(mb.declaringClass.signature());
}
for (int p = 0, max = outerLocalVariables == null ? 0 : outerLocalVariables.length; p < max; p++) {
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
index 288fb8f..2d5fd51 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 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
@@ -214,7 +214,9 @@
public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
return unconditionalInits().mergedWith(otherInits);
}
-
+public UnconditionalFlowInfo mergeDefiniteInitsWith(UnconditionalFlowInfo otherInits) {
+ return unconditionalInits().mergeDefiniteInitsWith(otherInits);
+}
public UnconditionalFlowInfo nullInfoLessUnconditionalCopy() {
return unconditionalInitsWithoutSideEffect().
nullInfoLessUnconditionalCopy();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
index ad63440..67194d5 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
@@ -538,7 +538,8 @@
unconditionalInits();
// if a variable is only initialized in one branch and not initialized in the other,
// then we need to cast a doubt on its initialization in the merged info
- mergedInfo.definiteInits &= initsWhenFalse.unconditionalCopy().definiteInits;
+ mergedInfo.mergeDefiniteInitsWith(initsWhenFalse.unconditionalCopy());
+
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=415997, classify unreachability precisely, IsElseStatementUnreachable could be due to null analysis
if ((mergedInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 && (initsWhenFalse.tagBits & FlowInfo.UNREACHABLE) == FlowInfo.UNREACHABLE_BY_NULLANALYSIS) {
mergedInfo.tagBits &= ~UNREACHABLE_OR_DEAD;
@@ -558,7 +559,7 @@
unconditionalInits();
// if a variable is only initialized in one branch and not initialized in the other,
// then we need to cast a doubt on its initialization in the merged info
- mergedInfo.definiteInits &= initsWhenTrue.unconditionalCopy().definiteInits;
+ mergedInfo.mergeDefiniteInitsWith(initsWhenTrue.unconditionalCopy());
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=415997, classify unreachability precisely, IsThenStatementUnreachable could be due to null analysis
if ((mergedInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 && (initsWhenTrue.tagBits & FlowInfo.UNREACHABLE) == FlowInfo.UNREACHABLE_BY_NULLANALYSIS) {
mergedInfo.tagBits &= ~UNREACHABLE_OR_DEAD;
@@ -615,6 +616,8 @@
abstract public UnconditionalFlowInfo mergedWith(
UnconditionalFlowInfo otherInits);
+abstract public UnconditionalFlowInfo mergeDefiniteInitsWith(UnconditionalFlowInfo otherInits);
+
/**
* Return a copy of this unconditional flow info, deprived from its null
* info. {@link #DEAD_END DEAD_END} is returned unmodified.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
index 584b45d..916a590 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2014 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 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
@@ -2183,7 +2183,54 @@
public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() {
return this;
}
+public UnconditionalFlowInfo mergeDefiniteInitsWith(UnconditionalFlowInfo otherInits) {
+ if ((otherInits.tagBits & UNREACHABLE_OR_DEAD) != 0 && this != DEAD_END) {
+ return this;
+ }
+ if ((this.tagBits & UNREACHABLE_OR_DEAD) != 0) {
+ return (UnconditionalFlowInfo) otherInits.copy(); // make sure otherInits won't be affected
+ }
+ // intersection of definitely assigned variables,
+ this.definiteInits &= otherInits.definiteInits;
+ if (this.extra != null) {
+ if (otherInits.extra != null) {
+ // both sides have extra storage
+ int i = 0, length, otherLength;
+ if ((length = this.extra[0].length) < (otherLength = otherInits.extra[0].length)) {
+ // current storage is shorter -> grow current
+ for (int j = 0; j < extraLength; j++) {
+ System.arraycopy(this.extra[j], 0,
+ (this.extra[j] = new long[otherLength]), 0, length);
+ }
+ for (; i < length; i++) {
+ this.extra[0][i] &= otherInits.extra[0][i];
+ }
+ for (; i < otherLength; i++) {
+ this.extra[0][i] = otherInits.extra[0][i];
+ }
+ }
+ else {
+ // current storage is longer
+ for (; i < otherLength; i++) {
+ this.extra[0][i] &= otherInits.extra[0][i];
+ }
+ }
+ } else {
+ for (int i = 0; i < this.extra[0].length; i++) {
+ this.extra[0][i] = 0;
+ }
+ }
+ }
+ else if (otherInits.extra != null) {
+ // no storage here, but other has extra storage.
+ int otherLength = otherInits.extra[0].length;
+ createExtraSpace(otherLength);
+ System.arraycopy(otherInits.extra[0], 0, this.extra[0], 0,
+ otherLength);
+ }
+ return this;
+}
public void resetAssignmentInfo(LocalVariableBinding local) {
resetAssignmentInfo(local.id + this.maxFieldCount);
}
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 967230b..3a25dea 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
@@ -614,7 +614,7 @@
case UnqualifiedFieldAccess :
return OPTION_ReportUnqualifiedFieldAccess;
case UnusedDeclaredThrownException :
- return OPTION_ReportUnusedDeclaredThrownExceptionWhenOverriding;
+ return OPTION_ReportUnusedDeclaredThrownException;
case FinallyBlockNotCompleting :
return OPTION_ReportFinallyBlockNotCompletingNormally;
case InvalidJavadoc :
@@ -1277,6 +1277,27 @@
return this.warningThreshold.isAnySet(irritants) || this.errorThreshold.isAnySet(irritants)
|| this.infoThreshold.isAnySet(irritants);
}
+ /*
+ * Just return the first irritant id that is set to 'ignored'.
+ */
+ public int getIgnoredIrritant(IrritantSet irritants) {
+ int[] bits = irritants.getBits();
+ for (int i = 0; i < IrritantSet.GROUP_MAX; i++) {
+ int bit = bits[i];
+ for (int b = 0; b < IrritantSet.GROUP_SHIFT; b++) {
+ int single = bit & (1 << b);
+ if (single > 0) {
+ single |= (i << IrritantSet.GROUP_SHIFT);
+ if (single == MissingNonNullByDefaultAnnotation)
+ continue;
+ if (!(this.warningThreshold.isSet(single) || this.errorThreshold.isSet(single) || this.infoThreshold.isSet(single))) {
+ return single;
+ }
+ }
+ }
+ }
+ return 0;
+ }
protected void resetDefaults() {
// problem default severities defined on IrritantSet
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java
index 54f524d..280a502 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/impl/IrritantSet.java
@@ -259,7 +259,9 @@
int group = (singleGroupIrritants & GROUP_MASK) >> GROUP_SHIFT;
return (this.bits[group] & singleGroupIrritants) != 0;
}
-
+ public int[] getBits() {
+ return this.bits;
+ }
public IrritantSet set(int singleGroupIrritants) {
int group = (singleGroupIrritants & GROUP_MASK) >> GROUP_SHIFT;
this.bits[group] |= (singleGroupIrritants & ~GROUP_MASK); // erase the group bits
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 9b7b03c..17312a2 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
@@ -15,6 +15,8 @@
package org.eclipse.jdt.internal.compiler.lookup;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.*;
@@ -60,6 +62,8 @@
boolean connectingHierarchy;
private ArrayList<Invocation> inferredInvocations;
+ /** Cache of interned inference variables. Access only via {@link InferenceVariable#get(TypeBinding, int, InvocationSite, Scope, ReferenceBinding)}. */
+ Map<InferenceVariable.InferenceVarKey, InferenceVariable> uniqueInferenceVariables = new HashMap<>();
public CompilationUnitScope(CompilationUnitDeclaration unit, LookupEnvironment environment) {
super(COMPILATION_UNIT_SCOPE, 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 f359f9c..2e127a7 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
@@ -292,7 +292,7 @@
this.environment.getNonNullAnnotationName());
break returnType;
} else {
- scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, useTypeAnnotations);
+ scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, useTypeAnnotations);
return;
}
}
@@ -308,7 +308,7 @@
scope.problemReporter().illegalReturnRedefinition(srcMethod, inheritedMethod,
this.environment.getNonNullAnnotationName());
else
- scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, useTypeAnnotations);
+ scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, useTypeAnnotations);
return;
}
}
@@ -400,7 +400,7 @@
inheritedMethod.declaringClass,
(inheritedNonNullNess == null) ? null : this.environment.getNullableAnnotationName());
} else {
- scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false);
+ scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, false);
}
continue;
} else if (currentNonNullNess == null)
@@ -413,7 +413,7 @@
inheritedMethod.declaringClass,
annotationName);
} else {
- scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false);
+ scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, false);
}
continue;
} else if (inheritedNonNullNess == Boolean.TRUE) {
@@ -438,7 +438,7 @@
if (currentArgument != null)
scope.problemReporter().illegalParameterRedefinition(currentArgument, inheritedMethod.declaringClass, inheritedParameter);
else
- scope.problemReporter().cannotImplementIncompatibleNullness(currentMethod, inheritedMethod, false);
+ scope.problemReporter().cannotImplementIncompatibleNullness(scope.referenceContext(), currentMethod, inheritedMethod, false);
}
}
}
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 07851ae..f30d941 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
@@ -130,7 +130,6 @@
/** The inference variables for which as solution is sought. */
InferenceVariable[] inferenceVariables;
- int nextVarId;
/** Constraints that have not yet been reduced and incorporated. */
ConstraintFormula[] initialConstraints;
@@ -164,43 +163,12 @@
/** Not per JLS: signal when current is ready to directly merge all bounds from inner. */
private boolean directlyAcceptingInnerBounds = false;
- // InferenceVariable interning:
- private InferenceVariable[] internedVariables;
-
- private InferenceVariable getInferenceVariable(TypeBinding typeParameter, int rank, InvocationSite site) {
- InferenceContext18 outermostContext = this.environment.currentInferenceContext;
- if (outermostContext == null)
- outermostContext = this;
- int i = 0;
- InferenceVariable[] interned = outermostContext.internedVariables;
- if (interned == null) {
- outermostContext.internedVariables = new InferenceVariable[10];
- } else {
- int len = interned.length;
- for (i = 0; i < len; i++) {
- InferenceVariable var = interned[i];
- if (var == null)
- break;
- if (var.typeParameter == typeParameter && var.rank == rank && isSameSite(var.site, site)) //$IDENTITY-COMPARISON$
- return var;
- }
- if (i >= len)
- System.arraycopy(interned, 0, outermostContext.internedVariables = new InferenceVariable[len+10], 0, len);
- }
- boolean differentContext = outermostContext != this;
- int id = differentContext ? Math.max(this.nextVarId, outermostContext.nextVarId) : this.nextVarId;
- this.nextVarId = id + 1;
- if (differentContext)
- outermostContext.nextVarId = this.nextVarId;
- return outermostContext.internedVariables[i] = new InferenceVariable(typeParameter, rank, id, site, this.environment, this.object);
- }
-
- boolean isSameSite(InvocationSite site1, InvocationSite site2) {
+ public static boolean isSameSite(InvocationSite site1, InvocationSite site2) {
if (site1 == site2)
return true;
if (site1 == null || site2 == null)
return false;
- if (site1.sourceStart() == site2.sourceStart() && site1.sourceEnd() == site2.sourceEnd() && site1.toString().equals(site2.toString()))
+ if (site1.sourceStart() == site2.sourceStart() && site1.sourceEnd() == site2.sourceEnd())
return true;
return false;
}
@@ -336,7 +304,7 @@
}
InferenceVariable[] newVariables = new InferenceVariable[len];
for (int i = 0; i < len; i++)
- newVariables[i] = getInferenceVariable(typeVariables[i], i, this.currentInvocation);
+ newVariables[i] = InferenceVariable.get(typeVariables[i], i, this.currentInvocation, this.scope, this.object);
addInferenceVariables(newVariables);
return newVariables;
}
@@ -364,7 +332,7 @@
newVariables[i] = (InferenceVariable) typeVariables[i]; // prevent double substitution of an already-substituted inferenceVariable
else
toAdd[numToAdd++] =
- newVariables[i] = getInferenceVariable(typeVariables[i], i, this.currentInvocation);
+ newVariables[i] = InferenceVariable.get(typeVariables[i], i, this.currentInvocation, this.scope, this.object);
}
if (numToAdd > 0) {
int start = 0;
@@ -1565,18 +1533,6 @@
if (!isSameSite(innerCtx.currentInvocation, this.currentInvocation))
innerCtx.outerContext = this;
this.usesUncheckedConversion = innerCtx.usesUncheckedConversion;
- for (InferenceVariable variable : this.inferenceVariables)
- if (!isInterned(variable))
- variable.updateSourceName(this.nextVarId++);
- }
-
- boolean isInterned(InferenceVariable iv) {
- if (this.internedVariables != null)
- for (int i = 0; i < this.internedVariables.length; i++) {
- if (this.internedVariables[i] == iv) //$IDENTITY-COMPARISON$
- return true;
- }
- return false;
}
public void resumeSuspendedInference(SuspendedInferenceRecord record) {
@@ -1589,8 +1545,6 @@
// move to back, add previous to front:
System.arraycopy(this.inferenceVariables, 0, this.inferenceVariables=new InferenceVariable[l1+l2], l2, l1);
System.arraycopy(record.inferenceVariables, 0, this.inferenceVariables, 0, l2);
- for (int i=l1;i<l1+l2;i++)
- this.inferenceVariables[i].updateSourceName(this.nextVarId++);
}
// replace invocation site & arguments:
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java
index 180f770..d482c7a 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceSubstitution.java
@@ -36,7 +36,7 @@
public TypeBinding substitute(Substitution substitution, TypeBinding originalType) {
for (int i = 0; i < this.variables.length; i++) {
InferenceVariable variable = this.variables[i];
- if (this.site == variable.site && TypeBinding.equalsEquals(getP(i), originalType)) {
+ if (InferenceContext18.isSameSite(this.site, variable.site) && TypeBinding.equalsEquals(getP(i), originalType)) {
if (this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled && originalType.hasNullTypeAnnotations())
return this.environment.createAnnotatedType(variable.withoutToplevelNullAnnotation(), originalType.getTypeAnnotations());
return variable;
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
index b999b85..6b78a5f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceVariable.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.lookup;
+import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.core.compiler.CharOperation;
@@ -18,14 +19,74 @@
* Implementation of 18.1.1 in JLS8
*/
public class InferenceVariable extends TypeVariableBinding {
+
+ /** Structured key for interning. */
+ static class InferenceVarKey {
+ /*@NonNull*/ TypeBinding typeParameter;
+ long position;
+ int rank;
+ InferenceVarKey(TypeBinding typeParameter, InvocationSite site, int rank) {
+ this.typeParameter = typeParameter;
+ this.position = ((long) site.sourceStart() << 32) + site.sourceEnd();
+ this.rank = rank;
+ }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (int) (this.position ^ (this.position >>> 32));
+ result = prime * result + this.rank;
+ result = prime * result + this.typeParameter.id;
+ return result;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (!(obj instanceof InferenceVarKey))
+ return false;
+ InferenceVarKey other = (InferenceVarKey) obj;
+ if (this.position != other.position)
+ return false;
+ if (this.rank != other.rank)
+ return false;
+ if (TypeBinding.notEquals(this.typeParameter, other.typeParameter))
+ return false;
+ return true;
+ }
+ }
+
+ /**
+ * Create or retrieve the inference variable representing the given typeParameter.
+ * Inference variables are interned to avoid duplication due to lambda copying.
+ */
+ public static InferenceVariable get(TypeBinding typeParameter, int rank, InvocationSite site, Scope scope, ReferenceBinding object) {
+ Map<InferenceVarKey, InferenceVariable> uniqueInferenceVariables = scope.compilationUnitScope().uniqueInferenceVariables;
+ InferenceVariable var = null;
+ InferenceVarKey key = null;
+ if (site != null && typeParameter != null) {
+ key = new InferenceVarKey(typeParameter, site, rank);
+ var = uniqueInferenceVariables.get(key);
+ }
+ if (var == null) {
+ int newVarId = uniqueInferenceVariables.size();
+ var = new InferenceVariable(typeParameter, rank, newVarId, site, scope.environment(), object);
+ if (key != null)
+ uniqueInferenceVariables.put(key, var);
+ }
+ return var;
+ }
+
InvocationSite site;
TypeBinding typeParameter;
long nullHints; // one of TagBits.{AnnotationNonNull,AnnotationNullable} may steer inference into inferring nullness as well; set both bits to request avoidance.
private InferenceVariable prototype;
- int varId; // this is used for constructing a source name like T#0. NB: varId and sourceName are mutable, to be updated when two InferenceContext18 are integrated.
+ int varId; // this is used for constructing a source name like T#0.
- public InferenceVariable(TypeBinding typeParameter, int parameterRank, int iVarId, InvocationSite site, LookupEnvironment environment, ReferenceBinding object) {
+ private InferenceVariable(TypeBinding typeParameter, int parameterRank, int iVarId, InvocationSite site, LookupEnvironment environment, ReferenceBinding object) {
this(typeParameter, parameterRank, site,
CharOperation.concat(typeParameter.shortReadableName(), Integer.toString(iVarId).toCharArray(), '#'),
environment, object);
@@ -49,15 +110,7 @@
this.superclass = object;
this.prototype = this;
}
- void updateSourceName(int newId) {
- int hashPos = CharOperation.indexOf('#', this.sourceName);
- this.varId = newId;
- this.sourceName = CharOperation.concat(
- CharOperation.subarray(this.sourceName, 0, hashPos),
- Integer.toString(this.varId).toCharArray(),
- '#');
- }
-
+
@Override
public TypeBinding clone(TypeBinding enclosingType) {
InferenceVariable clone = new InferenceVariable(this.typeParameter, this.rank, this.site, this.sourceName, this.environment, this.superclass);
@@ -131,17 +184,18 @@
public int hashCode() {
int code = this.typeParameter.hashCode() + 17 * this.rank;
- if (this.site != null)
- return 31 * code + this.site.hashCode();
- else
- return code;
+ if (this.site != null) {
+ code = 31 * code + this.site.sourceStart();
+ code = 31 * code + this.site.sourceEnd();
+ }
+ return code;
}
public boolean equals(Object obj) {
if (!(obj instanceof InferenceVariable))
return false;
InferenceVariable other = (InferenceVariable) obj;
return this.rank == other.rank
- && this.site == other.site
+ && InferenceContext18.isSameSite(this.site, other.site)
&& TypeBinding.equalsEquals(this.typeParameter, other.typeParameter);
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
index 67faad1..55cc090 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodBinding.java
@@ -569,12 +569,16 @@
//pre: null annotation analysis is enabled
protected void fillInDefaultNonNullness18(AbstractMethodDeclaration sourceMethod, LookupEnvironment env) {
+ MethodBinding original = original();
+ if(original == null) {
+ return;
+ }
if (hasNonNullDefaultFor(DefaultLocationParameter, true)) {
boolean added = false;
int length = this.parameters.length;
for (int i = 0; i < length; i++) {
TypeBinding parameter = this.parameters[i];
- if (!parameter.acceptsNonNullDefault())
+ if (!original.parameters[i].acceptsNonNullDefault())
continue;
long existing = parameter.tagBits & TagBits.AnnotationNullMASK;
if (existing == 0L) {
@@ -592,7 +596,7 @@
if (added)
this.tagBits |= TagBits.HasParameterAnnotations;
}
- if (this.returnType != null && hasNonNullDefaultFor(DefaultLocationReturnType, true) && this.returnType.acceptsNonNullDefault()) {
+ if (original.returnType != null && hasNonNullDefaultFor(DefaultLocationReturnType, true) && original.returnType.acceptsNonNullDefault()) {
if ((this.returnType.tagBits & TagBits.AnnotationNullMASK) == 0) {
this.returnType = env.createAnnotatedType(this.returnType, new AnnotationBinding[]{env.getNonNullAnnotation()});
} else if (sourceMethod instanceof MethodDeclaration && (this.returnType.tagBits & TagBits.AnnotationNonNull) != 0
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 aea2423..bbd02d3 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
@@ -60,6 +60,12 @@
*/
public static MethodBinding computeCompatibleMethod(MethodBinding originalMethod, TypeBinding[] arguments, Scope scope, InvocationSite invocationSite)
{
+ LookupEnvironment environment = scope.environment();
+ if ((originalMethod.tagBits & TagBits.IsNullnessKnown) == 0) {
+ // ensure nullness of originalMethod is known (but we are not interested in reporting problems against originalMethod)
+ new ImplicitNullAnnotationVerifier(environment, environment.globalOptions.inheritNullAnnotations)
+ .checkImplicitNullAnnotations(originalMethod, null/*srcMethod*/, false, scope);
+ }
ParameterizedGenericMethodBinding methodSubstitute;
TypeVariableBinding[] typeVariables = originalMethod.typeVariables;
TypeBinding[] substitutes = invocationSite.genericTypeArguments();
@@ -72,7 +78,7 @@
// incompatible due to wrong arity
return new ProblemMethodBinding(originalMethod, originalMethod.selector, substitutes, ProblemReasons.TypeParameterArityMismatch);
}
- methodSubstitute = scope.environment().createParameterizedGenericMethod(originalMethod, substitutes);
+ methodSubstitute = environment.createParameterizedGenericMethod(originalMethod, substitutes);
break computeSubstitutes;
}
// perform type argument inference (15.12.2.7)
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 40cae44..20639ff 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
@@ -1149,7 +1149,7 @@
else // WildcardBinding, CaptureBinding have no sourceName
nameBuffer.append(this.type.readableName());
}
- if (this.arguments != null && this.arguments.length > 0) { // empty arguments array happens when PTB has been created just to capture type annotations
+ if (this.arguments != null && this.arguments.length > 0 && !isRawType()) { // empty arguments array happens when PTB has been created just to capture type annotations
nameBuffer.append('<');
for (int i = 0, length = this.arguments.length; i < length; i++) {
if (i > 0) nameBuffer.append(',');
@@ -1177,7 +1177,7 @@
else // WildcardBinding, CaptureBinding have no sourceName
nameBuffer.append(this.type.shortReadableName());
}
- if (this.arguments != null && this.arguments.length > 0) { // empty arguments array happens when PTB has been created just to capture type annotations
+ if (this.arguments != null && this.arguments.length > 0 && !isRawType()) { // empty arguments array happens when PTB has been created just to capture type annotations
nameBuffer.append('<');
for (int i = 0, length = this.arguments.length; i < length; i++) {
if (i > 0) nameBuffer.append(',');
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 8c7c2c7..965f055 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
@@ -18,7 +18,6 @@
import java.util.HashMap;
-import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
import org.eclipse.jdt.internal.compiler.util.Util;
@@ -168,19 +167,7 @@
urb = (UnresolvedReferenceBinding) type;
ReferenceBinding resolvedType = urb.resolvedType;
if (resolvedType != null) {
- if(CharOperation.indexOf('$', type.sourceName()) > 0) {
- type = this.environment.convertToRawType(resolvedType, false);
- } else {
- 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;
- }
+ type = resolvedType;
}
}
try {
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 0fe0324..9386b62 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
@@ -984,7 +984,6 @@
TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization();
for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) {
TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i];
- if (annotatedType.firstBound == null)
annotatedType.firstBound = firstBound;
}
}
@@ -1001,7 +1000,6 @@
TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization();
for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) {
TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i];
- if (annotatedType.superclass == null)
annotatedType.superclass = superclass;
}
}
@@ -1016,7 +1014,6 @@
TypeBinding [] annotatedTypes = getDerivedTypesForDeferredInitialization();
for (int i = 0, length = annotatedTypes == null ? 0 : annotatedTypes.length; i < length; i++) {
TypeVariableBinding annotatedType = (TypeVariableBinding) annotatedTypes[i];
- if (annotatedType.superInterfaces == null)
annotatedType.superInterfaces = superInterfaces;
}
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java
index 5fecec4..2a1fd28 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/parser/AbstractCommentParser.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2013 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 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
@@ -172,7 +172,13 @@
}
this.lineEnd = (this.linePtr == this.lastLinePtr) ? this.javadocEnd: this.scanner.getLineEnd(this.linePtr) - 1;
this.javadocTextEnd = this.javadocEnd - 2; // supposed text end, it will be refined later...
-
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345
+ // when parsing tags such as @code and @literal,
+ // any tag should be discarded and considered as plain text until
+ // properly closed with closing brace
+ boolean considerTagAsPlainText = false;
+ // internal counter for opening braces
+ int openingBraces = 0;
// Loop on each comment character
int textEndPosition = -1;
while (!this.abort && this.index < this.javadocEnd) {
@@ -208,7 +214,20 @@
switch (nextCharacter) {
case '@' :
// Start tag parsing only if we are on line beginning or at inline tag beginning
- if ((!this.lineStarted || previousChar == '{')) {
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345: ignore all tags when inside @literal or @code tags
+ if (considerTagAsPlainText) {
+ // new tag found
+ if (!this.lineStarted) {
+ // we may want to report invalid syntax when no closing brace found,
+ // or when incoherent number of closing braces found
+ if (openingBraces > 0 && this.reportProblems) {
+ this.sourceParser.problemReporter().javadocUnterminatedInlineTag(this.inlineTagStart, invalidInlineTagLineEnd);
+ }
+ considerTagAsPlainText = false;
+ this.inlineTagStarted = false;
+ openingBraces = 0;
+ }
+ } else if ((!this.lineStarted || previousChar == '{')) {
if (this.inlineTagStarted) {
setInlineTagStarted(false);
// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53279
@@ -252,6 +271,12 @@
invalidTagLineEnd = this.lineEnd;
textEndPosition = this.index;
}
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345
+ // dealing with @literal or @code tags: ignore next tags
+ if (!isFormatterParser && (this.tagValue == TAG_LITERAL_VALUE || this.tagValue == TAG_CODE_VALUE)) {
+ considerTagAsPlainText = true;
+ openingBraces++;
+ }
} catch (InvalidInputException e) {
consumeToken();
}
@@ -284,13 +309,24 @@
if (verifText && this.tagValue == TAG_RETURN_VALUE && this.returnStatement != null) {
refreshReturnStatement();
}
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345: when ignoring tags, only decrement the opening braces counter
+ if (considerTagAsPlainText) {
+ invalidInlineTagLineEnd = this.lineEnd;
+ if (--openingBraces == 0) {
+ considerTagAsPlainText = false; // re-enable tag validation
+ }
+ }
if (this.inlineTagStarted) {
textEndPosition = this.index - 1;
- if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) {
- pushText(this.textStart, textEndPosition);
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345: do not push text yet if ignoring tags
+ if (!considerTagAsPlainText) {
+ if (this.lineStarted && this.textStart != -1 && this.textStart < textEndPosition) {
+ pushText(this.textStart, textEndPosition);
+ }
+ refreshInlineTagPosition(previousPosition);
}
- refreshInlineTagPosition(previousPosition);
- if (!isFormatterParser) this.textStart = this.index;
+ if (!isFormatterParser && !considerTagAsPlainText)
+ this.textStart = this.index;
setInlineTagStarted(false);
} else {
if (!this.lineStarted) {
@@ -304,7 +340,10 @@
if (verifText && this.tagValue == TAG_RETURN_VALUE && this.returnStatement != null) {
refreshReturnStatement();
}
- if (this.inlineTagStarted) {
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345: count opening braces when ignoring tags
+ if (considerTagAsPlainText) {
+ openingBraces++;
+ } else if (this.inlineTagStarted) {
setInlineTagStarted(false);
// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53279
// Cannot have opening brace in inline comment
@@ -325,7 +364,8 @@
this.textStart = previousPosition;
}
this.lineStarted = true;
- this.inlineTagStart = previousPosition;
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345: do not update tag start position when ignoring tags
+ if (!considerTagAsPlainText) this.inlineTagStart = previousPosition;
break;
case '*' :
// Store the star position as text start while formatting
@@ -395,7 +435,8 @@
// bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=53279
// Cannot leave comment inside inline comment
- if (this.inlineTagStarted) {
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206345: handle unterminated @code or @literal tag
+ if (this.inlineTagStarted || considerTagAsPlainText) {
if (this.reportProblems) {
int end = this.javadocTextEnd<invalidInlineTagLineEnd ? this.javadocTextEnd : invalidInlineTagLineEnd;
if (this.index >= this.javadocEnd) end = invalidInlineTagLineEnd;
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 12822b2..28f8c44 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
@@ -1594,6 +1594,8 @@
return ProblemSeverities.Warning;
case IProblem.IllegalUseOfUnderscoreAsAnIdentifier:
return this.underScoreIsLambdaParameter ? ProblemSeverities.Error : ProblemSeverities.Warning;
+ case IProblem.ProblemNotAnalysed:
+ return ProblemSeverities.Info; // Not configurable
}
int irritant = getIrritant(problemID);
if (irritant != 0) {
@@ -5861,6 +5863,19 @@
severity,
annotation.sourceStart, annotation.sourceEnd);
}
+public void nullAnnotationAtQualifyingType(Annotation annotation) {
+ String[] arguments = new String[] {
+ String.valueOf(annotation.resolvedType.readableName())
+ };
+ String[] shortArguments = new String[] {
+ String.valueOf(annotation.resolvedType.shortReadableName())
+ };
+ int severity = ProblemSeverities.Error | ProblemSeverities.Fatal;
+ handle(IProblem.NullAnnotationAtQualifyingType,
+ arguments, shortArguments,
+ severity,
+ annotation.sourceStart, annotation.sourceEnd);
+}
public void nullAnnotationUnsupportedLocation(TypeReference type) {
int sourceEnd = type.sourceEnd;
if (type instanceof ParameterizedSingleTypeReference) {
@@ -8952,6 +8967,14 @@
token.sourceStart,
token.sourceEnd);
}
+public void problemNotAnalysed(Expression token, String optionKey) {
+ this.handle(
+ IProblem.ProblemNotAnalysed,
+ optionKey != null ? new String[]{optionKey} : new String[]{},
+ new String[] { token.constant.stringValue() },
+ token.sourceStart,
+ token.sourceEnd);
+}
public void useAssertAsAnIdentifier(int sourceStart, int sourceEnd) {
this.handle(
IProblem.UseAssertAsAnIdentifier,
@@ -9643,11 +9666,11 @@
location.sourceEnd);
}
-public void cannotImplementIncompatibleNullness(MethodBinding currentMethod, MethodBinding inheritedMethod, boolean showReturn) {
+public void cannotImplementIncompatibleNullness(ReferenceContext context, MethodBinding currentMethod, MethodBinding inheritedMethod, boolean showReturn) {
int sourceStart = 0, sourceEnd = 0;
- if (this.referenceContext instanceof TypeDeclaration) {
- sourceStart = ((TypeDeclaration) this.referenceContext).sourceStart;
- sourceEnd = ((TypeDeclaration) this.referenceContext).sourceEnd;
+ if (context instanceof TypeDeclaration) {
+ sourceStart = ((TypeDeclaration) context).sourceStart;
+ sourceEnd = ((TypeDeclaration) context).sourceEnd;
}
String[] problemArguments = {
showReturn
@@ -10416,6 +10439,10 @@
annotation.sourceStart,
annotation.sourceEnd);
}
+public void typeAnnotationAtQualifiedName(Annotation annotation) {
+ this.handle(IProblem.TypeAnnotationAtQualifiedName, NoArgument, NoArgument, annotation.sourceStart,
+ annotation.sourceEnd);
+ }
public void genericInferenceError(String message, InvocationSite invocationSite) {
genericInferenceProblem(message, invocationSite, ProblemSeverities.Error);
}
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 4746474..d07d1ee 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
@@ -862,9 +862,12 @@
1057 = strictfp is not permitted for abstract interface method {0}
1058 = Default methods are allowed only in interfaces.
1059 = Cannot infer type argument(s) for <{0}> {1}
+1060 = Illegally placed annotation: type annotations must directly precede the simple name of the type they are meant to affect (or the [] for arrays)
+1061 = The nullness annotation ''{0}'' is not applicable at this location, it must be placed directly before the nested type name.
1100 = Problem detected during type inference: {0}
-
+#1101 is already used up but deprecated
+1102 = At least one of the problems in category ''{0}'' is not analysed due to a compiler option being ignored
### ELABORATIONS
## Access restrictions
78592 = The type ''{1}'' is not API (restriction on classpath entry ''{0}'')
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
index e033637..818bb0b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/util/Util.java
@@ -1198,7 +1198,7 @@
count++;
}
} catch (ArrayIndexOutOfBoundsException e) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
}
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
index 7757fed..aae7faa 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/AST.java
@@ -503,7 +503,7 @@
return (CompilationUnit) result;
} catch (IllegalStateException e) {
// convert ASTParser's complaints into old form
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
}
}
@@ -577,7 +577,7 @@
return (CompilationUnit) result;
} catch (IllegalStateException e) {
// convert ASTParser's complaints into old form
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
}
}
@@ -815,21 +815,19 @@
} catch (NoSuchMethodException e) {
// all AST node classes have a Foo(AST) constructor
// therefore nodeClass is not legit
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
} catch (InstantiationException e) {
// all concrete AST node classes can be instantiated
// therefore nodeClass is not legit
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
// all AST node classes have an accessible Foo(AST) constructor
// therefore nodeClass is not legit
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
// concrete AST node classes do not die in the constructor
// therefore nodeClass is not legit
- IllegalArgumentException iae = new IllegalArgumentException();
- iae.initCause(e.getCause());
- throw iae;
+ throw new IllegalArgumentException(e.getCause());
}
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
index fa4e478..4452ea6 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/ASTParser.java
@@ -299,7 +299,7 @@
throw new IllegalStateException("invalid environment settings"); //$NON-NLS-1$
}
} catch (IllegalArgumentException e) {
- throw new IllegalStateException("invalid environment settings"); //$NON-NLS-1$
+ throw new IllegalStateException("invalid environment settings", e); //$NON-NLS-1$
}
return allClasspaths;
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java
index b4b1da6..512a8d0 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/CharacterLiteral.java
@@ -286,7 +286,7 @@
throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
}
} catch (InvalidInputException e) {
- throw new IllegalArgumentException("illegal character literal");//$NON-NLS-1$
+ throw new IllegalArgumentException("illegal character literal", e);//$NON-NLS-1$
}
}
nextChar = scanner.getNextChar();
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 15ca187..bbb9ab2 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
@@ -769,7 +769,7 @@
throw new IllegalArgumentException(element + " has an unexpected type"); //$NON-NLS-1$
binaryElementPositions.put(key, i);
} catch (JavaModelException e) {
- throw new IllegalArgumentException(element + " does not exist"); //$NON-NLS-1$
+ throw new IllegalArgumentException(element + " does not exist", e); //$NON-NLS-1$
}
}
}
@@ -792,7 +792,7 @@
try {
finder.search();
} catch (JavaModelException e) {
- throw new IllegalArgumentException(element + " does not exist"); //$NON-NLS-1$
+ throw new IllegalArgumentException(element + " does not exist", e); //$NON-NLS-1$
}
this.bindings[index] = finder.foundBinding;
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java
index 1136b34..6bb5390 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DocCommentParser.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2013 IBM Corporation and others.
+ * Copyright (c) 2004, 2016 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
@@ -427,6 +427,9 @@
if (length == TAG_CATEGORY_LENGTH && CharOperation.equals(TAG_CATEGORY, tagName)) {
this.tagValue = TAG_CATEGORY_VALUE;
valid = parseIdentifierTag(false); // TODO (frederic) reconsider parameter value when @category will be significant in spec
+ } else if (length == TAG_CODE_LENGTH && CharOperation.equals(TAG_CODE, tagName)) {
+ this.tagValue = TAG_CODE_VALUE;
+ createTag();
} else {
this.tagValue = TAG_OTHERS_VALUE;
createTag();
@@ -490,8 +493,11 @@
this.tagValue = TAG_LINK_VALUE;
} else if (length == TAG_LINKPLAIN_LENGTH && CharOperation.equals(TAG_LINKPLAIN, tagName)) {
this.tagValue = TAG_LINKPLAIN_VALUE;
+ } else if (length == TAG_LITERAL_LENGTH && CharOperation.equals(TAG_LITERAL, tagName)) {
+ this.tagValue = TAG_LITERAL_VALUE;
}
- if (this.tagValue != NO_TAG_VALUE) {
+
+ if (this.tagValue != NO_TAG_VALUE && this.tagValue != TAG_LITERAL_VALUE) {
if (this.inlineTagStarted) {
valid = parseReference();
} else {
@@ -500,7 +506,7 @@
valid = false;
}
} else {
- this.tagValue = TAG_OTHERS_VALUE;
+ if (this.tagValue == NO_TAG_VALUE) this.tagValue = TAG_OTHERS_VALUE;
createTag();
}
break;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Javadoc.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Javadoc.java
index 85ae7ff..4d4abe5 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Javadoc.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Javadoc.java
@@ -264,7 +264,7 @@
throw new IllegalArgumentException();
}
} catch (InvalidInputException e) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
}
preValueChange(COMMENT_PROPERTY);
this.comment = docComment;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleName.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleName.java
index 60dab87..fda05fb 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleName.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/SimpleName.java
@@ -199,9 +199,7 @@
throw new IllegalArgumentException("Invalid identifier : >" + identifier + "<"); //$NON-NLS-1$//$NON-NLS-2$
}
} catch (InvalidInputException e) {
- IllegalArgumentException iae = new IllegalArgumentException("Invalid identifier : >" + identifier + "<"); //$NON-NLS-1$//$NON-NLS-2$
- iae.initCause(e);
- throw iae;
+ throw new IllegalArgumentException("Invalid identifier : >" + identifier + "<", e); //$NON-NLS-1$//$NON-NLS-2$
}
} finally {
this.ast.scanner.sourceLevel = sourceLevel;
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Statement.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Statement.java
index dffc912..60ba518 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Statement.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/Statement.java
@@ -155,7 +155,7 @@
throw new IllegalArgumentException();
}
} catch (InvalidInputException e) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
}
}
// we do not consider the obsolete comment as a structureal property
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
index fb0571a..7ecfa08 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteAnalyzer.java
@@ -4346,8 +4346,6 @@
}
final void handleException(Throwable e) {
- IllegalArgumentException runtimeException= new IllegalArgumentException("Document does not match the AST"); //$NON-NLS-1$
- runtimeException.initCause(e);
- throw runtimeException;
+ throw new IllegalArgumentException("Document does not match the AST", e); //$NON-NLS-1$
}
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java
index 2bd730c..efb8893 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/internal/core/dom/rewrite/ASTRewriteFormatter.java
@@ -429,7 +429,7 @@
try {
doc.addPosition(POS_CATEGORY, positions[i]);
} catch (BadLocationException e) {
- throw new IllegalArgumentException("Position outside of string. offset: " + positions[i].offset + ", length: " + positions[i].length + ", string size: " + string.length()); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ throw new IllegalArgumentException("Position outside of string. offset: " + positions[i].offset + ", length: " + positions[i].length + ", string size: " + string.length(), e); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
}
}
}
diff --git a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
index adb1566..987a744 100644
--- a/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
+++ b/org.eclipse.jdt.core/formatter/org/eclipse/jdt/core/formatter/DefaultCodeFormatterConstants.java
@@ -4408,7 +4408,7 @@
int existingValue = Integer.parseInt(value);
return (existingValue & Alignment.M_FORCE) != 0;
} catch (NumberFormatException e) {
- throw new IllegalArgumentException("Alignment value is not an integer: " + value); //$NON-NLS-1$
+ throw new IllegalArgumentException("Alignment value is not an integer: " + value, e); //$NON-NLS-1$
}
}
@@ -4435,7 +4435,7 @@
return INDENT_DEFAULT;
}
} catch (NumberFormatException e) {
- throw new IllegalArgumentException("Alignment value is not an integer: " + value); //$NON-NLS-1$
+ throw new IllegalArgumentException("Alignment value is not an integer: " + value, e); //$NON-NLS-1$
}
}
@@ -4478,7 +4478,7 @@
return WRAP_NO_SPLIT;
}
} catch (NumberFormatException e) {
- throw new IllegalArgumentException("Alignment value is not an integer: " + value); //$NON-NLS-1$
+ throw new IllegalArgumentException("Alignment value is not an integer: " + value, e); //$NON-NLS-1$
}
}
/**
@@ -4504,7 +4504,7 @@
}
return String.valueOf(existingValue);
} catch (NumberFormatException e) {
- throw new IllegalArgumentException("Alignment value is not an integer: " + value); //$NON-NLS-1$
+ throw new IllegalArgumentException("Alignment value is not an integer: " + value, e); //$NON-NLS-1$
}
}
@@ -4547,7 +4547,7 @@
}
return String.valueOf(existingValue);
} catch (NumberFormatException e) {
- throw new IllegalArgumentException("Alignment value is not an integer: " + value); //$NON-NLS-1$
+ throw new IllegalArgumentException("Alignment value is not an integer: " + value, e); //$NON-NLS-1$
}
}
/**
@@ -4605,7 +4605,7 @@
}
return String.valueOf(existingValue);
} catch (NumberFormatException e) {
- throw new IllegalArgumentException("Alignment value is not an integer: " + value); //$NON-NLS-1$
+ throw new IllegalArgumentException("Alignment value is not an integer: " + value, e); //$NON-NLS-1$
}
}
}
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 e186a14..6e5aa19 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
@@ -114,19 +114,6 @@
import java.util.Hashtable;
import java.util.Map;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IConfigurationElement;
-import org.eclipse.core.runtime.IExtension;
-import org.eclipse.core.runtime.IExtensionPoint;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.core.runtime.Platform;
-import org.eclipse.core.runtime.Plugin;
-import org.eclipse.core.runtime.QualifiedName;
-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;
import org.eclipse.core.resources.IFolder;
@@ -140,6 +127,19 @@
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.SubMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
@@ -150,10 +150,26 @@
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
-import org.eclipse.jdt.internal.core.*;
+import org.eclipse.jdt.internal.core.BatchOperation;
+import org.eclipse.jdt.internal.core.BufferManager;
+import org.eclipse.jdt.internal.core.ClasspathAccessRule;
+import org.eclipse.jdt.internal.core.ClasspathAttribute;
+import org.eclipse.jdt.internal.core.ClasspathEntry;
+import org.eclipse.jdt.internal.core.ClasspathValidation;
+import org.eclipse.jdt.internal.core.CreateTypeHierarchyOperation;
+import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
+import org.eclipse.jdt.internal.core.ExternalFoldersManager;
+import org.eclipse.jdt.internal.core.JavaCorePreferenceInitializer;
+import org.eclipse.jdt.internal.core.JavaModel;
+import org.eclipse.jdt.internal.core.JavaModelManager;
+import org.eclipse.jdt.internal.core.JavaProject;
+import org.eclipse.jdt.internal.core.Region;
+import org.eclipse.jdt.internal.core.SetContainerOperation;
+import org.eclipse.jdt.internal.core.SetVariablesOperation;
import org.eclipse.jdt.internal.core.builder.JavaBuilder;
import org.eclipse.jdt.internal.core.builder.State;
import org.eclipse.jdt.internal.core.nd.indexer.Indexer;
+import org.eclipse.jdt.internal.core.search.indexing.IndexManager;
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;
@@ -4116,7 +4132,7 @@
// if factory is null, default factory must be used
if (factory == null) factory = BufferManager.getDefaultBufferManager().getDefaultBufferFactory();
- return getWorkingCopies(BufferFactoryWrapper.create(factory));
+ return getWorkingCopies(org.eclipse.jdt.internal.core.BufferFactoryWrapper.create(factory));
}
/**
@@ -4181,14 +4197,14 @@
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
+ subMonitor.split(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());
+ subMonitor.split(manager.batchContainerInitializationsProgress.getWorked());
synchronized(manager) {
try {
manager.wait(100);
@@ -4264,38 +4280,8 @@
// 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
- }
+ // 47% of the time is spent in the dummy search
+ updateLegacyIndex(mainMonitor.split(47));
// check if the build state version number has changed since last session
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=98969)
@@ -4342,6 +4328,41 @@
}
}
+ private static void updateLegacyIndex(IProgressMonitor monitor) {
+ 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
+ );
+ } catch (JavaModelException e) {
+ // /search failed: ignore
+ } catch (OperationCanceledException e) {
+ if (monitor.isCanceled())
+ throw e;
+ // else indexes were not ready: catch the exception so that jars are still refreshed
+ }
+ }
+
/**
* Returns whether a given classpath variable is read-only or not.
*
@@ -5439,6 +5460,22 @@
JavaModelManager.getDeltaState().removePreResourceChangedListener(listener);
}
+ /**
+ * Deletes and rebuilds the java index.
+ *
+ * @param monitor a progress monitor, or <code>null</code> if progress
+ * reporting and cancellation are not desired
+ * @throws CoreException
+ * @since 3.13
+ */
+ public static void rebuildIndex(IProgressMonitor monitor) throws CoreException {
+ SubMonitor subMonitor = SubMonitor.convert(monitor, 10);
+ IndexManager manager = JavaModelManager.getIndexManager();
+ manager.deleteIndexFiles(subMonitor.split(1));
+ manager.reset();
+ Indexer.getInstance().rebuildIndex(subMonitor.split(7));
+ updateLegacyIndex(subMonitor.split(2));
+ }
/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
index 1846d3f..c0ec076 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/core/Signature.java
@@ -1483,7 +1483,7 @@
}
return count;
} catch (ArrayIndexOutOfBoundsException e) { // signature is syntactically incorrect if last character is C_ARRAY
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
}
}
@@ -1626,7 +1626,7 @@
count++;
}
} catch (ArrayIndexOutOfBoundsException e) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
}
}
@@ -1680,7 +1680,7 @@
i = e + 1;
}
} catch (ArrayIndexOutOfBoundsException e) {
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(e);
}
}
/**
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java
index 0250d5d..4de81cb 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaElementInfo.java
@@ -28,7 +28,7 @@
return super.clone();
}
catch (CloneNotSupportedException e) {
- throw new Error();
+ throw new Error(e);
}
}
public IJavaElement[] getChildren() {
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 b898a64..c250a8c 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
@@ -27,6 +27,7 @@
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
@@ -173,7 +174,7 @@
private static final String ASSUMED_EXTERNAL_FILES_CACHE = "assumedExternalFilesCache"; //$NON-NLS-1$
public static enum ArchiveValidity {
- BAD_FORMAT, UNABLE_TO_READ, VALID;
+ BAD_FORMAT, UNABLE_TO_READ, FILE_NOT_FOUND, VALID;
public boolean isValid() {
return this == VALID;
@@ -2767,7 +2768,10 @@
* zip/jar, or it must be an absolute workspace relative path if
* representing a zip/jar inside the workspace.
*
- * @exception CoreException If unable to create/open the ZipFile
+ * @exception CoreException If unable to create/open the ZipFile. The
+ * cause will be a {@link ZipException} if the file was corrupt, a
+ * {@link FileNotFoundException} if the file does not exist, or a
+ * {@link IOException} if we were unable to read the file.
*/
public ZipFile getZipFile(IPath path) throws CoreException {
return getZipFile(path, true);
@@ -2782,7 +2786,7 @@
*/
public static boolean throwIoExceptionsInGetZipFile = false;
- private ZipFile getZipFile(IPath path, boolean checkInvalidArchiveCache) throws CoreException {
+ public ZipFile getZipFile(IPath path, boolean checkInvalidArchiveCache) throws CoreException {
if (checkInvalidArchiveCache) {
throwExceptionIfArchiveInvalid(path);
}
@@ -2807,7 +2811,15 @@
}
return zipFile;
} catch (IOException e) {
- ArchiveValidity reason = (e instanceof ZipException) ? ArchiveValidity.BAD_FORMAT : ArchiveValidity.UNABLE_TO_READ;
+ ArchiveValidity reason;
+
+ if (e instanceof ZipException) {
+ reason = ArchiveValidity.BAD_FORMAT;
+ } else if (e instanceof FileNotFoundException) {
+ reason = ArchiveValidity.FILE_NOT_FOUND;
+ } else {
+ reason = ArchiveValidity.UNABLE_TO_READ;
+ }
addInvalidArchive(path, reason);
throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, e));
}
@@ -2835,13 +2847,14 @@
private void throwExceptionIfArchiveInvalid(IPath path) throws CoreException {
ArchiveValidity validity = getArchiveValidity(path);
- if (!validity.isValid()) {
- IOException reason;
- if (validity == ArchiveValidity.BAD_FORMAT) {
- reason = new ZipException();
- } else {
- reason = new IOException();
- }
+ IOException reason;
+ switch (validity) {
+ case BAD_FORMAT: reason = new ZipException(); break;
+ case FILE_NOT_FOUND: reason = new FileNotFoundException(); break;
+ case UNABLE_TO_READ: reason = new IOException(); break;
+ default: reason = null;
+ }
+ if (reason != null) {
throw new CoreException(new Status(IStatus.ERROR, JavaCore.PLUGIN_ID, -1, Messages.status_IOException, reason));
}
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
index 02e6460..65dd9b5 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java
@@ -913,9 +913,9 @@
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
} catch (SAXException e) {
- throw new IOException(Messages.file_badFormat);
+ throw new IOException(Messages.file_badFormat, e);
} catch (ParserConfigurationException e) {
- throw new IOException(Messages.file_badFormat);
+ throw new IOException(Messages.file_badFormat, e);
} finally {
reader.close();
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java
index 13a38c3..f205707 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/UserLibrary.java
@@ -154,9 +154,9 @@
DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
cpElement = parser.parse(new InputSource(reader)).getDocumentElement();
} catch (SAXException e) {
- throw new IOException(Messages.file_badFormat);
+ throw new IOException(Messages.file_badFormat, e);
} catch (ParserConfigurationException e) {
- throw new IOException(Messages.file_badFormat);
+ throw new IOException(Messages.file_badFormat, e);
} finally {
reader.close();
}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java
index 3097a43..26fb1c4 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/builder/BatchImageBuilder.java
@@ -112,7 +112,11 @@
}
);
}
- member.delete(IResource.FORCE, null);
+ try {
+ member.delete(IResource.FORCE, null);
+ } catch(CoreException e) {
+ Util.log(e, "Error occurred while deleting: " + member.getFullPath()); //$NON-NLS-1$
+ }
}
}
this.notifier.checkCancel();
@@ -139,7 +143,11 @@
return false;
if (!resource.isDerived())
resource.setDerived(true, null);
- resource.delete(IResource.FORCE, null);
+ try {
+ resource.delete(IResource.FORCE, null);
+ } catch(CoreException e) {
+ Util.log(e, "Error occurred while deleting: " + resource.getFullPath()); //$NON-NLS-1$
+ }
}
return false;
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java
index fb02f13..f38304d 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/Nd.java
@@ -169,8 +169,8 @@
this.db.setLocked(lockDB);
if (!isSupportedVersion()) {
- Package.log("Index database is uses an unsupported version " + this.db.getVersion() //$NON-NLS-1$
- + " Deleting and recreating.", null); //$NON-NLS-1$
+ Package.logInfo("Index database uses the unsupported version " + this.db.getVersion() //$NON-NLS-1$
+ + ". Deleting and recreating."); //$NON-NLS-1$
this.db.close();
this.fPath.delete();
this.db = new Database(this.fPath, cache, getDefaultVersion(), isPermanentlyReadOnly());
@@ -599,4 +599,8 @@
public NdNodeTypeRegistry<NdNode> getTypeRegistry() {
return this.fNodeTypeRegistry;
}
+
+ public void clear(IProgressMonitor monitor) {
+ getDB().clear(getDefaultVersion());
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java
index df7ca4e..2bd371c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/RawGrowableArray.java
@@ -126,7 +126,7 @@
GROWABLE_BLOCK_HEADER_BYTES = type.size();
- MAX_GROWABLE_SIZE = (Database.MAX_MALLOC_SIZE - GROWABLE_BLOCK_HEADER_BYTES)
+ MAX_GROWABLE_SIZE = (Database.MAX_SINGLE_BLOCK_MALLOC_SIZE - GROWABLE_BLOCK_HEADER_BYTES)
/ Database.PTR_SIZE;
}
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java
index 02060fe..8bb0ed0 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/Database.java
@@ -46,8 +46,9 @@
* INT_SIZE | pointer to head of linked list of blocks of size MIN_BLOCK_DELTAS*BLOCK_SIZE_DELTA
* .. | ...
* INT_SIZE * (M + 1) | pointer to head of linked list of blocks of size (M + MIN_BLOCK_DELTAS) * BLOCK_SIZE_DELTA
+ * FREE_BLOCK_OFFSET | chunk number for the root of the large block free space trie
* WRITE_NUMBER_OFFSET | long integer which is incremented on every write
- * MALLOC_STATS_OFFSET | memory usage statistics
+ * MALLOC_STATS_OFFSET | memory usage statistics
* DATA_AREA | The database singletons are stored here and use the remainder of chunk 0
*
* M = CHUNK_SIZE / BLOCK_SIZE_DELTA - MIN_BLOCK_DELTAS
@@ -86,21 +87,26 @@
private static final int BLOCK_PREV_OFFSET = BLOCK_HEADER_SIZE;
private static final int BLOCK_NEXT_OFFSET = BLOCK_HEADER_SIZE + INT_SIZE;
private static final int FREE_BLOCK_HEADER_SIZE = BLOCK_NEXT_OFFSET + INT_SIZE;
-
- public static final int MIN_BLOCK_DELTAS = (FREE_BLOCK_HEADER_SIZE + BLOCK_SIZE_DELTA - 1) /
- BLOCK_SIZE_DELTA; // Must be enough multiples of BLOCK_SIZE_DELTA in order to fit the free block header
- public static final int MAX_BLOCK_DELTAS = CHUNK_SIZE / BLOCK_SIZE_DELTA;
- public static final int MAX_MALLOC_SIZE = MAX_BLOCK_DELTAS * BLOCK_SIZE_DELTA - BLOCK_HEADER_SIZE;
- public static final int PTR_SIZE = 4; // size of a pointer in the database in bytes
+
+ // Must be enough multiples of BLOCK_SIZE_DELTA in order to fit the free block header
+ public static final int MIN_BLOCK_DELTAS = (FREE_BLOCK_HEADER_SIZE + BLOCK_SIZE_DELTA - 1) / BLOCK_SIZE_DELTA;
+ public static final int MAX_BLOCK_DELTAS = (CHUNK_SIZE - LargeBlock.HEADER_SIZE - LargeBlock.FOOTER_SIZE)
+ / BLOCK_SIZE_DELTA;
+ public static final int MAX_SINGLE_BLOCK_MALLOC_SIZE = MAX_BLOCK_DELTAS * BLOCK_SIZE_DELTA - BLOCK_HEADER_SIZE;
+ public static final int PTR_SIZE = 4; // size of a pointer in the database in bytes
public static final int STRING_SIZE = PTR_SIZE;
public static final int FLOAT_SIZE = INT_SIZE;
public static final int DOUBLE_SIZE = LONG_SIZE;
public static final long MAX_DB_SIZE= ((long) 1 << (Integer.SIZE + BLOCK_SIZE_DELTA_BITS));
+ public static final long MAX_MALLOC_SIZE = MAX_DB_SIZE - LargeBlock.HEADER_SIZE - LargeBlock.FOOTER_SIZE
+ - CHUNK_SIZE - BLOCK_HEADER_SIZE;
+
public static final int VERSION_OFFSET = 0;
- private static final int MALLOC_TABLE_OFFSET = VERSION_OFFSET + INT_SIZE;
- public static final int WRITE_NUMBER_OFFSET = MALLOC_TABLE_OFFSET
+ public static final int MALLOC_TABLE_OFFSET = VERSION_OFFSET + INT_SIZE;
+ public static final int FREE_BLOCK_OFFSET = MALLOC_TABLE_OFFSET
+ (CHUNK_SIZE / BLOCK_SIZE_DELTA - MIN_BLOCK_DELTAS + 1) * INT_SIZE;
+ public static final int WRITE_NUMBER_OFFSET = FREE_BLOCK_OFFSET + PTR_SIZE;
public static final int MALLOC_STATS_OFFSET = WRITE_NUMBER_OFFSET + LONG_SIZE;
public static final int DATA_AREA_OFFSET = MALLOC_STATS_OFFSET + MemoryStats.SIZE;
@@ -128,7 +134,6 @@
private final Chunk fHeaderChunk;
private Chunk[] fChunks;
private int fChunksUsed;
- private int fChunksAllocated;
private ChunkCache fCache;
private long malloced;
@@ -159,12 +164,12 @@
if (nChunksOnDisk <= 0) {
this.fVersion= version;
this.fChunks= new Chunk[1];
- this.fChunksUsed = this.fChunksAllocated = this.fChunks.length;
+ this.fChunksUsed = this.fChunks.length;
} else {
this.fHeaderChunk.read();
this.fVersion= this.fHeaderChunk.getInt(VERSION_OFFSET);
this.fChunks = new Chunk[nChunksOnDisk]; // chunk[0] is unused.
- this.fChunksUsed = this.fChunksAllocated = nChunksOnDisk;
+ this.fChunksUsed = nChunksOnDisk;
}
} catch (IOException e) {
throw new IndexException(new DBStatus(e));
@@ -172,8 +177,8 @@
this.memoryUsage = new MemoryStats(this.fHeaderChunk, MALLOC_STATS_OFFSET);
}
- private static int divideRoundingUp(int num, int den) {
- return (num + den - 1) / den;
+ private static int divideRoundingUp(long num, int den) {
+ return (int) ((num + den - 1) / den);
}
private void openFile() throws FileNotFoundException {
@@ -292,7 +297,7 @@
this.fHeaderChunk.clear(0, CHUNK_SIZE);
// Chunks have been removed from the cache, so we may just reset the array of chunks.
this.fChunks = new Chunk[] {null};
- this.fChunksUsed = this.fChunksAllocated = this.fChunks.length;
+ this.fChunksUsed = this.fChunks.length;
try {
wasCanceled = this.fHeaderChunk.flush() || wasCanceled; // Zero out header chunk.
wasCanceled = performUninterruptableWrite(() -> {
@@ -381,7 +386,7 @@
*/
public void memcpy(long dest, long source, int numBytes) {
assert numBytes >= 0;
- assert numBytes <= MAX_MALLOC_SIZE;
+ assert numBytes <= MAX_SINGLE_BLOCK_MALLOC_SIZE;
// TODO: make use of lower-level System.arrayCopy
for (int count = 0; count < numBytes; count++) {
putByte(dest + count, getByte(source + count));
@@ -391,78 +396,442 @@
/**
* Allocate a block out of the database.
*/
- public long malloc(final int datasize, final short poolId) throws IndexException {
+ public long malloc(final long datasize, final short poolId) throws IndexException {
assert this.fExclusiveLock;
assert datasize >= 0;
assert datasize <= MAX_MALLOC_SIZE;
- int needDeltas= divideRoundingUp(datasize + BLOCK_HEADER_SIZE, BLOCK_SIZE_DELTA);
- if (needDeltas < MIN_BLOCK_DELTAS) {
- needDeltas= MIN_BLOCK_DELTAS;
- }
-
- // Which block size.
- long freeblock = 0;
- int useDeltas;
- for (useDeltas= needDeltas; useDeltas <= MAX_BLOCK_DELTAS; useDeltas++) {
- freeblock = getFirstBlock(useDeltas * BLOCK_SIZE_DELTA);
- if (freeblock != 0)
- break;
- }
-
- // Get the block.
- Chunk chunk;
- if (freeblock == 0) {
- // Allocate a new chunk.
- freeblock= createNewChunk();
- useDeltas = MAX_BLOCK_DELTAS;
- chunk = getChunk(freeblock);
+ long result;
+ int usedSize;
+ if (datasize >= MAX_SINGLE_BLOCK_MALLOC_SIZE) {
+ int newChunkNum = createLargeBlock(datasize);
+ usedSize = Math.abs(getBlockHeaderForChunkNum(newChunkNum)) * CHUNK_SIZE;
+ result = newChunkNum * CHUNK_SIZE + LargeBlock.HEADER_SIZE;
+ // Note that we identify large blocks by setting their block size to 0.
+ clearRange(result, usedSize - LargeBlock.HEADER_SIZE - LargeBlock.FOOTER_SIZE);
+ result = result + BLOCK_HEADER_SIZE;
} else {
- chunk = getChunk(freeblock);
- removeBlock(chunk, useDeltas * BLOCK_SIZE_DELTA, freeblock);
+ long freeBlock = 0;
+ int needDeltas = divideRoundingUp(datasize + BLOCK_HEADER_SIZE, BLOCK_SIZE_DELTA);
+ if (needDeltas < MIN_BLOCK_DELTAS) {
+ needDeltas = MIN_BLOCK_DELTAS;
+ }
+
+ // Which block size.
+ int useDeltas;
+ for (useDeltas = needDeltas; useDeltas <= MAX_BLOCK_DELTAS; useDeltas++) {
+ freeBlock = getFirstBlock(useDeltas * BLOCK_SIZE_DELTA);
+ if (freeBlock != 0)
+ break;
+ }
+
+ // Get the block.
+ Chunk chunk;
+ if (freeBlock == 0) {
+ // Allocate a new chunk.
+ freeBlock = (long) (createLargeBlock(datasize)) * (long) CHUNK_SIZE + LargeBlock.HEADER_SIZE;
+ useDeltas = MAX_BLOCK_DELTAS;
+ chunk = getChunk(freeBlock);
+ } else {
+ chunk = getChunk(freeBlock);
+ removeBlock(chunk, useDeltas * BLOCK_SIZE_DELTA, freeBlock);
+ }
+
+ final int unusedDeltas = useDeltas - needDeltas;
+ if (unusedDeltas >= MIN_BLOCK_DELTAS) {
+ // Add in the unused part of our block.
+ addBlock(chunk, unusedDeltas * BLOCK_SIZE_DELTA, freeBlock + needDeltas * BLOCK_SIZE_DELTA);
+ useDeltas = needDeltas;
+ }
+
+ // Make our size negative to show in use.
+ usedSize = useDeltas * BLOCK_SIZE_DELTA;
+ chunk.putShort(freeBlock, (short) -usedSize);
+
+ // Clear out the block, lots of people are expecting this.
+ chunk.clear(freeBlock + BLOCK_HEADER_SIZE, usedSize - BLOCK_HEADER_SIZE);
+ result = freeBlock + BLOCK_HEADER_SIZE;
}
- final int unusedDeltas = useDeltas - needDeltas;
- if (unusedDeltas >= MIN_BLOCK_DELTAS) {
- // Add in the unused part of our block.
- addBlock(chunk, unusedDeltas * BLOCK_SIZE_DELTA, freeblock + needDeltas * BLOCK_SIZE_DELTA);
- useDeltas= needDeltas;
- }
-
- // Make our size negative to show in use.
- final int usedSize= useDeltas * BLOCK_SIZE_DELTA;
- chunk.putShort(freeblock, (short) -usedSize);
-
- // Clear out the block, lots of people are expecting this.
- chunk.clear(freeblock + BLOCK_HEADER_SIZE, usedSize - BLOCK_HEADER_SIZE);
-
this.malloced += usedSize;
- long result = freeblock + BLOCK_HEADER_SIZE;
this.memoryUsage.recordMalloc(poolId, usedSize);
return result;
}
- private long createNewChunk() throws IndexException {
+ /**
+ * Clears all the bytes in the given range by setting them to zero.
+ *
+ * @param startAddress first address to clear
+ * @param bytesToClear number of addresses to clear
+ */
+ public void clearRange(long startAddress, int bytesToClear) {
+ if (bytesToClear == 0) {
+ return;
+ }
+ long endAddress = startAddress + bytesToClear;
+ assert endAddress <= this.fChunksUsed * CHUNK_SIZE;
+ int blockNumber = (int) (startAddress / CHUNK_SIZE);
+ int firstBlockBytesToClear = Math.min((int) (((blockNumber + 1) * CHUNK_SIZE) - startAddress), bytesToClear);
+
+ Chunk firstBlock = getChunk(startAddress);
+ firstBlock.clear(startAddress, firstBlockBytesToClear);
+ startAddress += firstBlockBytesToClear;
+ bytesToClear -= firstBlockBytesToClear;
+ while (bytesToClear > CHUNK_SIZE) {
+ Chunk nextBlock = getChunk(startAddress);
+ nextBlock.clear(startAddress, CHUNK_SIZE);
+ startAddress += CHUNK_SIZE;
+ bytesToClear -= CHUNK_SIZE;
+ }
+
+ if (bytesToClear > 0) {
+ Chunk nextBlock = getChunk(startAddress);
+ nextBlock.clear(startAddress, bytesToClear);
+ }
+ }
+
+ /**
+ * Obtains a new block that can fit the given number of bytes (at minimum). Returns the
+ * chunk number.
+ *
+ * @param datasize minimum number of bytes needed
+ * @return the chunk number
+ */
+ private int createLargeBlock(long datasize) {
+ final int neededChunks = getChunksNeededForBytes(datasize);
+ int freeBlockChunkNum = getFreeBlockFromTrie(neededChunks);
+ final int numChunks;
+
+ if (freeBlockChunkNum == 0) {
+ final int lastChunkNum = this.fChunksUsed;
+
+ numChunks = neededChunks;
+
+ // Check if the last block in the database is free. If so, unlink and expand it.
+ int lastBlockSize = getBlockFooterForChunkBefore(lastChunkNum);
+ if (lastBlockSize > 0) {
+ int startChunkNum = getFirstChunkOfBlockBefore(lastChunkNum);
+
+ unlinkFreeBlock(startChunkNum);
+ // Allocate additional new chunks such that the new chunk is large enough to
+ // handle this allocation.
+ createNewChunks(neededChunks - lastBlockSize);
+ freeBlockChunkNum = startChunkNum;
+ } else {
+ freeBlockChunkNum = createNewChunks(numChunks);
+ }
+ } else {
+ numChunks = getBlockHeaderForChunkNum(freeBlockChunkNum);
+
+ unlinkFreeBlock(freeBlockChunkNum);
+ }
+
+ final int resultChunkNum;
+ if (numChunks > neededChunks) {
+ // If the chunk we've selected is larger than necessary, split it. We have the
+ // choice of using either half of the block. In the interest of leaving more
+ // opportunities of merging large blocks, we leave the unused half of the block
+ // next to the larger adjacent block.
+ final long nextBlockChunkNum = freeBlockChunkNum + numChunks;
+
+ final int nextBlockSize = Math.abs(getBlockHeaderForChunkNum(nextBlockChunkNum));
+ final int prevBlockSize = Math.abs(getBlockFooterForChunkBefore(freeBlockChunkNum));
+
+ final int unusedChunks = numChunks - neededChunks;
+ if (nextBlockSize >= prevBlockSize) {
+ // Use the start of the block
+ resultChunkNum = freeBlockChunkNum;
+ // Return the last half of the block to the free block pool
+ linkFreeBlockToTrie(freeBlockChunkNum + neededChunks, unusedChunks);
+ } else {
+ // Use the end of the block
+ resultChunkNum = freeBlockChunkNum + neededChunks;
+ // Return the first half of the block to the free block pool
+ linkFreeBlockToTrie(freeBlockChunkNum, unusedChunks);
+ }
+ } else {
+ resultChunkNum = freeBlockChunkNum;
+ }
+
+ // Fill in the header and footer
+ setBlockHeader(resultChunkNum, -neededChunks);
+ return resultChunkNum;
+ }
+
+ /**
+ * Unlinks a free block (which currently belongs to the free block trie) so that it may
+ * be reused.
+ *
+ * @param freeBlockChunkNum chunk number of the block to be unlinked
+ */
+ private void unlinkFreeBlock(int freeBlockChunkNum) {
+ long freeBlockAddress = freeBlockChunkNum * CHUNK_SIZE;
+ int anotherBlockOfSameSize = 0;
+ int nextBlockChunkNum = getInt(freeBlockAddress + LargeBlock.NEXT_BLOCK_OFFSET);
+ int prevBlockChunkNum = getInt(freeBlockAddress + LargeBlock.PREV_BLOCK_OFFSET);
+ // Relink the linked list
+ if (nextBlockChunkNum != 0) {
+ anotherBlockOfSameSize = nextBlockChunkNum;
+ putInt(nextBlockChunkNum * CHUNK_SIZE + LargeBlock.PREV_BLOCK_OFFSET, prevBlockChunkNum);
+ }
+ if (prevBlockChunkNum != 0) {
+ anotherBlockOfSameSize = prevBlockChunkNum;
+ putInt(prevBlockChunkNum * CHUNK_SIZE + LargeBlock.NEXT_BLOCK_OFFSET, nextBlockChunkNum);
+ }
+
+ long root = getInt(FREE_BLOCK_OFFSET);
+ if (root == freeBlockChunkNum) {
+ putInt(FREE_BLOCK_OFFSET, 0);
+ }
+
+ int freeBlockSize = getBlockHeaderForChunkNum(freeBlockChunkNum);
+ int parentChunkNum = getInt(freeBlockAddress + LargeBlock.PARENT_OFFSET);
+ if (parentChunkNum != 0) {
+ int currentSize = getBlockHeaderForChunkNum(parentChunkNum);
+ int difference = currentSize ^ freeBlockSize;
+ if (difference != 0) {
+ int firstDifference = LargeBlock.SIZE_OF_SIZE_FIELD * 8 - Integer.numberOfLeadingZeros(difference) - 1;
+ long locationOfChildPointer = parentChunkNum * CHUNK_SIZE + LargeBlock.CHILD_TABLE_OFFSET
+ + (firstDifference * INT_SIZE);
+ putInt(locationOfChildPointer, 0);
+ }
+ }
+
+ if (anotherBlockOfSameSize != 0) {
+ insertChild(parentChunkNum, anotherBlockOfSameSize);
+ }
+
+ int currentParent = parentChunkNum;
+ for (int childIdx = 0; childIdx < LargeBlock.ENTRIES_IN_CHILD_TABLE; childIdx++) {
+ int nextChildChunkNum = getInt(freeBlockAddress + LargeBlock.CHILD_TABLE_OFFSET + (childIdx * INT_SIZE));
+ if (nextChildChunkNum != 0) {
+ insertChild(currentParent, nextChildChunkNum);
+ // Parent all subsequent children under the child that was most similar to the old parent
+ if (currentParent == parentChunkNum) {
+ currentParent = nextChildChunkNum;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Returns the chunk number of a free block that contains at least the given number of chunks, or
+ * 0 if there is no existing contiguous free block containing at least the given number of chunks.
+ *
+ * @param numChunks minumum number of chunks desired
+ * @return the chunk number of a free block containing at least the given number of chunks or 0
+ * if there is no existing free block containing that many chunks.
+ */
+ private int getFreeBlockFromTrie(int numChunks) {
+ int currentChunkNum = getInt(FREE_BLOCK_OFFSET);
+
+ int resultChunkNum = getSmallestChildNoSmallerThan(currentChunkNum, numChunks);
+ if (resultChunkNum == 0) {
+ return 0;
+ }
+
+ // Try not to return the trie node itself if there is a linked list entry available, since unlinking
+ // something from the linked list is faster than unlinking a trie node.
+ int nextResultChunkNum = getInt(resultChunkNum * CHUNK_SIZE + LargeBlock.NEXT_BLOCK_OFFSET);
+ if (nextResultChunkNum != 0) {
+ return nextResultChunkNum;
+ }
+ return resultChunkNum;
+ }
+
+ /**
+ * Given the chunk number of a block somewhere in the free space trie, this returns the smallest
+ * child in the subtree that is no smaller than the given number of chunks.
+ *
+ * @param trieNodeChunkNum chunk number of a block in the free space trie
+ * @param numChunks desired number of chunks
+ * @return the chunk number of the first chunk in a contiguous free block containing at least the
+ * given number of chunks
+ */
+ private int getSmallestChildNoSmallerThan(int trieNodeChunkNum, int numChunks) {
+ if (trieNodeChunkNum == 0) {
+ return 0;
+ }
+ int currentSize = getBlockHeaderForChunkNum(trieNodeChunkNum);
+ assert (currentSize >= 0);
+ int difference = currentSize ^ numChunks;
+ if (difference == 0) {
+ return trieNodeChunkNum;
+ }
+
+ int bitMask = Integer.highestOneBit(difference);
+ int firstDifference = LargeBlock.SIZE_OF_SIZE_FIELD * 8 - Integer.numberOfLeadingZeros(bitMask) - 1;
+ boolean lookingForSmallerChild = (currentSize > numChunks);
+ for (int testPosition = firstDifference; testPosition < LargeBlock.ENTRIES_IN_CHILD_TABLE; testPosition++) {
+ if (((currentSize & bitMask) != 0) == lookingForSmallerChild) {
+ int nextChildChunkNum = getInt(
+ trieNodeChunkNum * CHUNK_SIZE + LargeBlock.CHILD_TABLE_OFFSET + (testPosition * PTR_SIZE));
+ int childResultChunkNum = getSmallestChildNoSmallerThan(nextChildChunkNum, numChunks);
+ if (childResultChunkNum != 0) {
+ return childResultChunkNum;
+ }
+ }
+ bitMask <<= 1;
+ }
+
+ if (lookingForSmallerChild) {
+ return trieNodeChunkNum;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Link the given unused block into the free block tries. The block does not need to have
+ * its header filled in already.
+ *
+ * @param freeBlockChunkNum chunk number of the start of the block
+ * @param numChunks number of chunks in the block
+ */
+ private void linkFreeBlockToTrie(int freeBlockChunkNum, int numChunks) {
+ setBlockHeader(freeBlockChunkNum, numChunks);
+ long freeBlockAddress = freeBlockChunkNum * CHUNK_SIZE;
+ Chunk chunk = getChunk(freeBlockAddress);
+ chunk.clear(freeBlockAddress + LargeBlock.HEADER_SIZE,
+ LargeBlock.UNALLOCATED_HEADER_SIZE - LargeBlock.HEADER_SIZE);
+
+ insertChild(getInt(FREE_BLOCK_OFFSET), freeBlockChunkNum);
+ }
+
+ /**
+ * Adds the given child block to the given parent subtree of the free space trie. Any existing
+ * subtree under the given child block will be retained.
+ *
+ * @param parentChunkNum root of the existing tree, or 0 if the child is going to be the new root
+ * @param newChildChunkNum the new child to insert
+ */
+ private void insertChild(int parentChunkNum, int newChildChunkNum) {
+ if (parentChunkNum == 0) {
+ putInt(newChildChunkNum * CHUNK_SIZE + LargeBlock.PARENT_OFFSET, parentChunkNum);
+ putInt(FREE_BLOCK_OFFSET, newChildChunkNum);
+ return;
+ }
+ int numChunks = getBlockHeaderForChunkNum(newChildChunkNum);
+ for (;;) {
+ int currentSize = getBlockHeaderForChunkNum(parentChunkNum);
+ int difference = currentSize ^ numChunks;
+ if (difference == 0) {
+ // The newly added item is exactly the same size as this trie node
+ insertFreeBlockAfter(parentChunkNum, newChildChunkNum);
+ return;
+ }
+
+ int firstDifference = LargeBlock.SIZE_OF_SIZE_FIELD * 8 - Integer.numberOfLeadingZeros(difference) - 1;
+ long locationOfChildPointer = parentChunkNum * CHUNK_SIZE + LargeBlock.CHILD_TABLE_OFFSET
+ + (firstDifference * INT_SIZE);
+ int childChunkNum = getInt(locationOfChildPointer);
+ if (childChunkNum == 0) {
+ putInt(locationOfChildPointer, newChildChunkNum);
+ putInt(newChildChunkNum * CHUNK_SIZE + LargeBlock.PARENT_OFFSET, parentChunkNum);
+ return;
+ }
+ parentChunkNum = childChunkNum;
+ }
+ }
+
+ /**
+ * Adds the given block to the linked list of equally-sized free chunks in the free space trie.
+ * Both chunks must be unused, must be the same size, and the previous chunk must already
+ * be linked into the free space trie. The newly-added chunk must not have any children.
+ *
+ * @param prevChunkNum chunk number of previous block in the existing list
+ * @param newChunkNum new chunk to be added to the list
+ */
+ private void insertFreeBlockAfter(int prevChunkNum, int newChunkNum) {
+ long prevChunkAddress = (long) prevChunkNum * CHUNK_SIZE;
+ int nextChunkNum = getInt(prevChunkAddress + LargeBlock.NEXT_BLOCK_OFFSET);
+ long nextChunkAddress = (long) nextChunkNum * CHUNK_SIZE;
+ long newLockAddress = (long) newChunkNum * CHUNK_SIZE;
+
+ putInt(prevChunkAddress + LargeBlock.NEXT_BLOCK_OFFSET, newChunkNum);
+ if (nextChunkNum != 0) {
+ putInt(nextChunkAddress + LargeBlock.PREV_BLOCK_OFFSET, newChunkNum);
+ }
+ putInt(newLockAddress + LargeBlock.PREV_BLOCK_OFFSET, prevChunkNum);
+ putInt(newLockAddress + LargeBlock.NEXT_BLOCK_OFFSET, nextChunkNum);
+ }
+
+ /**
+ * Returns the chunk number of the chunk at the start of a block, given the
+ * chunk number of the chunk at the start of the following block.
+ *
+ * @param chunkNum the chunk number of the chunk immediately following the
+ * chunk being queried
+ * @return the chunk number of the chunk at the start of the previous block
+ */
+ private int getFirstChunkOfBlockBefore(int chunkNum) {
+ int blockChunks = Math.abs(getBlockFooterForChunkBefore(chunkNum));
+ return chunkNum - blockChunks;
+ }
+
+ /**
+ * Sets the block header and footer for the given range of chunks which make
+ * up a contiguous block.
+ *
+ * @param firstChunkNum chunk number of the first chunk in the block
+ * @param headerContent the content of the header. Its magnitude is the number of
+ * chunks in the block. It is positive if the chunk is free and negative if
+ * the chunk is in use.
+ */
+ private void setBlockHeader(int firstChunkNum, int headerContent) {
+ assert headerContent != 0;
+ assert firstChunkNum < this.fChunksUsed;
+ int numBlocks = Math.abs(headerContent);
+ long firstChunkAddress = firstChunkNum * CHUNK_SIZE;
+ putInt(firstChunkAddress, headerContent);
+ putInt(firstChunkAddress + (numBlocks * CHUNK_SIZE) - LargeBlock.FOOTER_SIZE, headerContent);
+ }
+
+ /**
+ * Returns the size of the block (in number of chunks) starting at the given address. The return value is positive
+ * if the block is free and negative if the block is allocated.
+ */
+ private int getBlockHeaderForChunkNum(long firstChunkNum) {
+ if (firstChunkNum >= this.fChunksUsed) {
+ return 0;
+ }
+ return getInt(firstChunkNum * CHUNK_SIZE);
+ }
+
+ /**
+ * Returns the size of the block (in number of chunks), given the (non-inclusive) address that the block ends at.
+ * The return value is positive if the block is free and negative if the block is allocated.
+ */
+ private int getBlockFooterForChunkBefore(int chunkNum) {
+ if (chunkNum < 2) {
+ // Don't report the database header as a normal chunk.
+ return 0;
+ }
+ return getInt(chunkNum * CHUNK_SIZE - LargeBlock.FOOTER_SIZE);
+ }
+
+ private int createNewChunks(int numChunks) throws IndexException {
assert this.fExclusiveLock;
synchronized (this.fCache) {
- final int newChunkIndex = this.fChunksUsed; // fChunks.length;
+ final int firstChunkIndex = this.fChunksUsed;
+ final int lastChunkIndex = firstChunkIndex + numChunks - 1;
- final Chunk chunk = new Chunk(this, newChunkIndex);
- chunk.fDirty = true;
+ final Chunk lastChunk = new Chunk(this, lastChunkIndex);
+ lastChunk.fDirty = true;
- if (newChunkIndex >= this.fChunksAllocated) {
- int increment = Math.max(1024, this.fChunksAllocated / 20);
- Chunk[] newchunks = new Chunk[this.fChunksAllocated + increment];
- System.arraycopy(this.fChunks, 0, newchunks, 0, this.fChunksAllocated);
-
- this.fChunks = newchunks;
- this.fChunksAllocated += increment;
+ if (lastChunkIndex >= this.fChunks.length) {
+ int increment = Math.max(1024, this.fChunks.length / 20);
+ int newNumChunks = Math.max(lastChunkIndex + 1, this.fChunks.length + increment);
+ Chunk[] newChunks = new Chunk[newNumChunks];
+ System.arraycopy(this.fChunks, 0, newChunks, 0, this.fChunks.length);
+ this.fChunks = newChunks;
}
- this.fChunksUsed += 1;
- this.fChunks[newChunkIndex] = chunk;
- this.fCache.add(chunk, true);
- long address = (long) newChunkIndex * CHUNK_SIZE;
+ this.fChunksUsed = lastChunkIndex + 1;
+ this.fChunks[lastChunkIndex] = lastChunk;
+ this.fCache.add(lastChunk, true);
+ long result = (long) firstChunkIndex * CHUNK_SIZE;
/*
* Non-dense pointers are at most 31 bits dense pointers are at most 35 bits Check the sizes here and throw
@@ -470,33 +839,15 @@
* indexing operation should be stopped. This is desired since generally, once the max size is exceeded,
* there are lots of errors.
*/
- if (address >= MAX_DB_SIZE) {
+ long endAddress = result + (numChunks * CHUNK_SIZE);
+ if (endAddress > MAX_DB_SIZE) {
Object bindings[] = { this.getLocation().getAbsolutePath(), MAX_DB_SIZE };
throw new IndexException(new Status(IStatus.ERROR, Package.PLUGIN_ID, Package.STATUS_DATABASE_TOO_LARGE,
- NLS.bind("Database too large! Address = " + address + ", max size = " + MAX_DB_SIZE, bindings), //$NON-NLS-1$ //$NON-NLS-2$
- null));
+ NLS.bind("Database too large! Address = " + endAddress + ", max size = " + MAX_DB_SIZE, //$NON-NLS-1$ //$NON-NLS-2$
+ bindings), null));
}
- return address;
- }
- }
- /**
- * For testing purposes, only.
- */
- private long createNewChunks(int numChunks) throws IndexException {
- assert this.fExclusiveLock;
- synchronized (this.fCache) {
- final int oldLen= this.fChunks.length;
- Chunk[] newchunks = new Chunk[oldLen + numChunks];
- System.arraycopy(this.fChunks, 0, newchunks, 0, oldLen);
- final Chunk chunk= new Chunk(this, oldLen + numChunks - 1);
- chunk.fDirty= true;
- newchunks[ oldLen + numChunks - 1 ] = chunk;
- this.fChunks= newchunks;
- this.fCache.add(chunk, true);
- this.fChunksAllocated=oldLen + numChunks;
- this.fChunksUsed=oldLen + numChunks;
- return (long) (oldLen + numChunks - 1) * CHUNK_SIZE;
+ return firstChunkIndex;
}
}
@@ -544,26 +895,74 @@
/**
* Free an allocated block.
*
- * @param address memory address to be freed
- * @param poolId the same ID that was previously passed into malloc when allocating this memory address
+ * @param address
+ * memory address to be freed
+ * @param poolId
+ * the same ID that was previously passed into malloc when allocating this memory address
*/
public void free(long address, short poolId) throws IndexException {
assert this.fExclusiveLock;
if (address == 0) {
return;
}
- // TODO Look for opportunities to merge blocks
+ long blockSize;
long block = address - BLOCK_HEADER_SIZE;
Chunk chunk = getChunk(block);
- int blocksize = - chunk.getShort(block);
- if (blocksize < 0) {
- // Already freed.
- throw new IndexException(new Status(IStatus.ERROR, Package.PLUGIN_ID, 0,
- "Already freed record " + address, new Exception())); //$NON-NLS-1$
+ blockSize = -chunk.getShort(block);
+ // We use a block size of 0 to indicate a large block that fills a range of chunks
+ if (blockSize == 0) {
+ int offsetIntoChunk = (int) (address % CHUNK_SIZE);
+ assert offsetIntoChunk == LargeBlock.HEADER_SIZE + BLOCK_HEADER_SIZE;
+ // Deallocating a large block
+ // This was a large block. It uses a sequence of full chunks.
+ int chunkNum = (int) (address / CHUNK_SIZE);
+ int numChunks = -getBlockHeaderForChunkNum(chunkNum);
+ if (numChunks < 0) {
+ // Already freed.
+ throw new IndexException(new Status(IStatus.ERROR, Package.PLUGIN_ID, 0,
+ "Already freed large block " + address, new Exception())); //$NON-NLS-1$
+ }
+ blockSize = numChunks * CHUNK_SIZE;
+ freeLargeChunk(chunkNum, numChunks);
+ } else {
+ // Deallocating a normal block
+ // TODO Look for opportunities to merge small blocks
+ if (blockSize < 0) {
+ // Already freed.
+ throw new IndexException(new Status(IStatus.ERROR, Package.PLUGIN_ID, 0,
+ "Already freed record " + address, new Exception())); //$NON-NLS-1$
+ }
+ addBlock(chunk, (int) blockSize, block);
}
- addBlock(chunk, blocksize, block);
- this.freed += blocksize;
- this.memoryUsage.recordFree(poolId, blocksize);
+
+ this.freed += blockSize;
+ this.memoryUsage.recordFree(poolId, blockSize);
+ }
+
+ private void freeLargeChunk(int chunkNum, int numChunks) {
+ assert chunkNum > 0;
+ assert numChunks > 0;
+ int prevBlockHeader = getBlockFooterForChunkBefore(chunkNum);
+ int nextBlockChunkNum = chunkNum + numChunks;
+ int nextBlockHeader = getBlockHeaderForChunkNum(nextBlockChunkNum);
+
+ // If the previous block is unused, merge with it
+ if (prevBlockHeader > 0) {
+ int prevBlockChunkNum = getFirstChunkOfBlockBefore(chunkNum);
+
+ unlinkFreeBlock(prevBlockChunkNum);
+ chunkNum = prevBlockChunkNum;
+ numChunks += prevBlockHeader;
+ }
+
+ // If the next block is unused, merge with it
+ if (nextBlockHeader > 0) {
+ unlinkFreeBlock(nextBlockChunkNum);
+ numChunks += nextBlockHeader;
+ }
+
+ // Block merging is done. Now reinsert the merged block into the free space trie
+ linkFreeBlockToTrie(chunkNum, numChunks);
}
public void putByte(long offset, byte value) throws IndexException {
@@ -745,7 +1144,7 @@
this.memoryUsage.refresh();
this.fHeaderChunk.fDirty= false;
this.fChunks= new Chunk[] { null };
- this.fChunksUsed = this.fChunksAllocated = this.fChunks.length;
+ this.fChunksUsed = this.fChunks.length;
try {
this.fFile.close();
} catch (IOException e) {
@@ -931,6 +1330,10 @@
return this.fFile.length();
}
+ public int getChunkCount() {
+ return this.fChunksUsed;
+ }
+
/**
* A Record Pointer is a pointer as returned by Database.malloc().
* This is a pointer to a block + BLOCK_HEADER_SIZE.
@@ -953,4 +1356,19 @@
public MemoryStats getMemoryStats() {
return this.memoryUsage;
}
+
+ /**
+ * Returns the number of bytes that can fit in the payload of the given number of chunks.
+ */
+ public static long getBytesThatFitInChunks(int numChunks) {
+ return CHUNK_SIZE * numChunks - LargeBlock.HEADER_SIZE - LargeBlock.FOOTER_SIZE - BLOCK_HEADER_SIZE;
+ }
+
+ /**
+ * Returns the number of chunks needed to fit the given number of bytes of payload.
+ */
+ public static int getChunksNeededForBytes(long datasize) {
+ return divideRoundingUp(datasize + BLOCK_HEADER_SIZE + LargeBlock.HEADER_SIZE + LargeBlock.FOOTER_SIZE,
+ CHUNK_SIZE);
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/LargeBlock.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/LargeBlock.java
new file mode 100644
index 0000000..26af53c
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/LargeBlock.java
@@ -0,0 +1,26 @@
+package org.eclipse.jdt.internal.core.nd.db;
+
+public class LargeBlock {
+ public static final int SIZE_OFFSET = 0;
+ public static final int SIZE_OF_SIZE_FIELD = Database.INT_SIZE;
+ /**
+ * Size of the header for a large block. The header consists of a int which holds the number of chunks in the block.
+ * It is negative for an allocated block and positive for an unallocated block. The header is located at the start
+ * of the large block.
+ */
+ public static final int HEADER_SIZE = Math.max(Database.INT_SIZE, Database.BLOCK_SIZE_DELTA);
+
+ public static final int ENTRIES_IN_CHILD_TABLE = SIZE_OF_SIZE_FIELD * 8;
+ public static final int CHILD_TABLE_OFFSET = HEADER_SIZE;
+ public static final int PARENT_OFFSET = CHILD_TABLE_OFFSET + (Database.INT_SIZE * ENTRIES_IN_CHILD_TABLE);
+ public static final int PREV_BLOCK_OFFSET = PARENT_OFFSET + Database.INT_SIZE;
+ public static final int NEXT_BLOCK_OFFSET = PREV_BLOCK_OFFSET + Database.INT_SIZE;
+
+ public static final int UNALLOCATED_HEADER_SIZE = NEXT_BLOCK_OFFSET + Database.INT_SIZE;
+
+ /**
+ * The large block footer is located at the end of the last chunk in the large block. It is an exact copy of the
+ * header.
+ */
+ public static final int FOOTER_SIZE = HEADER_SIZE;
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/LongString.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/LongString.java
index c78b7f9..eb0e48a 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/LongString.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/LongString.java
@@ -29,13 +29,13 @@
private static final int NEXT1 = 4;
private static final int CHARS1 = 8;
- private static final int NUM_CHARS1 = (Database.MAX_MALLOC_SIZE - CHARS1) / 2;
+ private static final int NUM_CHARS1 = (Database.MAX_SINGLE_BLOCK_MALLOC_SIZE - CHARS1) / 2;
// Additional fields of subsequent records.
private static final int NEXTN = 0;
private static final int CHARSN = 4;
- private static final int NUM_CHARSN = (Database.MAX_MALLOC_SIZE - CHARSN) / 2;
+ private static final int NUM_CHARSN = (Database.MAX_SINGLE_BLOCK_MALLOC_SIZE - CHARSN) / 2;
public LongString(Database db, long record) {
this.db = db;
@@ -47,7 +47,7 @@
final int numCharsn = useBytes ? NUM_CHARSN * 2 : NUM_CHARSN;
this.db = db;
- this.record = db.malloc(Database.MAX_MALLOC_SIZE, Database.POOL_STRING_LONG);
+ this.record = db.malloc(Database.MAX_SINGLE_BLOCK_MALLOC_SIZE, Database.POOL_STRING_LONG);
// Write the first record.
final int length = chars.length;
@@ -64,7 +64,7 @@
long lastNext = this.record + NEXT1;
int start = numChars1;
while (length - start > numCharsn) {
- long nextRecord = db.malloc(Database.MAX_MALLOC_SIZE, Database.POOL_STRING_LONG);
+ long nextRecord = db.malloc(Database.MAX_SINGLE_BLOCK_MALLOC_SIZE, Database.POOL_STRING_LONG);
db.putRecPtr(lastNext, nextRecord);
chunk= db.getChunk(nextRecord);
if (useBytes) {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ShortString.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ShortString.java
index 09992a5..eb56c6c 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ShortString.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/db/ShortString.java
@@ -25,7 +25,7 @@
private static final int LENGTH = 0;
private static final int CHARS = 4;
- public static final int MAX_BYTE_LENGTH = Database.MAX_MALLOC_SIZE - CHARS;
+ public static final int MAX_BYTE_LENGTH = Database.MAX_SINGLE_BLOCK_MALLOC_SIZE - CHARS;
public ShortString(Database db, long offset) {
this.db = db;
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java
index afd740e..d52ce33 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/ClassFileToIndexConverter.java
@@ -16,9 +16,7 @@
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.compiler.CharOperation;
-import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
import org.eclipse.jdt.internal.compiler.codegen.AnnotationTargetTypeConstants;
import org.eclipse.jdt.internal.compiler.env.ClassSignature;
import org.eclipse.jdt.internal.compiler.env.EnumConstantSignature;
@@ -69,8 +67,6 @@
import org.eclipse.jdt.internal.core.nd.java.NdTypeParameter;
import org.eclipse.jdt.internal.core.nd.java.NdTypeSignature;
import org.eclipse.jdt.internal.core.nd.java.NdVariable;
-import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeDescriptor;
-import org.eclipse.jdt.internal.core.nd.java.model.BinaryTypeFactory;
import org.eclipse.jdt.internal.core.nd.util.CharArrayUtils;
import org.eclipse.jdt.internal.core.util.CharArrayBuffer;
import org.eclipse.jdt.internal.core.util.Util;
@@ -97,12 +93,6 @@
return this.resource.getNd();
}
- public static IBinaryType getTypeFromClassFile(IClassFile iClassFile, IProgressMonitor monitor)
- throws CoreException, ClassFormatException {
- BinaryTypeDescriptor descriptor = BinaryTypeFactory.createDescriptor(iClassFile);
- return BinaryTypeFactory.rawReadType(descriptor, true);
- }
-
/**
* Create a type info from the given class file in a jar and adds it to the given list of infos.
*
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java
index 318a736..2380780 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/indexer/Indexer.java
@@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.nd.indexer;
-import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -43,6 +43,7 @@
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobGroup;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElement;
@@ -115,10 +116,16 @@
*/
private Set<Listener> listeners = Collections.newSetFromMap(new WeakHashMap<Listener, Boolean>());
+ private JobGroup group = new JobGroup(Messages.Indexer_updating_index_job_name, 1, 1);
+
private Job rescanJob = Job.create(Messages.Indexer_updating_index_job_name, monitor -> {
rescan(monitor);
});
+ private Job rebuildIndexJob = Job.create(Messages.Indexer_updating_index_job_name, monitor -> {
+ rebuildIndex(monitor);
+ });
+
public static interface Listener {
void consume(IndexerEvent event);
}
@@ -560,14 +567,6 @@
String pathString = thePath.toString();
JavaIndex javaIndex = JavaIndex.getIndex(this.nd);
- File theFile = thePath.toFile();
- if (!(theFile.exists() && theFile.isFile())) {
- if (DEBUG) {
- Package.log("the file " + pathString + " does not exist", null); //$NON-NLS-1$ //$NON-NLS-2$
- }
- return 0;
- }
-
NdResourceFile resourceFile;
this.nd.acquireWriteLock(subMonitor.split(5));
@@ -589,9 +588,11 @@
if (DEBUG) {
Package.logInfo("rescanning " + thePath.toString() + ", " + fingerprint); //$NON-NLS-1$ //$NON-NLS-2$
}
- int result;
+ int result = 0;
try {
- result = addElement(resourceFile, element, subMonitor.split(50));
+ if (fingerprint.fileExists()) {
+ result = addElement(resourceFile, element, subMonitor.split(50));
+ }
} catch (JavaModelException e) {
if (DEBUG) {
Package.log("the file " + pathString + " cannot be indexed due to a recoverable error", null); //$NON-NLS-1$ //$NON-NLS-2$
@@ -611,6 +612,12 @@
Package.log("A RuntimeException occurred while indexing " + pathString, e); //$NON-NLS-1$
}
throw e;
+ } catch (FileNotFoundException e) {
+ fingerprint = FileFingerprint.getEmpty();
+ }
+
+ if (DEBUG && !fingerprint.fileExists()) {
+ Package.log("the file " + pathString + " was not indexed because it does not exist", null); //$NON-NLS-1$ //$NON-NLS-2$
}
List<NdResourceFile> allResourcesWithThisPath = Collections.emptyList();
@@ -648,9 +655,10 @@
/**
* Adds an archive to the index, under the given NdResourceFile.
+ * @throws FileNotFoundException if the file does not exist
*/
private int addElement(NdResourceFile resourceFile, IJavaElement element, IProgressMonitor monitor)
- throws JavaModelException {
+ throws JavaModelException, FileNotFoundException {
SubMonitor subMonitor = SubMonitor.convert(monitor);
if (element instanceof JarPackageFragmentRoot) {
@@ -704,6 +712,8 @@
} catch (ZipException e) {
Package.log("The zip file " + jarRoot.getPath() + " was corrupt", e); //$NON-NLS-1$//$NON-NLS-2$
// Indicates a corrupt zip file. Treat this like an empty zip file.
+ } catch (FileNotFoundException e) {
+ throw e;
} catch (IOException ioException) {
throw new JavaModelException(ioException, IJavaModelStatusConstants.IO_EXCEPTION);
} catch (CoreException coreException) {
@@ -722,7 +732,7 @@
boolean indexed = false;
try {
- ClassFileReader classFileReader = BinaryTypeFactory.rawReadType(descriptor, true);
+ ClassFileReader classFileReader = BinaryTypeFactory.rawReadTypeTestForExists(descriptor, true, false);
if (classFileReader != null) {
indexed = addClassToIndex(resourceFile, descriptor.fieldDescriptor, descriptor.indexPath,
classFileReader, iterationMonitor);
@@ -983,6 +993,10 @@
public Indexer(Nd toPopulate, IWorkspaceRoot workspaceRoot) {
this.nd = toPopulate;
this.root = workspaceRoot;
+ this.rescanJob.setSystem(true);
+ this.rescanJob.setJobGroup(this.group);
+ this.rebuildIndexJob.setSystem(true);
+ this.rebuildIndexJob.setJobGroup(this.group);
}
public void rescanAll() {
@@ -1070,4 +1084,20 @@
}
}
}
+
+ public void rebuildIndex(IProgressMonitor monitor) throws CoreException {
+ SubMonitor subMonitor = SubMonitor.convert(monitor, 100);
+
+ this.nd.acquireWriteLock(subMonitor.split(1));
+ try {
+ this.nd.clear(subMonitor.split(2));
+ } finally {
+ this.nd.releaseWriteLock();
+ }
+ rescan(subMonitor.split(98));
+ }
+
+ public void requestRebuildIndex() {
+ this.rebuildIndexJob.schedule();
+ }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java
index f1b0262..b5d6062 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/FileFingerprint.java
@@ -139,6 +139,15 @@
}
/**
+ * Returns true iff the file existed at the time the fingerprint was computed.
+ *
+ * @return true iff the file existed at the time the fingerprint was computed.
+ */
+ public boolean fileExists() {
+ return !equals(EMPTY);
+ }
+
+ /**
* Compares the given File with the receiver. If the fingerprint matches (ie: the file
*/
public FingerprintTestResult test(IPath path, IProgressMonitor monitor) throws CoreException {
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
index 006aeff..778d5da 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/JavaIndex.java
@@ -34,9 +34,9 @@
public class JavaIndex {
// Version constants
- static final int CURRENT_VERSION = Nd.version(1, 37);
- static final int MAX_SUPPORTED_VERSION = Nd.version(1, 37);
- static final int MIN_SUPPORTED_VERSION = Nd.version(1, 37);
+ static final int CURRENT_VERSION = Nd.version(1, 38);
+ static final int MAX_SUPPORTED_VERSION = Nd.version(1, 38);
+ static final int MIN_SUPPORTED_VERSION = Nd.version(1, 38);
// Fields for the search header
public static final FieldSearchIndex<NdResourceFile> FILES;
@@ -293,8 +293,4 @@
registry.register(0x0200, NdWorkspaceLocation.type.getFactory());
return registry;
}
-
- public void rebuildIndex() {
- // TODO: delete and recreate the index
- }
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
index d6d3981..631c384 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/BinaryTypeFactory.java
@@ -10,15 +10,19 @@
*******************************************************************************/
package org.eclipse.jdt.internal.core.nd.java.model;
+import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IJavaElement;
@@ -37,6 +41,7 @@
import org.eclipse.jdt.internal.core.nd.IReader;
import org.eclipse.jdt.internal.core.nd.Nd;
import org.eclipse.jdt.internal.core.nd.db.IndexException;
+import org.eclipse.jdt.internal.core.nd.indexer.Indexer;
import org.eclipse.jdt.internal.core.nd.java.JavaIndex;
import org.eclipse.jdt.internal.core.nd.java.JavaNames;
import org.eclipse.jdt.internal.core.nd.java.NdResourceFile;
@@ -111,9 +116,8 @@
* no such type exists.
* @throws ClassFormatException
*/
- public static IBinaryType readType(BinaryTypeDescriptor descriptor,
- IProgressMonitor monitor) throws JavaModelException, ClassFormatException {
-
+ public static IBinaryType readType(BinaryTypeDescriptor descriptor, IProgressMonitor monitor) throws JavaModelException, ClassFormatException {
+
if (JavaIndex.isEnabled()) {
try {
return readFromIndex(JavaIndex.getIndex(), descriptor, monitor);
@@ -125,6 +129,14 @@
return rawReadType(descriptor, true);
}
+ public static ClassFileReader rawReadType(BinaryTypeDescriptor descriptor, boolean fullyInitialize) throws JavaModelException, ClassFormatException {
+ try {
+ return rawReadTypeTestForExists(descriptor, fullyInitialize, true);
+ } catch (FileNotFoundException e) {
+ throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+ }
+ }
+
/**
* Read the class file from disk, circumventing the index's cache. This should only be used by callers
* that need to read information from the class file which aren't present in the index (such as method bodies).
@@ -132,15 +144,18 @@
* @return the newly-created ClassFileReader or null if the given class file does not exist.
* @throws ClassFormatException if the class file existed but was corrupt
* @throws JavaModelException if unable to read the class file due to a transient failure
+ * @throws FileNotFoundException if the file does not exist
*/
- public static ClassFileReader rawReadType(BinaryTypeDescriptor descriptor, boolean fullyInitialize) throws JavaModelException, ClassFormatException {
+ public static ClassFileReader rawReadTypeTestForExists(BinaryTypeDescriptor descriptor, boolean fullyInitialize,
+ boolean useInvalidArchiveCache) throws JavaModelException, ClassFormatException, FileNotFoundException {
if (descriptor == null) {
return null;
}
if (descriptor.isInJarFile()) {
ZipFile zip = null;
try {
- zip = JavaModelManager.getJavaModelManager().getZipFile(new Path(new String(descriptor.workspacePath)));
+ zip = JavaModelManager.getJavaModelManager().getZipFile(new Path(new String(descriptor.workspacePath)),
+ useInvalidArchiveCache);
char[] entryNameCharArray = CharArrayUtils.concat(
JavaNames.fieldDescriptorToBinaryName(descriptor.fieldDescriptor), SuffixConstants.SUFFIX_class);
String entryName = new String(entryNameCharArray);
@@ -161,7 +176,18 @@
}
} else {
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(new String(descriptor.workspacePath)));
- byte[] contents = Util.getResourceContentsAsByteArray(file);
+ byte[] contents;
+ try (InputStream stream = file.getContents(true)) {
+ contents = org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1);
+ } catch (CoreException e) {
+ IStatus status = e.getStatus();
+ if (status.getCode() == IResourceStatus.RESOURCE_NOT_FOUND) {
+ throw new FileNotFoundException();
+ }
+ throw new JavaModelException(e);
+ } catch (IOException e) {
+ throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+ }
return new ClassFileReader(contents, file.getFullPath().toString().toCharArray(), fullyInitialize);
}
return null;
@@ -217,8 +243,8 @@
throw new JavaModelException(e);
}
} catch (IndexException e) {
- // Index corrupted. Rebuild it.
- index.rebuildIndex();
+ Package.log("Index corruption detected. Rebuilding index.", e); //$NON-NLS-1$
+ Indexer.getInstance().requestRebuildIndex();
}
}
}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/Package.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/Package.java
new file mode 100644
index 0000000..1aad354
--- /dev/null
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/nd/java/model/Package.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2015, 2016 Google, Inc and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stefan Xenos (Google) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.core.nd.java.model;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jdt.core.JavaCore;
+
+/* package */ class Package {
+ public static String PLUGIN_ID = JavaCore.PLUGIN_ID;
+
+ public static void log(Throwable e) {
+ String msg = e.getMessage();
+ if (msg == null) {
+ log("Error", e); //$NON-NLS-1$
+ } else {
+ log("Error: " + msg, e); //$NON-NLS-1$
+ }
+ }
+
+ public static void log(String message, Throwable e) {
+ log(createStatus(message, e));
+ }
+
+ public static IStatus createStatus(String msg, Throwable e) {
+ return new Status(IStatus.ERROR, PLUGIN_ID, msg, e);
+ }
+
+ public static IStatus createStatus(String msg) {
+ return new Status(IStatus.ERROR, PLUGIN_ID, msg);
+ }
+
+ public static void logInfo(String message) {
+ log(new Status(IStatus.INFO, PLUGIN_ID, message));
+ }
+
+ public static void log(IStatus status) {
+ JavaCore.getPlugin().getLog().log(status);
+ }
+}
diff --git a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
index 7ce53fa..dc72697 100644
--- a/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
+++ b/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/IndexManager.java
@@ -28,6 +28,7 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
@@ -164,7 +165,7 @@
if (count > 0)
removeIndexesState(locations);
}
- deleteIndexFiles(knownPaths);
+ deleteIndexFiles(knownPaths, null);
}
/**
* Compute the pre-built index location for a specified URL
@@ -212,17 +213,25 @@
}
return indexLocation;
}
-public void deleteIndexFiles() {
+/**
+ * Use {@link #deleteIndexFiles(IProgressMonitor)}
+ */
+public final void deleteIndexFiles() {
+ deleteIndexFiles(null);
+}
+public void deleteIndexFiles(IProgressMonitor monitor) {
if (DEBUG)
Util.verbose("Deleting index files"); //$NON-NLS-1$
this.savedIndexNamesFile.delete(); // forget saved indexes & delete each index file
- deleteIndexFiles(null);
+ deleteIndexFiles(null, monitor);
}
-private void deleteIndexFiles(SimpleSet pathsToKeep) {
+private void deleteIndexFiles(SimpleSet pathsToKeep, IProgressMonitor monitor) {
File[] indexesFiles = getSavedIndexesDirectory().listFiles();
if (indexesFiles == null) return;
+ SubMonitor subMonitor = SubMonitor.convert(monitor, indexesFiles.length);
for (int i = 0, l = indexesFiles.length; i < l; i++) {
+ subMonitor.split(1);
String fileName = indexesFiles[i].getAbsolutePath();
if (pathsToKeep != null && pathsToKeep.includes(new FileIndexLocation(indexesFiles[i]))) continue;
String suffix = ".index"; //$NON-NLS-1$
@@ -865,14 +874,16 @@
/**
* Flush current state
*/
-public synchronized void reset() {
+public void reset() {
super.reset();
- if (this.indexes != null) {
- this.indexes = new SimpleLookupTable();
- this.indexStates = null;
+ synchronized (this) {
+ if (this.indexes != null) {
+ this.indexes = new SimpleLookupTable();
+ this.indexStates = null;
+ }
+ this.indexLocations = new SimpleLookupTable();
+ this.javaPluginLocation = null;
}
- this.indexLocations = new SimpleLookupTable();
- this.javaPluginLocation = null;
}
/**
* Resets the index for a given path.
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 71bc061..7c07d0f 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
@@ -297,22 +297,29 @@
/**
* Flush current state
*/
- public synchronized void reset() {
+ public void reset() {
if (VERBOSE)
Util.verbose("Reset"); //$NON-NLS-1$
- if (this.processingThread != null) {
+ Thread thread;
+ synchronized (this) {
+ thread = this.processingThread;
+ }
+
+ if (thread != null) {
discardJobs(null); // discard all jobs
} else {
- /* initiate background processing */
- 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);
- // 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());
- this.processingThread.start();
+ synchronized (this) {
+ /* initiate background processing */
+ 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);
+ // 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());
+ this.processingThread.start();
+ }
}
}
/**