Bug 549989: Extract the JavaContextCore and move it to jdt.core.manipulation
- Initialize IJavaContext
- Extract out the JavaContextCore
- Apply JavaContextCore inside JavaContext
- Move MultiVariable, CompilationUnitCompletion, JavaVariable to jdt.core.manipulation
Change-Id: Id6bbe6be5b77ee0a8b5d4f19872c19ea5032ca43
Signed-off-by: Sheng Chen <sheche@microsoft.com>
diff --git a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
index 5ac167a..8479d66 100644
--- a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
@@ -58,6 +58,7 @@
org.eclipse.jdt.internal.ui.text;x-friends:="org.eclipse.jdt.ui",
org.eclipse.jdt.internal.ui.text.correction;x-friends:="org.eclipse.jdt.ui",
org.eclipse.jdt.internal.ui.text.correction.proposals;x-friends:="org.eclipse.jdt.ui",
+ org.eclipse.jdt.internal.ui.text.template.contentassist;x-friends:="org.eclipse.jdt.ui",
org.eclipse.jdt.internal.ui.util;x-friends:="org.eclipse.jdt.ui"
Import-Package: com.ibm.icu.text
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/MultiVariable.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/template/contentassist/MultiVariable.java
similarity index 95%
rename from org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/MultiVariable.java
rename to org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/template/contentassist/MultiVariable.java
index 5f58ea4..11070e0 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/template/contentassist/MultiVariable.java
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/text/template/contentassist/MultiVariable.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2011 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Microsoft Corporation - moved template related code to jdt.core.manipulation - https://bugs.eclipse.org/549989
*******************************************************************************/
package org.eclipse.jdt.internal.ui.text.template.contentassist;
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/CompilationUnitCompletion.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/CompilationUnitCompletion.java
similarity index 98%
rename from org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/CompilationUnitCompletion.java
rename to org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/CompilationUnitCompletion.java
index e330692..1024de3 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/CompilationUnitCompletion.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/CompilationUnitCompletion.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2018 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -11,6 +11,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Lukas Hanke <hanke@yatta.de> - [templates][content assist] Content assist for 'for' loop should suggest member variables - https://bugs.eclipse.org/117215
+ * Microsoft Corporation - moved template related code to jdt.core.manipulation - https://bugs.eclipse.org/549989
*******************************************************************************/
package org.eclipse.jdt.internal.corext.template.java;
@@ -37,7 +38,7 @@
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.compiler.IProblem;
-import org.eclipse.jdt.internal.ui.JavaPlugin;
+import org.eclipse.jdt.internal.core.manipulation.JavaManipulationPlugin;
/**
* A completion requester to collect informations on local variables.
@@ -142,7 +143,7 @@
String implementorName= SignatureUtil.stripSignatureToFQN(signature);
if (implementorName.length() == 0)
return false;
-
+
int implementorDims= Signature.getArrayCount(signature);
int superDimsIndex= supertype.indexOf("[]"); //$NON-NLS-1$
int superDims;
@@ -415,7 +416,7 @@
IJavaProject project= fUnit.getJavaProject();
IType type= project.findType(superType);
if (type == null)
- throw new JavaModelException(new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK, "No such type", null))); //$NON-NLS-1$
+ throw new JavaModelException(new CoreException(new Status(IStatus.ERROR, JavaManipulationPlugin.getPluginId(), IStatus.OK, "No such type", null))); //$NON-NLS-1$
return computeBinding(type, index);
}
@@ -584,7 +585,7 @@
}
}
- throw new JavaModelException(new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK, "Illegal hierarchy", null))); //$NON-NLS-1$
+ throw new JavaModelException(new CoreException(new Status(IStatus.ERROR, JavaManipulationPlugin.getPluginId(), IStatus.OK, "Illegal hierarchy", null))); //$NON-NLS-1$
}
/**
@@ -846,7 +847,7 @@
/**
* Returns all arrays, visible in the current context's scope, in the order that they appear.
- *
+ *
* @return all visible arrays
*/
public Variable[] findArraysInCurrentScope() {
@@ -859,7 +860,7 @@
if (localVariable.isArray())
arrays.add(localVariable);
}
-
+
// fields
for (ListIterator<Variable> iterator= fFields.listIterator(fFields.size()); iterator.hasPrevious();) {
Variable field= iterator.previous();
@@ -915,7 +916,7 @@
* Returns all variables, visible in the current context's scope, implementing
* <code>java.lang.Iterable</code> <em>and</em> all arrays, in the order that they appear. That
* is, the returned variables can be used within the <code>foreach</code> language construct.
- *
+ *
* @return all visible <code>Iterable</code>s and arrays
*/
public Variable[] findIterablesInCurrentScope() {
@@ -928,7 +929,7 @@
if (localVariable.isArray() || localVariable.isIterable())
iterables.add(localVariable);
}
-
+
// fields
for (ListIterator<Variable> iterator= fFields.listIterator(fFields.size()); iterator.hasPrevious();) {
Variable field= iterator.previous();
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/IJavaContext.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/IJavaContext.java
new file mode 100644
index 0000000..1a8e463
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/IJavaContext.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Microsoft Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Microsoft Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.template.java;
+
+import org.eclipse.jface.text.templates.TemplateVariable;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+
+import org.eclipse.jdt.internal.corext.template.java.CompilationUnitCompletion.Variable;
+
+import org.eclipse.jdt.internal.ui.text.template.contentassist.MultiVariable;
+
+public interface IJavaContext {
+
+ /**
+ * Returns the compilation unit if one is associated with this context,
+ * <code>null</code> otherwise.
+ *
+ * @return the compilation unit of this context or <code>null</code>
+ */
+ ICompilationUnit getCompilationUnit();
+
+ /**
+ * Exception handler when generate the template
+ * @param e Exception
+ */
+ void handleException(Exception e);
+
+ /**
+ * Returns the names of arrays available in the current {@link CompilationUnit}'s scope.
+ *
+ * @return the names of local arrays available in the current {@link CompilationUnit}'s scope
+ */
+ Variable[] getArrays();
+
+ /**
+ * Returns the names of local variables matching <code>type</code>.
+ *
+ * @param type the type of the variables
+ * @return the names of local variables matching <code>type</code>
+ * @since 3.3
+ */
+ Variable[] getLocalVariables(String type);
+
+ /**
+ * Returns the names of fields matching <code>type</code>.
+ *
+ * @param type the type of the fields
+ * @return the names of fields matching <code>type</code>
+ * @since 3.3
+ */
+ Variable[] getFields(String type);
+
+ /**
+ * Returns the names of iterables or arrays available in the current {@link CompilationUnit}'s scope.
+ *
+ * @return the names of iterables or arrays available in the current {@link CompilationUnit}'s scope
+ */
+ Variable[] getIterables();
+
+ /**
+ * Marks the name as used.
+ * @param name the name to be marked
+ */
+ void markAsUsed(String name);
+
+ /**
+ * Return the suggested names matching <code>type</code>
+ * @param type the type of the variable
+ * @return the suggested names matching <code>type</code>
+ * @throws IllegalArgumentException Exception
+ */
+ String[] suggestVariableNames(String type) throws IllegalArgumentException;
+
+ /**
+ * Adds an import for type with type name <code>type</code> if possible.
+ * Returns a string which can be used to reference the type.
+ *
+ * @param type the fully qualified name of the type to import
+ * @return returns a type to which the type binding can be assigned to.
+ * The returned type contains is unqualified when an import could be added or was already known.
+ * It is fully qualified, if an import conflict prevented the import.
+ * @since 3.4
+ */
+ String addImport(String type);
+
+ /**
+ * Return the template variable matching <code>name</code>
+ * @param name the variable name
+ * @return the template variable matching <code>name</code>
+ */
+ TemplateVariable getTemplateVariable(String name);
+
+ /**
+ * Adds a multi-variable guess dependency.
+ *
+ * @param master the master variable - <code>slave</code> needs to be updated when
+ * <code>master</code> changes
+ * @param slave the dependent variable
+ * @since 3.3
+ */
+ void addDependency(MultiVariable master, MultiVariable slave);
+}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/JavaContextCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/JavaContextCore.java
new file mode 100644
index 0000000..a1bf21c
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/JavaContextCore.java
@@ -0,0 +1,752 @@
+/*******************************************************************************
+ * Copyright (c) 2019 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Lars Vogel <lars.vogel@gmail.com> - [templates][content assist] Ctrl+Space without any starting letter shows to no templates - https://bugs.eclipse.org/406463
+ * Lukas Hanke <hanke@yatta.de> - [templates][content assist] Content assist for 'for' loop should suggest member variables - https://bugs.eclipse.org/117215
+ * Nicolaj Hoess <nicohoess@gmail.com> - Make some internal methods accessible to help Postfix Code Completion plug-in - https://bugs.eclipse.org/433500
+ * Microsoft Corporation - moved template related code to jdt.core.manipulation - https://bugs.eclipse.org/549989
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.template.java;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.BadPositionCategoryException;
+import org.eclipse.jface.text.DefaultPositionUpdater;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IPositionUpdater;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.templates.DocumentTemplateContext;
+import org.eclipse.jface.text.templates.Template;
+import org.eclipse.jface.text.templates.TemplateBuffer;
+import org.eclipse.jface.text.templates.TemplateContextType;
+import org.eclipse.jface.text.templates.TemplateException;
+import org.eclipse.jface.text.templates.TemplateTranslator;
+import org.eclipse.jface.text.templates.TemplateVariable;
+import org.eclipse.jface.text.templates.TemplateVariableType;
+
+import org.eclipse.jdt.core.Flags;
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IField;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.IMethod;
+import org.eclipse.jdt.core.IType;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
+import org.eclipse.jdt.core.NamingConventions;
+import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
+import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
+import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
+import org.eclipse.jdt.core.manipulation.TypeKinds;
+import org.eclipse.jdt.core.manipulation.TypeNameMatchCollector;
+import org.eclipse.jdt.core.search.IJavaSearchConstants;
+import org.eclipse.jdt.core.search.IJavaSearchScope;
+import org.eclipse.jdt.core.search.SearchEngine;
+import org.eclipse.jdt.core.search.SearchPattern;
+import org.eclipse.jdt.core.search.TypeNameMatch;
+
+import org.eclipse.jdt.internal.core.manipulation.JavaManipulationPlugin;
+import org.eclipse.jdt.internal.core.manipulation.StubUtility;
+import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
+import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
+import org.eclipse.jdt.internal.corext.template.java.CompilationUnitCompletion.Variable;
+import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
+
+import org.eclipse.jdt.internal.ui.text.template.contentassist.MultiVariable;
+
+
+/**
+ * A context for Java source.
+ */
+public class JavaContextCore extends CompilationUnitContextCore implements IJavaContext {
+
+ /** A code completion requester for guessing local variable names. */
+ private CompilationUnitCompletion fCompletion;
+ /**
+ * The list of used local names.
+ * @since 3.3
+ */
+ private Set<String> fUsedNames= new HashSet<>();
+ private Map<String, MultiVariable> fVariables= new HashMap<>();
+ private ImportRewrite fImportRewrite;
+
+ private Set<String> fCompatibleContextTypeIds;
+
+ private DocumentTemplateContext fContext;
+
+ /**
+ * Creates a java template context.
+ *
+ * @param context the JavaContext instance
+ * @param type the context type.
+ * @param document the document.
+ * @param completionOffset the completion offset within the document.
+ * @param completionLength the completion length.
+ * @param compilationUnit the compilation unit (may be <code>null</code>).
+ */
+ public JavaContextCore(DocumentTemplateContext context, TemplateContextType type, IDocument document, int completionOffset, int completionLength, ICompilationUnit compilationUnit) {
+ super(type, document, completionOffset, completionLength, compilationUnit);
+ this.fContext = context;
+ }
+
+ /**
+ * Creates a java template context.
+ *
+ * @param type the context type.
+ * @param document the document.
+ * @param completionOffset the completion offset within the document.
+ * @param completionLength the completion length.
+ * @param compilationUnit the compilation unit (may be <code>null</code>).
+ */
+ public JavaContextCore(TemplateContextType type, IDocument document, int completionOffset, int completionLength, ICompilationUnit compilationUnit) {
+ super(type, document, completionOffset, completionLength, compilationUnit);
+ this.fContext = this;
+ }
+
+ /**
+ * Creates a java template context.
+ *
+ * @param context the JavaContext instance
+ * @param type the context type.
+ * @param document the document.
+ * @param completionPosition the position defining the completion offset and length
+ * @param compilationUnit the compilation unit (may be <code>null</code>).
+ * @since 3.2
+ */
+ public JavaContextCore(DocumentTemplateContext context, TemplateContextType type, IDocument document, Position completionPosition, ICompilationUnit compilationUnit) {
+ super(type, document, completionPosition, compilationUnit);
+ this.fContext = context;
+ }
+
+ /**
+ * Creates a java template context.
+ *
+ * @param type the context type.
+ * @param document the document.
+ * @param completionPosition the position defining the completion offset and length
+ * @param compilationUnit the compilation unit (may be <code>null</code>).
+ * @since 3.2
+ */
+ public JavaContextCore(TemplateContextType type, IDocument document, Position completionPosition, ICompilationUnit compilationUnit) {
+ super(type, document, completionPosition, compilationUnit);
+ this.fContext = this;
+ }
+
+ /**
+ * Adds a context type that is also compatible. That means the context can also process templates of that context type.
+ *
+ * @param contextTypeId the context type to accept
+ */
+ public void addCompatibleContextType(String contextTypeId) {
+ if (fCompatibleContextTypeIds == null)
+ fCompatibleContextTypeIds= new HashSet<>();
+ fCompatibleContextTypeIds.add(contextTypeId);
+ }
+
+ /*
+ * @see TemplateContext#evaluate(Template template)
+ */
+ @Override
+ public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException {
+ clear();
+
+ if (!canEvaluate(template))
+ throw new TemplateException(JavaTemplateMessages.Context_error_cannot_evaluate);
+
+ TemplateTranslator translator= new TemplateTranslator() {
+ @Override
+ protected TemplateVariable createVariable(TemplateVariableType type, String name, int[] offsets) {
+// TemplateVariableResolver resolver= getContextType().getResolver(type.getName());
+// return resolver.createVariable();
+
+ MultiVariable variable= new JavaVariable(type, name, offsets);
+ fVariables.put(name, variable);
+ return variable;
+ }
+ };
+ TemplateBuffer buffer= translator.translate(template);
+
+ getContextType().resolve(buffer, fContext);
+
+ rewriteImports();
+
+ clear();
+
+ return buffer;
+ }
+
+ private void clear() {
+ fUsedNames.clear();
+ fImportRewrite= null;
+ }
+
+ /*
+ * @see TemplateContext#canEvaluate(Template templates)
+ */
+ @Override
+ public boolean canEvaluate(Template template) {
+ if (!hasCompatibleContextType(template))
+ return false;
+
+ if (this.isForceEvaluation())
+ return true;
+
+ String key= getKey().toLowerCase();
+ if (key.length() > 0 || !isAfterDot()) {
+ String templateName= template.getName().toLowerCase();
+ return JavaCore.ENABLED.equals(JavaCore.getOption(JavaCore.CODEASSIST_SUBSTRING_MATCH))
+ ? templateName.contains(key)
+ : templateName.startsWith(key);
+ }
+ return false;
+ }
+
+ private boolean isAfterDot() {
+ try {
+ IDocument document= getDocument();
+ int offset= getCompletionOffset();
+ return document.get(offset - 1, 1).charAt(0) == '.';
+ } catch (BadLocationException e) {
+ return false;
+ }
+ }
+
+ private boolean hasCompatibleContextType(Template template) {
+ String key= getKey();
+ if (template.matches(key, getContextType().getId()))
+ return true;
+
+ if (fCompatibleContextTypeIds == null)
+ return false;
+
+ Iterator<String> iter= fCompatibleContextTypeIds.iterator();
+ while (iter.hasNext()) {
+ if (template.matches(key, iter.next()))
+ return true;
+ }
+
+ return false;
+ }
+
+ /*
+ * @see DocumentTemplateContext#getCompletionPosition();
+ */
+ @Override
+ public int getStart() {
+
+ if (this.isManaged() && getCompletionLength() > 0)
+ return super.getStart();
+
+ try {
+ IDocument document= getDocument();
+
+ int start= getCompletionOffset();
+ int end= getCompletionOffset() + getCompletionLength();
+
+ while (start != 0 && Character.isUnicodeIdentifierPart(document.getChar(start - 1)))
+ start--;
+
+ while (start != end && Character.isWhitespace(document.getChar(start)))
+ start++;
+
+ if (start == end)
+ start= getCompletionOffset();
+
+ return start;
+
+ } catch (BadLocationException e) {
+ return super.getStart();
+ }
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.corext.template.DocumentTemplateContext#getEnd()
+ */
+ @Override
+ public int getEnd() {
+
+ if (this.isManaged() || getCompletionLength() == 0)
+ return super.getEnd();
+
+ try {
+ IDocument document= getDocument();
+
+ int start= getCompletionOffset();
+ int end= getCompletionOffset() + getCompletionLength();
+
+ while (start != end && Character.isWhitespace(document.getChar(end - 1)))
+ end--;
+
+ return end;
+
+ } catch (BadLocationException e) {
+ return super.getEnd();
+ }
+ }
+
+ /*
+ * @see org.eclipse.jdt.internal.corext.template.DocumentTemplateContext#getKey()
+ */
+ @Override
+ public String getKey() {
+
+ if (getCompletionLength() == 0)
+ return super.getKey();
+
+ try {
+ IDocument document= getDocument();
+
+ int start= getStart();
+ int end= getCompletionOffset();
+ return start <= end
+ ? document.get(start, end - start)
+ : ""; //$NON-NLS-1$
+
+ } catch (BadLocationException e) {
+ return super.getKey();
+ }
+ }
+
+ /**
+ * Returns the character before the start position of the completion.
+ *
+ * @return the character before the start position of the completion
+ */
+ public char getCharacterBeforeStart() {
+ int start= getStart();
+
+ try {
+ return start == 0
+ ? ' '
+ : getDocument().getChar(start - 1);
+
+ } catch (BadLocationException e) {
+ return ' ';
+ }
+ }
+
+ @Override
+ public void handleException(Exception e) {
+ if (fContext != this && fContext instanceof IJavaContext) {
+ // invoke handleException() in JavaContext
+ ((IJavaContext) fContext).handleException(e);
+ } else {
+ JavaManipulationPlugin.log(e);
+ }
+
+ }
+
+ private CompilationUnitCompletion getCompletion() {
+ ICompilationUnit compilationUnit= getCompilationUnit();
+ if (fCompletion == null) {
+ fCompletion= new CompilationUnitCompletion(compilationUnit);
+
+ if (compilationUnit != null) {
+ try {
+ compilationUnit.codeComplete(getStart(), fCompletion);
+ } catch (JavaModelException e) {
+ // ignore
+ }
+ }
+ }
+
+ return fCompletion;
+ }
+
+ /**
+ * Returns the names of arrays available in the current {@link CompilationUnit}'s scope.
+ *
+ * @return the names of local arrays available in the current {@link CompilationUnit}'s scope
+ */
+ @Override
+ public Variable[] getArrays() {
+ Variable[] arrays= getCompletion().findArraysInCurrentScope();
+ arrange(arrays);
+ return arrays;
+ }
+
+ /**
+ * Sorts already used variables behind any that are not yet used.
+ *
+ * @param variables the variables to sort
+ * @since 3.3
+ */
+ private void arrange(Variable[] variables) {
+ Arrays.sort(variables, new Comparator<Variable>() {
+ @Override
+ public int compare(Variable o1, Variable o2) {
+ return rank(o1) - rank(o2);
+ }
+
+ private int rank(Variable l) {
+ return fUsedNames.contains(l.getName()) ? 1 : 0;
+ }
+ });
+ }
+
+ /**
+ * Returns the names of local variables matching <code>type</code>.
+ *
+ * @param type the type of the variables
+ * @return the names of local variables matching <code>type</code>
+ * @since 3.3
+ */
+ @Override
+ public Variable[] getLocalVariables(String type) {
+ Variable[] localVariables= getCompletion().findLocalVariables(type);
+ arrange(localVariables);
+ return localVariables;
+ }
+
+ /**
+ * Returns the names of fields matching <code>type</code>.
+ *
+ * @param type the type of the fields
+ * @return the names of fields matching <code>type</code>
+ * @since 3.3
+ */
+ @Override
+ public Variable[] getFields(String type) {
+ Variable[] fields= getCompletion().findFieldVariables(type);
+ arrange(fields);
+ return fields;
+ }
+
+ /**
+ * Returns the names of iterables or arrays available in the current {@link CompilationUnit}'s scope.
+ *
+ * @return the names of iterables or arrays available in the current {@link CompilationUnit}'s scope
+ */
+ @Override
+ public Variable[] getIterables() {
+ Variable[] iterables= getCompletion().findIterablesInCurrentScope();
+ arrange(iterables);
+ return iterables;
+ }
+
+ @Override
+ public void markAsUsed(String name) {
+ fUsedNames.add(name);
+ }
+
+ @Override
+ public String[] suggestVariableNames(String type) throws IllegalArgumentException {
+ String[] excludes= computeExcludes();
+ // TODO erasure, arrays, etc.
+ String[] result= suggestVariableName(type, excludes);
+ return result;
+ }
+
+ public String[] computeExcludes() {
+ String[] excludes= getCompletion().getLocalVariableNames();
+ if (!fUsedNames.isEmpty()) {
+ String[] allExcludes= new String[fUsedNames.size() + excludes.length];
+ System.arraycopy(excludes, 0, allExcludes, 0, excludes.length);
+ System.arraycopy(fUsedNames.toArray(), 0, allExcludes, 0, fUsedNames.size());
+ excludes= allExcludes;
+ }
+ return excludes;
+ }
+
+ private String[] suggestVariableName(String type, String[] excludes) throws IllegalArgumentException {
+ int dim=0;
+ while (type.endsWith("[]")) {//$NON-NLS-1$
+ dim++;
+ type= type.substring(0, type.length() - 2);
+ }
+
+ IJavaProject project= getJavaProject();
+ if (project != null)
+ return StubUtility.getVariableNameSuggestions(NamingConventions.VK_LOCAL, project, type, dim, Arrays.asList(excludes), true);
+
+ // fallback if we lack proper context: roll-our own lowercasing
+ return new String[] {Signature.getSimpleName(type).toLowerCase()};
+ }
+
+ /**
+ * Adds an import for type with type name <code>type</code> if possible.
+ * Returns a string which can be used to reference the type.
+ *
+ * @param type the fully qualified name of the type to import
+ * @return returns a type to which the type binding can be assigned to.
+ * The returned type contains is unqualified when an import could be added or was already known.
+ * It is fully qualified, if an import conflict prevented the import.
+ * @since 3.4
+ */
+ @Override
+ public String addImport(String type) {
+ if (isReadOnly())
+ return type;
+
+ ICompilationUnit cu= getCompilationUnit();
+ if (cu == null)
+ return type;
+
+ try {
+ boolean qualified= type.indexOf('.') != -1;
+ if (!qualified) {
+ IJavaSearchScope searchScope= SearchEngine.createJavaSearchScope(new IJavaElement[] { cu.getJavaProject() });
+ SimpleName nameNode= null;
+ TypeNameMatch[] matches= findAllTypes(type, searchScope, nameNode, null, cu);
+ if (matches.length != 1) // only add import if we have a single match
+ return type;
+ type= matches[0].getFullyQualifiedName();
+ }
+
+ CompilationUnit root= getASTRoot(cu);
+ if (fImportRewrite == null) {
+ if (root == null) {
+ fImportRewrite= StubUtility.createImportRewrite(cu, true);
+ } else {
+ fImportRewrite= StubUtility.createImportRewrite(root, true);
+ }
+ }
+
+ ImportRewriteContext context;
+ if (root == null)
+ context= null;
+ else
+ context= new ContextSensitiveImportRewriteContext(root, getCompletionOffset(), fImportRewrite);
+
+ return fImportRewrite.addImport(type, context);
+ } catch (JavaModelException e) {
+ handleException(e);
+ return type;
+ }
+ }
+
+ /**
+ * Adds a static import for the member with name <code>qualifiedMemberName</code>. The member is
+ * either a static field or a static method or a '*' to import all static members of a type.
+ *
+ * @param qualifiedMemberName the fully qualified name of the member to import or a qualified type
+ * name plus a '.*' suffix.
+ * @return returns either the simple member name if the import was successful or else the qualified name.
+ * @since 3.4
+ */
+ public String addStaticImport(String qualifiedMemberName) {
+ if (isReadOnly())
+ return qualifiedMemberName;
+
+ ICompilationUnit cu= getCompilationUnit();
+ if (cu == null)
+ return qualifiedMemberName;
+
+ int memberOffset= qualifiedMemberName.lastIndexOf('.');
+ if (memberOffset == -1)
+ return qualifiedMemberName;
+
+ String typeName= qualifiedMemberName.substring(0, memberOffset);
+ String memberName= qualifiedMemberName.substring(memberOffset + 1, qualifiedMemberName.length());
+ try {
+ boolean isField;
+ if ("*".equals(memberName)) { //$NON-NLS-1$
+ isField= true;
+ } else {
+ IJavaProject javaProject= cu.getJavaProject();
+
+ IType type= javaProject.findType(typeName);
+ if (type == null)
+ return qualifiedMemberName;
+
+ IField field= type.getField(memberName);
+ if (field.exists()) {
+ isField= true;
+ } else if (hasMethod(type, memberName)) {
+ isField= false;
+ } else {
+ return qualifiedMemberName;
+ }
+ }
+
+ CompilationUnit root= getASTRoot(cu);
+ if (fImportRewrite == null) {
+ if (root == null) {
+ fImportRewrite= StubUtility.createImportRewrite(cu, true);
+ } else {
+ fImportRewrite= StubUtility.createImportRewrite(root, true);
+ }
+ }
+
+ ImportRewriteContext context;
+ if (root == null)
+ context= null;
+ else
+ context= new ContextSensitiveImportRewriteContext(root, getCompletionOffset(), fImportRewrite);
+
+ return fImportRewrite.addStaticImport(typeName, memberName, isField, context);
+ } catch (JavaModelException e) {
+ handleException(e);
+ return typeName;
+ }
+ }
+
+ /**
+ * Does <code>type</code> contain a method with <code>name</code>?
+ *
+ * @param type the type to inspect
+ * @param name the name of the method to search for
+ * @return true if has such a method
+ * @throws JavaModelException if methods could not be retrieved
+ * @since 3.4
+ */
+ private boolean hasMethod(IType type, String name) throws JavaModelException {
+ IMethod[] methods= type.getMethods();
+ for (int i= 0; i < methods.length; i++) {
+ if (name.equals(methods[i].getElementName()))
+ return true;
+ }
+
+ return false;
+ }
+
+ private void rewriteImports() {
+ if (fImportRewrite == null)
+ return;
+
+ if (isReadOnly())
+ return;
+
+ ICompilationUnit cu= getCompilationUnit();
+ if (cu == null)
+ return;
+
+ try {
+ Position position= new Position(getCompletionOffset(), 0);
+ IDocument document= getDocument();
+ final String category= "__template_position_importer" + System.currentTimeMillis(); //$NON-NLS-1$
+ IPositionUpdater updater= new DefaultPositionUpdater(category);
+ document.addPositionCategory(category);
+ document.addPositionUpdater(updater);
+ document.addPosition(position);
+
+ try {
+ JavaModelUtil.applyEdit(cu, fImportRewrite.rewriteImports(null), false, null);
+
+ setCompletionOffset(position.getOffset());
+ } catch (CoreException e) {
+ handleException(e);
+ } finally {
+ document.removePosition(position);
+ document.removePositionUpdater(updater);
+ document.removePositionCategory(category);
+ }
+ } catch (BadLocationException e) {
+ handleException(e);
+ } catch (BadPositionCategoryException e) {
+ handleException(e);
+ }
+ }
+
+ private CompilationUnit getASTRoot(ICompilationUnit compilationUnit) {
+ return SharedASTProviderCore.getAST(compilationUnit, SharedASTProviderCore.WAIT_NO, new NullProgressMonitor());
+ }
+
+ /*
+ * Finds a type by the simple name. From AddImportsOperation
+ */
+ private TypeNameMatch[] findAllTypes(String simpleTypeName, IJavaSearchScope searchScope, SimpleName nameNode, IProgressMonitor monitor, ICompilationUnit cu) throws JavaModelException {
+ boolean is50OrHigher= JavaModelUtil.is50OrHigher(cu.getJavaProject());
+
+ int typeKinds= TypeKinds.ALL_TYPES;
+ if (nameNode != null) {
+ typeKinds= ASTResolving.getPossibleTypeKinds(nameNode, is50OrHigher);
+ }
+
+ ArrayList<TypeNameMatch> typeInfos= new ArrayList<>();
+ TypeNameMatchCollector requestor= new TypeNameMatchCollector(typeInfos);
+ new SearchEngine().searchAllTypeNames(null, 0, simpleTypeName.toCharArray(), SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE, getSearchForConstant(typeKinds), searchScope, requestor, IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH, monitor);
+
+ ArrayList<TypeNameMatch> typeRefsFound= new ArrayList<>(typeInfos.size());
+ for (int i= 0, len= typeInfos.size(); i < len; i++) {
+ TypeNameMatch curr= typeInfos.get(i);
+ if (curr.getPackageName().length() > 0) { // do not suggest imports from the default package
+ if (isOfKind(curr, typeKinds, is50OrHigher) && isVisible(curr, cu)) {
+ typeRefsFound.add(curr);
+ }
+ }
+ }
+ return typeRefsFound.toArray(new TypeNameMatch[typeRefsFound.size()]);
+ }
+
+ private int getSearchForConstant(int typeKinds) {
+ final int CLASSES= TypeKinds.CLASSES;
+ final int INTERFACES= TypeKinds.INTERFACES;
+ final int ENUMS= TypeKinds.ENUMS;
+ final int ANNOTATIONS= TypeKinds.ANNOTATIONS;
+
+ switch (typeKinds & (CLASSES | INTERFACES | ENUMS | ANNOTATIONS)) {
+ case CLASSES: return IJavaSearchConstants.CLASS;
+ case INTERFACES: return IJavaSearchConstants.INTERFACE;
+ case ENUMS: return IJavaSearchConstants.ENUM;
+ case ANNOTATIONS: return IJavaSearchConstants.ANNOTATION_TYPE;
+ case CLASSES | INTERFACES: return IJavaSearchConstants.CLASS_AND_INTERFACE;
+ case CLASSES | ENUMS: return IJavaSearchConstants.CLASS_AND_ENUM;
+ default: return IJavaSearchConstants.TYPE;
+ }
+ }
+
+ private boolean isOfKind(TypeNameMatch curr, int typeKinds, boolean is50OrHigher) {
+ int flags= curr.getModifiers();
+ if (Flags.isAnnotation(flags)) {
+ return is50OrHigher && ((typeKinds & TypeKinds.ANNOTATIONS) != 0);
+ }
+ if (Flags.isEnum(flags)) {
+ return is50OrHigher && ((typeKinds & TypeKinds.ENUMS) != 0);
+ }
+ if (Flags.isInterface(flags)) {
+ return (typeKinds & TypeKinds.INTERFACES) != 0;
+ }
+ return (typeKinds & TypeKinds.CLASSES) != 0;
+ }
+
+
+ private boolean isVisible(TypeNameMatch curr, ICompilationUnit cu) {
+ int flags= curr.getModifiers();
+ if (Flags.isPrivate(flags)) {
+ return false;
+ }
+ if (Flags.isPublic(flags) || Flags.isProtected(flags)) {
+ return true;
+ }
+ return curr.getPackageName().equals(cu.getParent().getElementName());
+ }
+
+ @Override
+ public TemplateVariable getTemplateVariable(String name) {
+ TemplateVariable variable= fVariables.get(name);
+ if (variable != null && !variable.isResolved())
+ getContextType().resolve(variable, fContext);
+ return variable;
+ }
+
+ @Override
+ public void addDependency(MultiVariable master, MultiVariable slave) {
+ // Do nothing
+ }
+
+}
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaVariable.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/JavaVariable.java
similarity index 90%
rename from org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaVariable.java
rename to org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/JavaVariable.java
index 7d54ce4..639b911 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaVariable.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/template/java/JavaVariable.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2011 IBM Corporation and others.
+ * Copyright (c) 2006, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
+ * Microsoft Corporation - moved template related code to jdt.core.manipulation - https://bugs.eclipse.org/549989
*******************************************************************************/
package org.eclipse.jdt.internal.corext.template.java;
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaContext.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaContext.java
index 5aefdc1..d9062e6 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaContext.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/template/java/JavaContext.java
@@ -18,29 +18,14 @@
package org.eclipse.jdt.internal.corext.template.java;
import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import org.eclipse.swt.widgets.Shell;
import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.BadPositionCategoryException;
-import org.eclipse.jface.text.DefaultPositionUpdater;
import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IPositionUpdater;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.TextUtilities;
@@ -48,40 +33,14 @@
import org.eclipse.jface.text.templates.TemplateBuffer;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateException;
-import org.eclipse.jface.text.templates.TemplateTranslator;
import org.eclipse.jface.text.templates.TemplateVariable;
-import org.eclipse.jface.text.templates.TemplateVariableType;
-import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.ICompilationUnit;
-import org.eclipse.jdt.core.IField;
-import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
-import org.eclipse.jdt.core.IMethod;
-import org.eclipse.jdt.core.IType;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jdt.core.JavaModelException;
-import org.eclipse.jdt.core.NamingConventions;
-import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.CompilationUnit;
-import org.eclipse.jdt.core.dom.SimpleName;
-import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
-import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
-import org.eclipse.jdt.core.manipulation.SharedASTProviderCore;
-import org.eclipse.jdt.core.manipulation.TypeKinds;
-import org.eclipse.jdt.core.manipulation.TypeNameMatchCollector;
-import org.eclipse.jdt.core.search.IJavaSearchConstants;
-import org.eclipse.jdt.core.search.IJavaSearchScope;
-import org.eclipse.jdt.core.search.SearchEngine;
-import org.eclipse.jdt.core.search.SearchPattern;
-import org.eclipse.jdt.core.search.TypeNameMatch;
-import org.eclipse.jdt.internal.core.manipulation.StubUtility;
-import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
import org.eclipse.jdt.internal.core.manipulation.util.Strings;
-import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
import org.eclipse.jdt.internal.corext.template.java.CompilationUnitCompletion.Variable;
-import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.ui.PreferenceConstants;
@@ -94,19 +53,9 @@
/**
* A context for Java source.
*/
-public class JavaContext extends CompilationUnitContext {
+public class JavaContext extends CompilationUnitContext implements IJavaContext {
- /** A code completion requester for guessing local variable names. */
- private CompilationUnitCompletion fCompletion;
- /**
- * The list of used local names.
- * @since 3.3
- */
- private Set<String> fUsedNames= new HashSet<>();
- private Map<String, MultiVariable> fVariables= new HashMap<>();
- private ImportRewrite fImportRewrite;
-
- private Set<String> fCompatibleContextTypeIds;
+ private JavaContextCore fJavaContextCore;
/**
* Creates a java template context.
@@ -119,6 +68,7 @@
*/
public JavaContext(TemplateContextType type, IDocument document, int completionOffset, int completionLength, ICompilationUnit compilationUnit) {
super(type, document, completionOffset, completionLength, compilationUnit);
+ this.fJavaContextCore = new JavaContextCore(this, type, document, completionOffset, completionLength, compilationUnit);
}
/**
@@ -132,6 +82,7 @@
*/
public JavaContext(TemplateContextType type, IDocument document, Position completionPosition, ICompilationUnit compilationUnit) {
super(type, document, completionPosition, compilationUnit);
+ this.fJavaContextCore = new JavaContextCore(this, type, document, completionPosition, compilationUnit);
}
/**
@@ -140,9 +91,7 @@
* @param contextTypeId the context type to accept
*/
public void addCompatibleContextType(String contextTypeId) {
- if (fCompatibleContextTypeIds == null)
- fCompatibleContextTypeIds= new HashSet<>();
- fCompatibleContextTypeIds.add(contextTypeId);
+ this.fJavaContextCore.addCompatibleContextType(contextTypeId);
}
@@ -169,27 +118,7 @@
*/
@Override
public TemplateBuffer evaluate(Template template) throws BadLocationException, TemplateException {
- clear();
-
- if (!canEvaluate(template))
- throw new TemplateException(JavaTemplateMessages.Context_error_cannot_evaluate);
-
- TemplateTranslator translator= new TemplateTranslator() {
- @Override
- protected TemplateVariable createVariable(TemplateVariableType type, String name, int[] offsets) {
-// TemplateVariableResolver resolver= getContextType().getResolver(type.getName());
-// return resolver.createVariable();
-
- MultiVariable variable= new JavaVariable(type, name, offsets);
- fVariables.put(name, variable);
- return variable;
- }
- };
- TemplateBuffer buffer= translator.translate(template);
-
- getContextType().resolve(buffer, this);
-
- rewriteImports();
+ TemplateBuffer buffer= this.fJavaContextCore.evaluate(template);
IPreferenceStore prefs= JavaPlugin.getDefault().getPreferenceStore();
boolean useCodeFormatter= prefs.getBoolean(PreferenceConstants.TEMPLATES_USE_CODEFORMATTER);
@@ -198,62 +127,15 @@
JavaFormatter formatter= new JavaFormatter(TextUtilities.getDefaultLineDelimiter(getDocument()), getIndentation(), useCodeFormatter, project);
formatter.format(buffer, this);
- clear();
-
return buffer;
}
- private void clear() {
- fUsedNames.clear();
- fImportRewrite= null;
- }
-
/*
* @see TemplateContext#canEvaluate(Template templates)
*/
@Override
public boolean canEvaluate(Template template) {
- if (!hasCompatibleContextType(template))
- return false;
-
- if (this.isForceEvaluation())
- return true;
-
- String key= getKey().toLowerCase();
- if (key.length() > 0 || !isAfterDot()) {
- String templateName= template.getName().toLowerCase();
- return JavaCore.ENABLED.equals(JavaCore.getOption(JavaCore.CODEASSIST_SUBSTRING_MATCH))
- ? templateName.contains(key)
- : templateName.startsWith(key);
- }
- return false;
- }
-
- private boolean isAfterDot() {
- try {
- IDocument document= getDocument();
- int offset= getCompletionOffset();
- return document.get(offset - 1, 1).charAt(0) == '.';
- } catch (BadLocationException e) {
- return false;
- }
- }
-
- private boolean hasCompatibleContextType(Template template) {
- String key= getKey();
- if (template.matches(key, getContextType().getId()))
- return true;
-
- if (fCompatibleContextTypeIds == null)
- return false;
-
- Iterator<String> iter= fCompatibleContextTypeIds.iterator();
- while (iter.hasNext()) {
- if (template.matches(key, iter.next()))
- return true;
- }
-
- return false;
+ return this.fJavaContextCore.canEvaluate(template);
}
/*
@@ -261,30 +143,7 @@
*/
@Override
public int getStart() {
-
- if (this.isManaged() && getCompletionLength() > 0)
- return super.getStart();
-
- try {
- IDocument document= getDocument();
-
- int start= getCompletionOffset();
- int end= getCompletionOffset() + getCompletionLength();
-
- while (start != 0 && Character.isUnicodeIdentifierPart(document.getChar(start - 1)))
- start--;
-
- while (start != end && Character.isWhitespace(document.getChar(start)))
- start++;
-
- if (start == end)
- start= getCompletionOffset();
-
- return start;
-
- } catch (BadLocationException e) {
- return super.getStart();
- }
+ return this.fJavaContextCore.getStart();
}
/*
@@ -292,24 +151,7 @@
*/
@Override
public int getEnd() {
-
- if (this.isManaged() || getCompletionLength() == 0)
- return super.getEnd();
-
- try {
- IDocument document= getDocument();
-
- int start= getCompletionOffset();
- int end= getCompletionOffset() + getCompletionLength();
-
- while (start != end && Character.isWhitespace(document.getChar(end - 1)))
- end--;
-
- return end;
-
- } catch (BadLocationException e) {
- return super.getEnd();
- }
+ return this.fJavaContextCore.getEnd();
}
/*
@@ -317,22 +159,7 @@
*/
@Override
public String getKey() {
-
- if (getCompletionLength() == 0)
- return super.getKey();
-
- try {
- IDocument document= getDocument();
-
- int start= getStart();
- int end= getCompletionOffset();
- return start <= end
- ? document.get(start, end - start)
- : ""; //$NON-NLS-1$
-
- } catch (BadLocationException e) {
- return super.getKey();
- }
+ return this.fJavaContextCore.getKey();
}
/**
@@ -341,79 +168,34 @@
* @return the character before the start position of the completion
*/
public char getCharacterBeforeStart() {
- int start= getStart();
-
- try {
- return start == 0
- ? ' '
- : getDocument().getChar(start - 1);
-
- } catch (BadLocationException e) {
- return ' ';
- }
+ return this.fJavaContextCore.getCharacterBeforeStart();
}
- private static void handleException(Shell shell, Exception e) {
+ @Override
+ public void handleException(Exception e) {
String title= JavaTemplateMessages.JavaContext_error_title;
if (e instanceof CoreException)
- ExceptionHandler.handle((CoreException)e, shell, title, null);
+ ExceptionHandler.handle((CoreException)e, null, title, null);
else if (e instanceof InvocationTargetException)
- ExceptionHandler.handle((InvocationTargetException)e, shell, title, null);
+ ExceptionHandler.handle((InvocationTargetException)e, null, title, null);
else {
JavaPlugin.log(e);
String message= e.getMessage();
if (message == null) {
message= JavaTemplateMessages.JavaContext_unexpected_error_message;
}
- MessageDialog.openError(shell, title, message);
+ MessageDialog.openError(null, title, message);
}
}
- private CompilationUnitCompletion getCompletion() {
- ICompilationUnit compilationUnit= getCompilationUnit();
- if (fCompletion == null) {
- fCompletion= new CompilationUnitCompletion(compilationUnit);
-
- if (compilationUnit != null) {
- try {
- compilationUnit.codeComplete(getStart(), fCompletion);
- } catch (JavaModelException e) {
- // ignore
- }
- }
- }
-
- return fCompletion;
- }
-
/**
* Returns the names of arrays available in the current {@link CompilationUnit}'s scope.
*
* @return the names of local arrays available in the current {@link CompilationUnit}'s scope
*/
+ @Override
public Variable[] getArrays() {
- Variable[] arrays= getCompletion().findArraysInCurrentScope();
- arrange(arrays);
- return arrays;
- }
-
- /**
- * Sorts already used variables behind any that are not yet used.
- *
- * @param variables the variables to sort
- * @since 3.3
- */
- private void arrange(Variable[] variables) {
- Arrays.sort(variables, new Comparator<Variable>() {
- @Override
- public int compare(Variable o1, Variable o2) {
- return rank(o1) - rank(o2);
- }
-
- private int rank(Variable l) {
- return fUsedNames.contains(l.getName()) ? 1 : 0;
- }
- });
+ return this.fJavaContextCore.getArrays();
}
/**
@@ -423,10 +205,9 @@
* @return the names of local variables matching <code>type</code>
* @since 3.3
*/
+ @Override
public Variable[] getLocalVariables(String type) {
- Variable[] localVariables= getCompletion().findLocalVariables(type);
- arrange(localVariables);
- return localVariables;
+ return this.fJavaContextCore.getLocalVariables(type);
}
/**
@@ -436,10 +217,9 @@
* @return the names of fields matching <code>type</code>
* @since 3.3
*/
+ @Override
public Variable[] getFields(String type) {
- Variable[] fields= getCompletion().findFieldVariables(type);
- arrange(fields);
- return fields;
+ return this.fJavaContextCore.getFields(type);
}
/**
@@ -447,47 +227,23 @@
*
* @return the names of iterables or arrays available in the current {@link CompilationUnit}'s scope
*/
+ @Override
public Variable[] getIterables() {
- Variable[] iterables= getCompletion().findIterablesInCurrentScope();
- arrange(iterables);
- return iterables;
+ return this.fJavaContextCore.getIterables();
}
+ @Override
public void markAsUsed(String name) {
- fUsedNames.add(name);
+ this.fJavaContextCore.markAsUsed(name);
}
+ @Override
public String[] suggestVariableNames(String type) throws IllegalArgumentException {
- String[] excludes= computeExcludes();
- // TODO erasure, arrays, etc.
- String[] result= suggestVariableName(type, excludes);
- return result;
+ return this.fJavaContextCore.suggestVariableNames(type);
}
String[] computeExcludes() {
- String[] excludes= getCompletion().getLocalVariableNames();
- if (!fUsedNames.isEmpty()) {
- String[] allExcludes= new String[fUsedNames.size() + excludes.length];
- System.arraycopy(excludes, 0, allExcludes, 0, excludes.length);
- System.arraycopy(fUsedNames.toArray(), 0, allExcludes, 0, fUsedNames.size());
- excludes= allExcludes;
- }
- return excludes;
- }
-
- private String[] suggestVariableName(String type, String[] excludes) throws IllegalArgumentException {
- int dim=0;
- while (type.endsWith("[]")) {//$NON-NLS-1$
- dim++;
- type= type.substring(0, type.length() - 2);
- }
-
- IJavaProject project= getJavaProject();
- if (project != null)
- return StubUtility.getVariableNameSuggestions(NamingConventions.VK_LOCAL, project, type, dim, Arrays.asList(excludes), true);
-
- // fallback if we lack proper context: roll-our own lowercasing
- return new String[] {Signature.getSimpleName(type).toLowerCase()};
+ return this.fJavaContextCore.computeExcludes();
}
/**
@@ -500,45 +256,9 @@
* It is fully qualified, if an import conflict prevented the import.
* @since 3.4
*/
+ @Override
public String addImport(String type) {
- if (isReadOnly())
- return type;
-
- ICompilationUnit cu= getCompilationUnit();
- if (cu == null)
- return type;
-
- try {
- boolean qualified= type.indexOf('.') != -1;
- if (!qualified) {
- IJavaSearchScope searchScope= SearchEngine.createJavaSearchScope(new IJavaElement[] { cu.getJavaProject() });
- SimpleName nameNode= null;
- TypeNameMatch[] matches= findAllTypes(type, searchScope, nameNode, null, cu);
- if (matches.length != 1) // only add import if we have a single match
- return type;
- type= matches[0].getFullyQualifiedName();
- }
-
- CompilationUnit root= getASTRoot(cu);
- if (fImportRewrite == null) {
- if (root == null) {
- fImportRewrite= StubUtility.createImportRewrite(cu, true);
- } else {
- fImportRewrite= StubUtility.createImportRewrite(root, true);
- }
- }
-
- ImportRewriteContext context;
- if (root == null)
- context= null;
- else
- context= new ContextSensitiveImportRewriteContext(root, getCompletionOffset(), fImportRewrite);
-
- return fImportRewrite.addImport(type, context);
- } catch (JavaModelException e) {
- handleException(null, e);
- return type;
- }
+ return this.fJavaContextCore.addImport(type);
}
/**
@@ -551,198 +271,12 @@
* @since 3.4
*/
public String addStaticImport(String qualifiedMemberName) {
- if (isReadOnly())
- return qualifiedMemberName;
-
- ICompilationUnit cu= getCompilationUnit();
- if (cu == null)
- return qualifiedMemberName;
-
- int memberOffset= qualifiedMemberName.lastIndexOf('.');
- if (memberOffset == -1)
- return qualifiedMemberName;
-
- String typeName= qualifiedMemberName.substring(0, memberOffset);
- String memberName= qualifiedMemberName.substring(memberOffset + 1, qualifiedMemberName.length());
- try {
- boolean isField;
- if ("*".equals(memberName)) { //$NON-NLS-1$
- isField= true;
- } else {
- IJavaProject javaProject= cu.getJavaProject();
-
- IType type= javaProject.findType(typeName);
- if (type == null)
- return qualifiedMemberName;
-
- IField field= type.getField(memberName);
- if (field.exists()) {
- isField= true;
- } else if (hasMethod(type, memberName)) {
- isField= false;
- } else {
- return qualifiedMemberName;
- }
- }
-
- CompilationUnit root= getASTRoot(cu);
- if (fImportRewrite == null) {
- if (root == null) {
- fImportRewrite= StubUtility.createImportRewrite(cu, true);
- } else {
- fImportRewrite= StubUtility.createImportRewrite(root, true);
- }
- }
-
- ImportRewriteContext context;
- if (root == null)
- context= null;
- else
- context= new ContextSensitiveImportRewriteContext(root, getCompletionOffset(), fImportRewrite);
-
- return fImportRewrite.addStaticImport(typeName, memberName, isField, context);
- } catch (JavaModelException e) {
- handleException(null, e);
- return typeName;
- }
+ return this.fJavaContextCore.addStaticImport(qualifiedMemberName);
}
- /**
- * Does <code>type</code> contain a method with <code>name</code>?
- *
- * @param type the type to inspect
- * @param name the name of the method to search for
- * @return true if has such a method
- * @throws JavaModelException if methods could not be retrieved
- * @since 3.4
- */
- private boolean hasMethod(IType type, String name) throws JavaModelException {
- IMethod[] methods= type.getMethods();
- for (int i= 0; i < methods.length; i++) {
- if (name.equals(methods[i].getElementName()))
- return true;
- }
-
- return false;
- }
-
- private void rewriteImports() {
- if (fImportRewrite == null)
- return;
-
- if (isReadOnly())
- return;
-
- ICompilationUnit cu= getCompilationUnit();
- if (cu == null)
- return;
-
- try {
- Position position= new Position(getCompletionOffset(), 0);
- IDocument document= getDocument();
- final String category= "__template_position_importer" + System.currentTimeMillis(); //$NON-NLS-1$
- IPositionUpdater updater= new DefaultPositionUpdater(category);
- document.addPositionCategory(category);
- document.addPositionUpdater(updater);
- document.addPosition(position);
-
- try {
- JavaModelUtil.applyEdit(cu, fImportRewrite.rewriteImports(null), false, null);
-
- setCompletionOffset(position.getOffset());
- } catch (CoreException e) {
- handleException(null, e);
- } finally {
- document.removePosition(position);
- document.removePositionUpdater(updater);
- document.removePositionCategory(category);
- }
- } catch (BadLocationException e) {
- handleException(null, e);
- } catch (BadPositionCategoryException e) {
- handleException(null, e);
- }
- }
-
- private CompilationUnit getASTRoot(ICompilationUnit compilationUnit) {
- return SharedASTProviderCore.getAST(compilationUnit, SharedASTProviderCore.WAIT_NO, new NullProgressMonitor());
- }
-
- /*
- * Finds a type by the simple name. From AddImportsOperation
- */
- private TypeNameMatch[] findAllTypes(String simpleTypeName, IJavaSearchScope searchScope, SimpleName nameNode, IProgressMonitor monitor, ICompilationUnit cu) throws JavaModelException {
- boolean is50OrHigher= JavaModelUtil.is50OrHigher(cu.getJavaProject());
-
- int typeKinds= TypeKinds.ALL_TYPES;
- if (nameNode != null) {
- typeKinds= ASTResolving.getPossibleTypeKinds(nameNode, is50OrHigher);
- }
-
- ArrayList<TypeNameMatch> typeInfos= new ArrayList<>();
- TypeNameMatchCollector requestor= new TypeNameMatchCollector(typeInfos);
- new SearchEngine().searchAllTypeNames(null, 0, simpleTypeName.toCharArray(), SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE, getSearchForConstant(typeKinds), searchScope, requestor, IJavaSearchConstants.FORCE_IMMEDIATE_SEARCH, monitor);
-
- ArrayList<TypeNameMatch> typeRefsFound= new ArrayList<>(typeInfos.size());
- for (int i= 0, len= typeInfos.size(); i < len; i++) {
- TypeNameMatch curr= typeInfos.get(i);
- if (curr.getPackageName().length() > 0) { // do not suggest imports from the default package
- if (isOfKind(curr, typeKinds, is50OrHigher) && isVisible(curr, cu)) {
- typeRefsFound.add(curr);
- }
- }
- }
- return typeRefsFound.toArray(new TypeNameMatch[typeRefsFound.size()]);
- }
-
- private int getSearchForConstant(int typeKinds) {
- final int CLASSES= TypeKinds.CLASSES;
- final int INTERFACES= TypeKinds.INTERFACES;
- final int ENUMS= TypeKinds.ENUMS;
- final int ANNOTATIONS= TypeKinds.ANNOTATIONS;
-
- switch (typeKinds & (CLASSES | INTERFACES | ENUMS | ANNOTATIONS)) {
- case CLASSES: return IJavaSearchConstants.CLASS;
- case INTERFACES: return IJavaSearchConstants.INTERFACE;
- case ENUMS: return IJavaSearchConstants.ENUM;
- case ANNOTATIONS: return IJavaSearchConstants.ANNOTATION_TYPE;
- case CLASSES | INTERFACES: return IJavaSearchConstants.CLASS_AND_INTERFACE;
- case CLASSES | ENUMS: return IJavaSearchConstants.CLASS_AND_ENUM;
- default: return IJavaSearchConstants.TYPE;
- }
- }
-
- private boolean isOfKind(TypeNameMatch curr, int typeKinds, boolean is50OrHigher) {
- int flags= curr.getModifiers();
- if (Flags.isAnnotation(flags)) {
- return is50OrHigher && ((typeKinds & TypeKinds.ANNOTATIONS) != 0);
- }
- if (Flags.isEnum(flags)) {
- return is50OrHigher && ((typeKinds & TypeKinds.ENUMS) != 0);
- }
- if (Flags.isInterface(flags)) {
- return (typeKinds & TypeKinds.INTERFACES) != 0;
- }
- return (typeKinds & TypeKinds.CLASSES) != 0;
- }
-
-
- private boolean isVisible(TypeNameMatch curr, ICompilationUnit cu) {
- int flags= curr.getModifiers();
- if (Flags.isPrivate(flags)) {
- return false;
- }
- if (Flags.isPublic(flags) || Flags.isProtected(flags)) {
- return true;
- }
- return curr.getPackageName().equals(cu.getParent().getElementName());
- }
-
+ @Override
public TemplateVariable getTemplateVariable(String name) {
- TemplateVariable variable= fVariables.get(name);
- if (variable != null && !variable.isResolved())
- getContextType().resolve(variable, this);
- return variable;
+ return this.fJavaContextCore.getTemplateVariable(name);
}
/**
@@ -753,6 +287,7 @@
* @param slave the dependent variable
* @since 3.3
*/
+ @Override
public void addDependency(MultiVariable master, MultiVariable slave) {
MultiVariableGuess guess= getMultiVariableGuess();
if (guess == null) {