/*******************************************************************************
* Copyright (c) 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Zend Technologies
*******************************************************************************/
package org.eclipse.php.internal.ui.corext.codemanipulation;
import java.io.IOException;
import java.util.*;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.dltk.annotations.NonNull;
import org.eclipse.dltk.ast.Modifiers;
import org.eclipse.dltk.ast.declarations.ModuleDeclaration;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.internal.core.ImportContainer;
import org.eclipse.dltk.internal.core.ImportDeclaration;
import org.eclipse.dltk.internal.corext.util.Strings;
import org.eclipse.dltk.internal.ui.DLTKUIStatus;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateBuffer;
import org.eclipse.jface.text.templates.TemplateException;
import org.eclipse.jface.text.templates.TemplateVariable;
import org.eclipse.jface.text.templates.persistence.TemplatePersistenceData;
import org.eclipse.jface.text.templates.persistence.TemplateStore;
import org.eclipse.php.core.PHPVersion;
import org.eclipse.php.core.ast.nodes.*;
import org.eclipse.php.core.compiler.ast.nodes.FullyQualifiedReference;
import org.eclipse.php.core.compiler.ast.nodes.NamespaceReference;
import org.eclipse.php.core.compiler.ast.nodes.PHPMethodDeclaration;
import org.eclipse.php.core.project.ProjectOptions;
import org.eclipse.php.internal.core.ast.rewrite.ASTRewrite;
import org.eclipse.php.internal.core.ast.rewrite.ImportRewrite;
import org.eclipse.php.internal.core.ast.util.Signature;
import org.eclipse.php.internal.core.typeinference.PHPModelUtils;
import org.eclipse.php.internal.core.typeinference.PHPSimpleTypes;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.php.internal.ui.corext.template.php.CodeTemplateContext;
import org.eclipse.php.internal.ui.corext.template.php.CodeTemplateContextType;
import org.eclipse.php.internal.ui.viewsupport.ProjectTemplateStore;
import org.eclipse.php.ui.editor.SharedASTProvider;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.wst.jsdt.internal.compiler.env.ICompilationUnit;
public class StubUtility {
private static final String[] EMPTY = new String[0];
private static final Set<String> VALID_TYPE_BODY_TEMPLATES;
static {
VALID_TYPE_BODY_TEMPLATES = new HashSet<>();
VALID_TYPE_BODY_TEMPLATES.add(CodeTemplateContextType.CLASSBODY_ID);
VALID_TYPE_BODY_TEMPLATES.add(CodeTemplateContextType.INTERFACEBODY_ID);
VALID_TYPE_BODY_TEMPLATES.add(CodeTemplateContextType.ENUMBODY_ID);
VALID_TYPE_BODY_TEMPLATES.add(CodeTemplateContextType.ANNOTATIONBODY_ID);
}
@SuppressWarnings("unchecked")
public static MethodDeclaration createImplementationStub(@NonNull ISourceModule unit,
NamespaceDeclaration namespace, ASTRewrite rewrite, ImportRewrite imports, IMethod method, boolean deferred)
throws CoreException {
Assert.isNotNull(imports);
Assert.isNotNull(rewrite);
AST ast = rewrite.getAST();
MethodDeclaration decl = ast.newMethodDeclaration();
decl.setModifier(getImplementationModifiers(ast, method, deferred));
FunctionDeclaration func = ast.newFunctionDeclaration();
func.setFunctionName(ast.newIdentifier(method.getElementName()));
decl.setFunction(func);
IParameter[] typeParams = method.getParameters();
List<FormalParameter> typeParameters = decl.getFunction().formalParameters();
ISourceModule sourceModule = method.getSourceModule();
ModuleDeclaration moduleDeclaration = SourceParserUtil.getModuleDeclaration(sourceModule);
org.eclipse.dltk.ast.declarations.MethodDeclaration methodDeclaration = PHPModelUtils
.getNodeByMethod(moduleDeclaration, method);
List<org.eclipse.php.core.compiler.ast.nodes.FormalParameter> arguments = (List<org.eclipse.php.core.compiler.ast.nodes.FormalParameter>) methodDeclaration
.getArguments();
boolean supportNullable = ProjectOptions.getPHPVersion(unit).isGreaterThan(PHPVersion.PHP7_0);
Map<String, ImportDeclaration> importContainers = getImportContainer(method);
String declaringNamespace = getDeclaringNamespace(method);
if (typeParams != null) {
for (int i = 0; i < typeParams.length; i++) {
FormalParameter newTypeParam = ast.newFormalParameter();
org.eclipse.php.core.compiler.ast.nodes.FormalParameter currTypeParam = arguments.get(i);
IParameter curr = typeParams[i];
if (currTypeParam.getParameterType() != null) {
String typeName = addImports(namespace, curr.getType(), declaringNamespace, importContainers,
imports);
if (typeName != null) {
String parameterType = curr.getType();
if (supportNullable
&& ((FullyQualifiedReference) currTypeParam.getParameterType()).isNullable()) {
parameterType = '?' + parameterType;
}
newTypeParam.setParameterType(ast.newIdentifier(parameterType));
}
}
newTypeParam.setParameterName(ast.newIdentifier(curr.getName()));
if (curr.getDefaultValue() != null) {
newTypeParam.setDefaultValue(ast.newIdentifier(curr.getDefaultValue()));
}
typeParameters.add(newTypeParam);
}
}
FullyQualifiedReference returnType = (FullyQualifiedReference) ((PHPMethodDeclaration) methodDeclaration)
.getReturnType();
if (returnType != null && supportNullable) {
String returnTypeName = returnType.getName();
if (returnType.isNullable()) {
returnTypeName = '?' + returnTypeName;
}
func.setReturnType(ast.newIdentifier(returnTypeName));
addImports(namespace, returnType.getName(), declaringNamespace, importContainers, imports);
}
if (!deferred) {
Block body = ast.newBlock();
func.setBody(body);
}
return decl;
}
private static String getDeclaringNamespace(IMethod method) {
IType namespace = PHPModelUtils.getCurrentNamespace(method);
if (namespace != null) {
return namespace.getElementName();
}
return "";
}
private static int getImplementationModifiers(AST ast, IMethod method, boolean deferred) throws ModelException {
int modifiers = method.getFlags() & ~Modifiers.AccAbstract & ~Modifiers.AccPrivate;
if (deferred) {
modifiers = modifiers & ~Modifiers.AccProtected;
modifiers = modifiers | Modifiers.AccPublic;
}
return modifiers;
}
private static Map<String, ImportDeclaration> getImportContainer(IMethod method) throws ModelException {
Map<String, ImportDeclaration> importContainers = new HashMap<String, ImportDeclaration>();
ImportContainersFinder finder = new ImportContainersFinder(importContainers);
method.getSourceModule().accept(finder);
return importContainers;
}
private static String addImports(NamespaceDeclaration namespace, String typeName, String declaringNamespace,
Map<String, ImportDeclaration> importContainers, ImportRewrite imports) {
if (PHPSimpleTypes.isSimpleType(typeName)) {
return typeName;
}
ImportDeclaration importDeclaration = importContainers.get(typeName);
if (importDeclaration != null) {
typeName = importDeclaration.getElementName();
} else if (typeName != null && declaringNamespace != null && !declaringNamespace.equals("")) { //$NON-NLS-1$
typeName = declaringNamespace + NamespaceReference.NAMESPACE_SEPARATOR + typeName;
}
if (typeName != null) {
imports.addImport(namespace, typeName);
return typeName;
}
return null;
}
private static class ImportContainersFinder implements IModelElementVisitor {
Map<String, ImportDeclaration> importContainers;
public ImportContainersFinder(Map<String, ImportDeclaration> importContainers) {
this.importContainers = importContainers;
}
@Override
public boolean visit(IModelElement element) {
if (element instanceof ImportContainer) {
try {
for (IModelElement ele : ((ImportContainer) element).getChildren()) {
if (!importContainers.containsKey(ele.getElementName())) {
importContainers.put(PHPModelUtils.extractElementName(ele.getElementName()),
(ImportDeclaration) ele);
}
}
} catch (ModelException e) {
PHPUiPlugin.log(e);
}
return false;
}
return true;
}
}
/*
* Don't use this method directly, use CodeGeneration.
*/
public static String getMethodBodyContent(boolean isConstructor, IScriptProject project, String destTypeName,
String methodName, String bodyStatement, String lineDelimiter) throws CoreException {
String templateName = isConstructor ? CodeTemplateContextType.CONSTRUCTORSTUB_ID
: CodeTemplateContextType.METHODSTUB_ID;
Template template = getCodeTemplate(templateName, project);
if (template == null) {
return bodyStatement;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), project, lineDelimiter);
context.setVariable(CodeTemplateContextType.ENCLOSING_METHOD, methodName);
context.setVariable(CodeTemplateContextType.ENCLOSING_TYPE, destTypeName);
context.setVariable(CodeTemplateContextType.BODY_STATEMENT, bodyStatement);
String str = evaluateTemplate(context, template, new String[] { CodeTemplateContextType.BODY_STATEMENT });
if (str == null && !Strings.containsOnlyWhitespaces(bodyStatement)) {
return bodyStatement;
}
return str;
}
/*
* Don't use this method directly, use CodeGeneration.
*/
public static String getGetterMethodBodyContent(IScriptProject project, String destTypeName, String methodName,
String fieldName, String lineDelimiter) throws CoreException {
String templateName = CodeTemplateContextType.GETTERSTUB_ID;
Template template = getCodeTemplate(templateName, project);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), project, lineDelimiter);
context.setVariable(CodeTemplateContextType.ENCLOSING_METHOD, methodName);
context.setVariable(CodeTemplateContextType.ENCLOSING_TYPE, destTypeName);
context.setVariable(CodeTemplateContextType.FIELD, fieldName);
return evaluateTemplate(context, template);
}
/*
* Don't use this method directly, use CodeGeneration.
*/
public static String getSetterMethodBodyContent(IScriptProject project, String destTypeName, String methodName,
String fieldName, String paramName, String lineDelimiter) throws CoreException {
String templateName = CodeTemplateContextType.SETTERSTUB_ID;
Template template = getCodeTemplate(templateName, project);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), project, lineDelimiter);
context.setVariable(CodeTemplateContextType.ENCLOSING_METHOD, methodName);
context.setVariable(CodeTemplateContextType.ENCLOSING_TYPE, destTypeName);
context.setVariable(CodeTemplateContextType.FIELD, fieldName);
context.setVariable(CodeTemplateContextType.FIELD_TYPE, fieldName);
context.setVariable(CodeTemplateContextType.PARAM, paramName);
return evaluateTemplate(context, template);
}
public static String getCatchBodyContent(IScriptProject sp, String exceptionType, String variableName,
String enclosingType, String enclosingMethod, String lineDelimiter) throws CoreException {
Template template = getCodeTemplate(CodeTemplateContextType.CATCHBLOCK_ID, sp);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sp, lineDelimiter);
context.setVariable(CodeTemplateContextType.ENCLOSING_TYPE, enclosingType);
context.setVariable(CodeTemplateContextType.ENCLOSING_METHOD, enclosingMethod);
context.setVariable(CodeTemplateContextType.EXCEPTION_TYPE, exceptionType);
context.setVariable(CodeTemplateContextType.EXCEPTION_VAR, variableName);
return evaluateTemplate(context, template);
}
public static String getCompilationUnitContent(IScriptProject sp, String fileComment, String typeComment,
String typeContent, String lineDelimiter) throws CoreException {
Template template = getCodeTemplate(CodeTemplateContextType.NEWTYPE_ID, sp);
if (template == null) {
return null;
}
IScriptProject project = sp;
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), project, lineDelimiter);
context.setVariable(CodeTemplateContextType.TYPE_COMMENT, typeComment != null ? typeComment : ""); //$NON-NLS-1$
context.setVariable(CodeTemplateContextType.FILE_COMMENT, fileComment != null ? fileComment : ""); //$NON-NLS-1$
context.setVariable(CodeTemplateContextType.TYPE_DECLARATION, typeContent);
context.setVariable(CodeTemplateContextType.TYPENAME, sp.getElementName());
String[] fullLine = { CodeTemplateContextType.PACKAGE_DECLARATION, CodeTemplateContextType.FILE_COMMENT,
CodeTemplateContextType.TYPE_COMMENT };
return evaluateTemplate(context, template, fullLine);
}
/*
* Don't use this method directly, use CodeGeneration.
*
* @see org.eclipse.jdt.ui.CodeGeneration#getFileComment(ICompilationUnit,
* String)
*/
public static String getFileComment(ISourceModule sm, String lineDelimiter) throws CoreException {
Template template = getCodeTemplate(CodeTemplateContextType.FILECOMMENT_ID, sm.getScriptProject());
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sm.getScriptProject(),
lineDelimiter);
context.setVariable(CodeTemplateContextType.FILENAME, sm.getElementName());
context.setVariable(CodeTemplateContextType.PROJECTNAME, sm.getScriptProject().getElementName());
return evaluateTemplate(context, template);
}
public static String getFileComment(IScriptProject sp, String lineDelimiter) throws CoreException {
Template template = getCodeTemplate(CodeTemplateContextType.FILECOMMENT_ID, sp);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sp, lineDelimiter);
context.setVariable(CodeTemplateContextType.FILENAME, sp.getElementName());
return evaluateTemplate(context, template);
}
/*
* Don't use this method directly, use CodeGeneration.
*
* @see org.eclipse.jdt.ui.CodeGeneration#getTypeComment(ICompilationUnit,
* String, String[], String)
*/
public static String getTypeComment(IScriptProject sp, String typeQualifiedName, String[] typeParameterNames,
String lineDelim) throws CoreException {
Template template = getCodeTemplate(CodeTemplateContextType.TYPECOMMENT_ID, sp);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sp, lineDelim);
context.setVariable(CodeTemplateContextType.ENCLOSING_TYPE, Signature.getQualifier(typeQualifiedName));
context.setVariable(CodeTemplateContextType.TYPENAME, Signature.getSimpleName(typeQualifiedName));
TemplateBuffer buffer;
try {
buffer = context.evaluate(template);
} catch (BadLocationException e) {
throw new CoreException(Status.CANCEL_STATUS);
} catch (TemplateException e) {
throw new CoreException(Status.CANCEL_STATUS);
}
if (buffer == null) {
return null;
}
String str = buffer.getString();
if (Strings.containsOnlyWhitespaces(str)) {
return null;
}
TemplateVariable position = findVariable(buffer, CodeTemplateContextType.TAGS); // look
// if
// PHPDoc
// tags
// have
// to
// be added
if (position == null) {
return str;
}
IDocument document = new Document(str);
int[] tagOffsets = position.getOffsets();
for (int i = tagOffsets.length - 1; i >= 0; i--) { // from last to first
try {
insertTag(document, tagOffsets[i], position.getLength(), EMPTY, null, typeParameterNames, false,
lineDelim, null);
} catch (BadLocationException e) {
throw new CoreException(DLTKUIStatus.createError(IStatus.ERROR, e));
}
}
return document.get();
}
/*
* Returns the parameters type names used in see tags. Currently, these are
* always fully qualified.
*/
public static String[] getParameterTypeNamesForSeeTag(IFunctionBinding binding) {
ITypeBinding[] typeParametersTypes = binding.getParameterTypes();
String[] typeParameterNames = null;
if (typeParametersTypes != null) {
typeParameterNames = new String[typeParametersTypes.length];
int i = 0;
for (ITypeBinding type : typeParametersTypes) {
typeParameterNames[i++] = type.getName();
}
}
return typeParameterNames;
}
/*
* Returns the parameters type names used in see tags. Currently, these are
* always fully qualified.
*/
private static String[] getParameterTypeNamesForSeeTag(IMethod overridden) throws ModelException {
try {
Program program = SharedASTProvider.getAST(overridden.getSourceModule(), SharedASTProvider.WAIT_YES,
new NullProgressMonitor());
ASTNode elementAt = program != null ? program.getElementAt(overridden.getSourceRange().getOffset()) : null;
IFunctionBinding resolvedBinding = null;
if (elementAt instanceof MethodDeclaration) {
MethodDeclaration methodDeclaration = (MethodDeclaration) elementAt;
resolvedBinding = methodDeclaration.resolveMethodBinding();
} else if (elementAt instanceof FunctionDeclaration) {
FunctionDeclaration functionDeclaration = (FunctionDeclaration) elementAt;
resolvedBinding = functionDeclaration.resolveFunctionBinding();
}
if (resolvedBinding != null) {
return getParameterTypeNamesForSeeTag(resolvedBinding);
}
} catch (IOException e) {
PHPUiPlugin.log(e);
}
// fall back code. Not good for generic methods!
String[] paramTypes = overridden.getParameterNames();
String[] paramTypeNames = new String[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
paramTypeNames[i] = Signature.toString(Signature.getTypeErasure(paramTypes[i]));
}
return paramTypeNames;
}
private static String getSeeTag(String declaringClassQualifiedName, String methodName,
String[] parameterTypesQualifiedNames) {
StringBuilder buf = new StringBuilder();
buf.append("@see "); //$NON-NLS-1$
buf.append(declaringClassQualifiedName);
buf.append("::"); //$NON-NLS-1$
buf.append(methodName);
buf.append('(');
if (null != parameterTypesQualifiedNames) {
for (int i = 0; i < parameterTypesQualifiedNames.length; i++) {
if (i > 0) {
buf.append(", "); //$NON-NLS-1$
}
buf.append(parameterTypesQualifiedNames[i]);
}
}
buf.append(')');
return buf.toString();
}
public static String[] getTypeParameterNames(String[] typeParameters) {
String[] typeParametersNames = new String[typeParameters.length];
for (int i = 0; i < typeParameters.length; i++) {
typeParametersNames[i] = typeParameters[i];
}
return typeParametersNames;
}
/**
* Don't use this method directly, use CodeGeneration.
*
* @param templateID
* the template id of the type body to get. Valid id's are
* {@link CodeTemplateContextType#CLASSBODY_ID},
* {@link CodeTemplateContextType#INTERFACEBODY_ID},
* {@link CodeTemplateContextType#ENUMBODY_ID},
* {@link CodeTemplateContextType#ANNOTATIONBODY_ID},
* @param sp
* the compilation unit to which the template is added
* @param typeName
* the type name
* @param lineDelim
* the line delimiter to use
* @return return the type body template or <code>null</code>
* @throws CoreException
* thrown if the template could not be evaluated
* @see org.eclipse.jdt.ui.CodeGeneration#getTypeBody(String,
* ICompilationUnit, String, String)
*/
public static String getTypeBody(String templateID, IScriptProject sp, String typeName, String lineDelim)
throws CoreException {
if (!VALID_TYPE_BODY_TEMPLATES.contains(templateID)) {
throw new IllegalArgumentException("Invalid code template ID: " + templateID); //$NON-NLS-1$
}
Template template = getCodeTemplate(templateID, sp);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sp, lineDelim);
// context.setCompilationUnitVariables(sp);
context.setVariable(CodeTemplateContextType.TYPENAME, typeName);
return evaluateTemplate(context, template);
}
/*
* Don't use this method directly, use CodeGeneration.
*
* @see org.eclipse.jdt.ui.CodeGeneration#getMethodComment(ICompilationUnit,
* String, String, String[], String[], String, String[], IMethod, String)
*/
public static String getMethodComment(IScriptProject sp, String typeName, String methodName, String[] paramNames,
String retTypeSig, String[] typeParameterNames, IMethod target, boolean delegate, String lineDelimiter,
List<String> newExceptions) throws CoreException {
String templateName = CodeTemplateContextType.METHODCOMMENT_ID;
if (target != null) {
if (delegate)
templateName = CodeTemplateContextType.DELEGATECOMMENT_ID;
else
templateName = CodeTemplateContextType.OVERRIDECOMMENT_ID;
} else if (retTypeSig == null && typeName != null && (typeName.equals(methodName) || "constructor" //$NON-NLS-1$
.equals(methodName))) {
templateName = CodeTemplateContextType.CONSTRUCTORCOMMENT_ID;
}
Template template = getCodeTemplate(templateName, sp);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sp, lineDelimiter);
// context.setCompilationUnitVariables(sp);
context.setVariable(CodeTemplateContextType.ENCLOSING_TYPE, typeName);
context.setVariable(CodeTemplateContextType.ENCLOSING_METHOD, methodName);
if (retTypeSig != null) {
context.setVariable(CodeTemplateContextType.RETURN_TYPE, retTypeSig);
}
if (target != null) {
String targetTypeName = target.getDeclaringType()
.getTypeQualifiedName(PHPModelUtils.ENCLOSING_TYPE_SEPARATOR);
if (targetTypeName.indexOf(PHPModelUtils.ENCLOSING_TYPE_SEPARATOR) > 0) {
targetTypeName = PHPModelUtils.ENCLOSING_TYPE_SEPARATOR + targetTypeName;
}
String[] targetParamTypeNames = getParameterTypeNamesForSeeTag(target);
if (delegate)
context.setVariable(CodeTemplateContextType.SEE_TO_TARGET_TAG,
getSeeTag(targetTypeName, methodName, targetParamTypeNames));
else
context.setVariable(CodeTemplateContextType.SEE_TO_OVERRIDDEN_TAG,
getSeeTag(targetTypeName, methodName, targetParamTypeNames));
}
TemplateBuffer buffer;
try {
buffer = context.evaluate(template);
} catch (BadLocationException e) {
throw new CoreException(Status.CANCEL_STATUS);
} catch (TemplateException e) {
throw new CoreException(Status.CANCEL_STATUS);
}
if (buffer == null) {
return null;
}
String str = buffer.getString();
if (Strings.containsOnlyWhitespaces(str)) {
return null;
}
TemplateVariable position = findVariable(buffer, CodeTemplateContextType.TAGS); // look
// if
// PHPDoc
// tags
// have
// to
// be added
if (position == null) {
return str;
}
IDocument document = new Document(str);
int[] tagOffsets = position.getOffsets();
for (int i = tagOffsets.length - 1; i >= 0; i--) { // from last to first
try {
insertTag(document, tagOffsets[i], position.getLength(), paramNames, retTypeSig, typeParameterNames,
false, lineDelimiter, newExceptions);
} catch (BadLocationException e) {
throw new CoreException(DLTKUIStatus.createError(IStatus.ERROR, e));
}
}
return document.get();
}
// remove lines for empty variables
private static String fixEmptyVariables(TemplateBuffer buffer, String[] variables)
throws MalformedTreeException, BadLocationException {
IDocument doc = new Document(buffer.getString());
int nLines = doc.getNumberOfLines();
MultiTextEdit edit = new MultiTextEdit();
HashSet<Integer> removedLines = new HashSet<>();
for (int i = 0; i < variables.length; i++) {
TemplateVariable position = findVariable(buffer, variables[i]); // look
// if
// Javadoc
// tags
// have
// to
// be
// added
if (position == null || position.getLength() > 0) {
continue;
}
int[] offsets = position.getOffsets();
for (int k = 0; k < offsets.length; k++) {
int line = doc.getLineOfOffset(offsets[k]);
IRegion lineInfo = doc.getLineInformation(line);
int offset = lineInfo.getOffset();
String str = doc.get(offset, lineInfo.getLength());
if (Strings.containsOnlyWhitespaces(str) && nLines > line + 1
&& removedLines.add(Integer.valueOf(line))) {
int nextStart = doc.getLineOffset(line + 1);
edit.addChild(new DeleteEdit(offset, nextStart - offset));
}
}
}
edit.apply(doc, 0);
return doc.get();
}
/*
* Don't use this method directly, use CodeGeneration.
*/
public static String getFieldComment(IScriptProject sp, String fieldType, String fieldName, String lineDelimiter)
throws CoreException {
Template template = getCodeTemplate(CodeTemplateContextType.FIELDCOMMENT_ID, sp);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sp, lineDelimiter);
// context.setCompilationUnitVariables(sp);
context.setVariable(CodeTemplateContextType.FIELD_TYPE, fieldType);
context.setVariable(CodeTemplateContextType.FIELD, fieldName);
return evaluateTemplate(context, template);
}
/*
* Don't use this method directly, use CodeGeneration.
*/
public static String getMultipleFieldsComment(IScriptProject sp, String[] fieldTypes, String[] fieldNames,
String lineDelim) throws CoreException {
Template template = getCodeTemplate(CodeTemplateContextType.MULTIFIELDCOMMENT_ID, sp);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sp, lineDelim);
// context.setCompilationUnitVariables(sp);
TemplateBuffer buffer;
try {
buffer = context.evaluate(template);
} catch (BadLocationException e) {
throw new CoreException(Status.CANCEL_STATUS);
} catch (TemplateException e) {
throw new CoreException(Status.CANCEL_STATUS);
}
if (buffer == null) {
return null;
}
String str = buffer.getString();
if (Strings.containsOnlyWhitespaces(str)) {
return null;
}
TemplateVariable position = findVariable(buffer, CodeTemplateContextType.TAGS); // look
// if
// PHPDoc
// tags
// have
// to
// be added
if (position == null) {
return str;
}
IDocument document = new Document(str);
int[] tagOffsets = position.getOffsets();
for (int i = tagOffsets.length - 1; i >= 0; i--) { // from last to first
try {
insertVarTags(document, tagOffsets[i], position.getLength(), fieldNames, fieldTypes, lineDelim);
} catch (BadLocationException e) {
throw new CoreException(DLTKUIStatus.createError(IStatus.ERROR, e));
}
}
return document.get();
}
/*
* Don't use this method directly, use CodeGeneration.
*
* @see org.eclipse.jdt.ui.CodeGeneration#getSetterComment(ICompilationUnit,
* String, String, String, String, String, String, String)
*/
public static String getSetterComment(IScriptProject sp, String typeName, String methodName, String fieldName,
String fieldType, String paramName, String bareFieldName, String lineDelimiter) throws CoreException {
String templateName = CodeTemplateContextType.SETTERCOMMENT_ID;
Template template = getCodeTemplate(templateName, sp);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sp, lineDelimiter);
context.setVariable(CodeTemplateContextType.ENCLOSING_TYPE, typeName);
context.setVariable(CodeTemplateContextType.ENCLOSING_METHOD, methodName);
context.setVariable(CodeTemplateContextType.FIELD, fieldName);
context.setVariable(CodeTemplateContextType.FIELD_TYPE, fieldType);
context.setVariable(CodeTemplateContextType.BARE_FIELD_NAME, bareFieldName);
context.setVariable(CodeTemplateContextType.PARAM, paramName);
return evaluateTemplate(context, template);
}
/*
* Don't use this method directly, use CodeGeneration.
*
* @see org.eclipse.jdt.ui.CodeGeneration#getGetterComment(ICompilationUnit,
* String, String, String, String, String, String)
*/
public static String getGetterComment(IScriptProject sp, String typeName, String methodName, String fieldName,
String fieldType, String bareFieldName, String lineDelimiter) throws CoreException {
String templateName = CodeTemplateContextType.GETTERCOMMENT_ID;
Template template = getCodeTemplate(templateName, sp);
if (template == null) {
return null;
}
CodeTemplateContext context = new CodeTemplateContext(template.getContextTypeId(), sp, lineDelimiter);
context.setVariable(CodeTemplateContextType.ENCLOSING_TYPE, typeName);
context.setVariable(CodeTemplateContextType.ENCLOSING_METHOD, methodName);
context.setVariable(CodeTemplateContextType.FIELD, fieldName);
context.setVariable(CodeTemplateContextType.FIELD_TYPE, fieldType);
context.setVariable(CodeTemplateContextType.BARE_FIELD_NAME, bareFieldName);
return evaluateTemplate(context, template);
}
private static String evaluateTemplate(CodeTemplateContext context, Template template) throws CoreException {
TemplateBuffer buffer;
try {
buffer = context.evaluate(template);
} catch (BadLocationException e) {
throw new CoreException(Status.CANCEL_STATUS);
} catch (TemplateException e) {
throw new CoreException(Status.CANCEL_STATUS);
}
if (buffer == null) {
return null;
}
String str = buffer.getString();
if (Strings.containsOnlyWhitespaces(str)) {
return null;
}
return str;
}
private static String evaluateTemplate(CodeTemplateContext context, Template template, String[] fullLineVariables)
throws CoreException {
TemplateBuffer buffer;
try {
buffer = context.evaluate(template);
if (buffer == null) {
return null;
}
String str = fixEmptyVariables(buffer, fullLineVariables);
if (Strings.containsOnlyWhitespaces(str)) {
return null;
}
return str;
} catch (BadLocationException e) {
throw new CoreException(Status.CANCEL_STATUS);
} catch (TemplateException e) {
throw new CoreException(Status.CANCEL_STATUS);
}
}
/*
* private static ASTNode getReturnType(MethodDeclaration decl) { // used
* from API, can't eliminate return decl.getAST().apiLevel() == AST.JLS2 ?
* decl.getReturnType() : decl.getReturnType2(); }
*/
private static TemplateVariable findVariable(TemplateBuffer buffer, String variable) {
TemplateVariable[] positions = buffer.getVariables();
for (int i = 0; i < positions.length; i++) {
TemplateVariable curr = positions[i];
if (variable.equals(curr.getType())) {
return curr;
}
}
return null;
}
private static void insertVarTags(IDocument textBuffer, int offset, int length, String[] fieldNames,
String[] fieldTypes, String lineDelimiter) throws BadLocationException {
IRegion region = textBuffer.getLineInformationOfOffset(offset);
if (region == null) {
return;
}
String lineStart = textBuffer.get(region.getOffset(), offset - region.getOffset());
StringBuilder buf = new StringBuilder();
for (int i = 0; i < fieldNames.length; i++) {
if (buf.length() > 0) {
buf.append(lineDelimiter).append(lineStart);
}
buf.append("@var ").append(fieldTypes[i]).append(' ').append(fieldNames[i]); //$NON-NLS-1$
}
if (buf.length() == 0 && isAllCommentWhitespace(lineStart)) {
int prevLine = textBuffer.getLineOfOffset(offset) - 1;
if (prevLine > 0) {
IRegion prevRegion = textBuffer.getLineInformation(prevLine);
int prevLineEnd = prevRegion.getOffset() + prevRegion.getLength();
// clear full line
textBuffer.replace(prevLineEnd, offset + length - prevLineEnd, ""); //$NON-NLS-1$
return;
}
}
textBuffer.replace(offset, length, buf.toString());
}
private static void insertTag(IDocument textBuffer, int offset, int length, String[] paramNames, String returnType,
String[] typeParameterNames, boolean isDeprecated, String lineDelimiter, List<String> newExceptions)
throws BadLocationException {
IRegion region = textBuffer.getLineInformationOfOffset(offset);
if (region == null) {
return;
}
String lineStart = textBuffer.get(region.getOffset(), offset - region.getOffset());
StringBuilder buf = new StringBuilder();
if (null != typeParameterNames) {
for (int i = 0; i < typeParameterNames.length; i++) {
if (buf.length() > 0) {
buf.append(lineDelimiter).append(lineStart);
}
buf.append("@param <").append(typeParameterNames[i]).append('>'); //$NON-NLS-1$
}
}
if (null != paramNames) {
for (int i = 0; i < paramNames.length; i++) {
if (buf.length() > 0) {
buf.append(lineDelimiter).append(lineStart);
}
buf.append("@param ").append(paramNames[i]); //$NON-NLS-1$
}
}
if (null != newExceptions) {
for (Iterator<String> iterator = newExceptions.iterator(); iterator.hasNext();) {
String exception = iterator.next();
if (buf.length() > 0) {
buf.append(lineDelimiter).append(lineStart);
}
buf.append("@throws ").append(exception); //$NON-NLS-1$
}
}
if (returnType != null && !returnType.equals("void")) { //$NON-NLS-1$
if (buf.length() > 0) {
buf.append(lineDelimiter).append(lineStart);
}
buf.append("@return ").append(returnType); //$NON-NLS-1$
}
if (isDeprecated) {
if (buf.length() > 0) {
buf.append(lineDelimiter).append(lineStart);
}
buf.append("@deprecated"); //$NON-NLS-1$
}
if (buf.length() == 0 && isAllCommentWhitespace(lineStart)) {
int prevLine = textBuffer.getLineOfOffset(offset) - 1;
if (prevLine > 0) {
IRegion prevRegion = textBuffer.getLineInformation(prevLine);
int prevLineEnd = prevRegion.getOffset() + prevRegion.getLength();
// clear full line
textBuffer.replace(prevLineEnd, offset + length - prevLineEnd, ""); //$NON-NLS-1$
return;
}
}
textBuffer.replace(offset, length, buf.toString());
}
private static boolean isAllCommentWhitespace(String lineStart) {
for (int i = 0; i < lineStart.length(); i++) {
char ch = lineStart.charAt(i);
if (!Character.isWhitespace(ch) && ch != '*') {
return false;
}
}
return true;
}
/**
* Returns the line delimiter which is used in the specified project.
*
* @param project
* the java project, or <code>null</code>
* @return the used line delimiter
*/
public static String getLineDelimiterUsed(IScriptProject project) {
return getProjectLineDelimiter(project);
}
private static String getProjectLineDelimiter(IScriptProject project) {
if (project == null) {
assert false;
return null;
}
String lineDelimiter = getLineDelimiterPreference(project);
if (lineDelimiter != null)
return lineDelimiter;
return System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
}
public static String getLineDelimiterPreference(IScriptProject project) {
IScopeContext[] scopeContext;
if (project != null) {
// project preference
scopeContext = new IScopeContext[] { new ProjectScope(project.getProject()) };
String lineDelimiter = Platform.getPreferencesService().getString(Platform.PI_RUNTIME,
Platform.PREF_LINE_SEPARATOR, null, scopeContext);
if (lineDelimiter != null)
return lineDelimiter;
}
// workspace preference
scopeContext = new IScopeContext[] { InstanceScope.INSTANCE };
String platformDefault = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$
return Platform.getPreferencesService().getString(Platform.PI_RUNTIME, Platform.PREF_LINE_SEPARATOR,
platformDefault, scopeContext);
}
// --------------------------- name suggestions --------------------------
public static final int STATIC_FIELD = 1;
public static final int INSTANCE_FIELD = 2;
public static final int CONSTANT_FIELD = 3;
public static final int PARAMETER = 4;
public static final int LOCAL = 5;
/**
* Only to be used by tests
*
* @param templateId
* the template id
* @param pattern
* the new pattern
* @param project
* not used
*/
public static void setCodeTemplate(String templateId, String pattern, IScriptProject project) {
TemplateStore codeTemplateStore = PHPUiPlugin.getDefault().getCodeTemplateStore();
TemplatePersistenceData data = codeTemplateStore.getTemplateData(templateId);
Template orig = data.getTemplate();
Template copy = new Template(orig.getName(), orig.getDescription(), orig.getContextTypeId(), pattern, true);
data.setTemplate(copy);
}
private static Template getCodeTemplate(String id, IScriptProject sp) {
if (sp == null)
return PHPUiPlugin.getDefault().getCodeTemplateStore().findTemplateById(id);
ProjectTemplateStore projectStore = new ProjectTemplateStore(sp.getProject());
try {
projectStore.load();
} catch (IOException e) {
PHPUiPlugin.log(e);
}
return projectStore.findTemplateById(id);
}
}