blob: 5fc5dcaf991a16a9febafbc75597690211a8f612 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.php.editor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.Document;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.modules.php.api.PhpVersion;
import org.netbeans.modules.php.editor.model.UseScope;
import org.netbeans.modules.php.editor.model.impl.Type;
import org.netbeans.modules.php.editor.model.nodes.NamespaceDeclarationInfo;
import org.netbeans.modules.php.editor.parser.astnodes.ArrayAccess;
import org.netbeans.modules.php.editor.parser.astnodes.ArrayCreation;
import org.netbeans.modules.php.editor.parser.astnodes.Assignment;
import org.netbeans.modules.php.editor.parser.astnodes.CatchClause;
import org.netbeans.modules.php.editor.parser.astnodes.ClassDeclaration;
import org.netbeans.modules.php.editor.parser.astnodes.ClassInstanceCreation;
import org.netbeans.modules.php.editor.parser.astnodes.ClassName;
import org.netbeans.modules.php.editor.parser.astnodes.Expression;
import org.netbeans.modules.php.editor.parser.astnodes.FieldAccess;
import org.netbeans.modules.php.editor.parser.astnodes.FormalParameter;
import org.netbeans.modules.php.editor.parser.astnodes.FunctionDeclaration;
import org.netbeans.modules.php.editor.parser.astnodes.FunctionInvocation;
import org.netbeans.modules.php.editor.parser.astnodes.FunctionName;
import org.netbeans.modules.php.editor.parser.astnodes.GroupUseStatementPart;
import org.netbeans.modules.php.editor.parser.astnodes.Identifier;
import org.netbeans.modules.php.editor.parser.astnodes.InfixExpression;
import org.netbeans.modules.php.editor.parser.astnodes.MethodDeclaration;
import org.netbeans.modules.php.editor.parser.astnodes.MethodInvocation;
import org.netbeans.modules.php.editor.parser.astnodes.NamespaceName;
import org.netbeans.modules.php.editor.parser.astnodes.NullableType;
import org.netbeans.modules.php.editor.parser.astnodes.Reference;
import org.netbeans.modules.php.editor.parser.astnodes.Scalar;
import org.netbeans.modules.php.editor.parser.astnodes.SingleUseStatementPart;
import org.netbeans.modules.php.editor.parser.astnodes.StaticConstantAccess;
import org.netbeans.modules.php.editor.parser.astnodes.StaticDispatch;
import org.netbeans.modules.php.editor.parser.astnodes.StaticMethodInvocation;
import org.netbeans.modules.php.editor.parser.astnodes.TypeDeclaration;
import org.netbeans.modules.php.editor.parser.astnodes.UnaryOperation;
import org.netbeans.modules.php.editor.parser.astnodes.UnaryOperation.Operator;
import org.netbeans.modules.php.editor.parser.astnodes.UseStatement;
import org.netbeans.modules.php.editor.parser.astnodes.Variable;
import org.netbeans.modules.php.editor.parser.astnodes.Variadic;
import org.netbeans.modules.php.editor.parser.astnodes.visitors.DefaultVisitor;
import org.netbeans.modules.php.project.api.PhpLanguageProperties;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.util.Parameters;
/**
*
* @author tomslot
*/
public final class CodeUtils {
public static final String FUNCTION_TYPE_PREFIX = "@fn:";
public static final String METHOD_TYPE_PREFIX = "@mtd:";
public static final String STATIC_METHOD_TYPE_PREFIX = "@static.mtd:";
public static final String NULLABLE_TYPE_PREFIX = "?"; // NOI18N
private static final Logger LOGGER = Logger.getLogger(CodeUtils.class.getName());
private CodeUtils() {
}
@CheckForNull
public static FileObject getFileObject(Document doc) {
Object sdp = doc.getProperty(Document.StreamDescriptionProperty);
if (sdp instanceof FileObject) {
return (FileObject) sdp;
}
if (sdp instanceof DataObject) {
return ((DataObject) sdp).getPrimaryFile();
}
return null;
}
public static UseScope.Type mapType(UseStatement.Type type) {
UseScope.Type newType = null;
switch (type) {
case CONST:
newType = UseScope.Type.CONST;
break;
case FUNCTION:
newType = UseScope.Type.FUNCTION;
break;
case TYPE:
newType = UseScope.Type.TYPE;
break;
default:
assert false : "Unknown type: " + type;
}
return newType;
}
// XXX move to proper place
/**
* Compounds full namespace for the given part of group use.
* @param groupUseStatementPart group use part
* @param singleUseStatementPart part to be resolved
* @param baseOffsets if {@code true}, offsets of base namespace name are used
* @return full namespace for the given part of group use
*/
public static NamespaceName compoundName(GroupUseStatementPart groupUseStatementPart, SingleUseStatementPart singleUseStatementPart, boolean baseOffsets) {
assert groupUseStatementPart != null;
assert singleUseStatementPart != null;
assert groupUseStatementPart.getItems().contains(singleUseStatementPart) : singleUseStatementPart + " not found in: " + groupUseStatementPart.getItems();
NamespaceName baseNamespaceName = groupUseStatementPart.getBaseNamespaceName();
NamespaceName namespaceName = singleUseStatementPart.getName();
List<Identifier> segments = new ArrayList<>(baseNamespaceName.getSegments().size() + namespaceName.getSegments().size());
segments.addAll(baseNamespaceName.getSegments());
segments.addAll(namespaceName.getSegments());
int start;
int end;
if (baseOffsets) {
start = baseNamespaceName.getStartOffset();
end = baseNamespaceName.getEndOffset();
} else {
start = namespaceName.getStartOffset();
end = namespaceName.getEndOffset();
}
return new NamespaceName(start, end, segments, baseNamespaceName.isGlobal(), baseNamespaceName.isCurrent());
}
/**
* Checks whether the given name is synthetic name. It means that
* the name starts with "#".
* @param name name to be checked
* @return {@code true} if the given name is synthetic
*/
public static boolean isSyntheticTypeName(String name) {
assert name != null;
return !name.isEmpty()
&& name.charAt(0) == '#'; // NOI18N
}
/**
* Checks whether the given name is synthetic name. It means that
* the name contains ":" (e.g. LambdaFunctionDeclaration:11).
* @param name name to be checked
* @return {@code true} if the given name is synthetic
*/
public static boolean isSyntheticFunctionName(String name) {
assert name != null;
return !name.isEmpty()
&& name.contains(":"); // NOI18N
}
public static PhpVersion getPhpVersion(FileObject file) {
assert file != null;
return PhpLanguageProperties.forFileObject(file).getPhpVersion();
}
public static boolean isPhpVersion(FileObject file, PhpVersion version) {
assert file != null;
assert version != null;
return getPhpVersion(file) == version;
}
public static boolean isPhpVersionLessThan(FileObject file, PhpVersion version) {
assert file != null;
assert version != null;
return getPhpVersion(file).compareTo(version) < 0;
}
public static boolean isPhpVersionGreaterThan(FileObject file, PhpVersion version) {
assert file != null;
assert version != null;
return getPhpVersion(file).compareTo(version) > 0;
}
/**
* @return {@code true} if the {@link StaticDispatch#getDispatcher() dispatcher}
* is not just identifier or a namespace name.
*/
public static boolean isUniformVariableSyntax(StaticDispatch dispatch) {
assert dispatch != null;
return isUniformVariableSyntax(dispatch.getDispatcher());
}
/**
* @return {@code true} if the given expression
* is not just identifier or a namespace name.
*/
public static boolean isUniformVariableSyntax(Expression expression) {
assert expression != null;
return extractUnqualifiedName(expression) == null;
}
@CheckForNull
public static Identifier extractUnqualifiedIdentifier(Expression typeName) {
Parameters.notNull("typeName", typeName); // NOI18N
if (typeName instanceof Identifier) {
return (Identifier) typeName;
} else if (typeName instanceof NamespaceName) {
return extractUnqualifiedIdentifier((NamespaceName) typeName);
} else if (typeName instanceof Variable) {
Variable v = (Variable) typeName;
return extractUnqualifiedIdentifier(v.getName()); // #167863
} else if (typeName instanceof FieldAccess) {
return extractUnqualifiedIdentifier(((FieldAccess) typeName).getField()); // #167863
} else if (typeName instanceof NullableType) {
return extractUnqualifiedIdentifier(((NullableType) typeName).getType());
}
//TODO: php5.3 !!!
//assert false : typeName.getClass(); //NOI18N
return null;
}
/**
* Extract unqualified name for Identifier, NamespaceName, and NullableType.
*
* @param typeName The type name
* @return The type name. If it is a nullable type, the name is returned with "?"
*/
@CheckForNull
public static String extractUnqualifiedName(Expression typeName) {
Parameters.notNull("typeName", typeName); // NOI18N
if (typeName instanceof Identifier) {
return ((Identifier) typeName).getName();
} else if (typeName instanceof NamespaceName) {
return extractUnqualifiedName((NamespaceName) typeName);
} else if (typeName instanceof NullableType) {
return NULLABLE_TYPE_PREFIX + extractUnqualifiedName(((NullableType) typeName).getType());
}
//TODO: php5.3 !!!
//assert false : "[php5.3] className Expression instead of Identifier"; //NOI18N
return null;
}
/**
* Extract qualified name for Identifier, NamespaceName, and NullableType.
*
* @param typeName The type name
* @return The type name. If it is a nullable type, the name is returned with "?"
*/
@CheckForNull
public static String extractQualifiedName(Expression typeName) {
Parameters.notNull("typeName", typeName); // NOI18N
if (typeName instanceof Identifier) {
return ((Identifier) typeName).getName();
} else if (typeName instanceof NamespaceName) {
return extractQualifiedName((NamespaceName) typeName);
} else if (typeName instanceof NullableType) {
NullableType nullableType = (NullableType) typeName;
return NULLABLE_TYPE_PREFIX + extractQualifiedName(nullableType.getType());
}
assert false : typeName.getClass();
return null;
}
// XXX not only class name anymore in php7+
public static String extractUnqualifiedClassName(StaticDispatch dispatch) {
Parameters.notNull("dispatch", dispatch);
Expression dispatcher = dispatch.getDispatcher();
return extractUnqualifiedName(dispatcher);
}
public static String extractUnqualifiedTypeName(FormalParameter param) {
Parameters.notNull("param", param);
Expression typeName = param.getParameterType();
return typeName != null ? extractUnqualifiedName(typeName) : null;
}
public static List<String> extractUnqualifiedTypeName(CatchClause catchClause) {
Parameters.notNull("catchClause", catchClause);
List<String> typeNames = new ArrayList<>();
for (Expression className : catchClause.getClassNames()) {
if (className != null) {
String typeName = extractUnqualifiedName(className);
if (typeName != null) {
typeNames.add(typeName);
}
}
}
return typeNames;
}
public static String extractUnqualifiedSuperClassName(ClassDeclaration clsDeclaration) {
Parameters.notNull("clsDeclaration", clsDeclaration);
Expression clsName = clsDeclaration.getSuperClass();
return clsName != null ? extractUnqualifiedName(clsName) : null;
}
@CheckForNull
public static String extractUnqualifiedSuperClassName(ClassInstanceCreation classInstanceCreation) {
assert classInstanceCreation != null;
assert classInstanceCreation.isAnonymous() : classInstanceCreation;
Expression clsName = classInstanceCreation.getSuperClass();
return clsName != null ? extractUnqualifiedName(clsName) : null;
}
public static String extractUnqualifiedName(NamespaceName namespaceName) {
final List<Identifier> segments = namespaceName.getSegments();
return segments.get(segments.size() - 1).getName();
}
public static String extractQualifiedName(NamespaceName namespaceName) {
Parameters.notNull("namespaceName", namespaceName);
StringBuilder sb = new StringBuilder();
final List<Identifier> segments = namespaceName.getSegments();
if (namespaceName.isGlobal()) {
sb.append(NamespaceDeclarationInfo.NAMESPACE_SEPARATOR);
}
for (Iterator<Identifier> it = segments.iterator(); it.hasNext();) {
Identifier identifier = it.next();
sb.append(identifier.getName());
if (it.hasNext()) {
sb.append(NamespaceDeclarationInfo.NAMESPACE_SEPARATOR);
}
}
return sb.toString();
}
public static Identifier extractUnqualifiedIdentifier(NamespaceName namespaceName) {
final List<Identifier> segments = namespaceName.getSegments();
if (segments.size() >= 1) {
return segments.get(segments.size() - 1);
}
//TODO: php5.3 !!!
//assert false : "[php5.3] className Expression instead of Identifier"; //NOI18N
return null;
}
//TODO: rewrite for php53
public static String extractClassName(ClassName clsName) {
assert clsName != null;
Expression name = clsName.getName();
while (name instanceof Variable || name instanceof FieldAccess) {
if (name instanceof Variable) {
Variable var = (Variable) name;
name = var.getName();
} else if (name instanceof FieldAccess) {
FieldAccess fld = (FieldAccess) name;
name = fld.getField().getName();
}
}
if (name instanceof NamespaceName) {
return extractQualifiedName((NamespaceName) name);
}
return (name instanceof Identifier) ? ((Identifier) name).getName() : ""; //NOI18N
}
public static String extractClassName(ClassDeclaration clsDeclaration) {
return clsDeclaration.getName().getName();
}
public static String extractClassName(ClassInstanceCreation classInstanceCreation) {
return extractClassName(classInstanceCreation.getClassName());
}
public static String extractTypeName(TypeDeclaration typeDeclaration) {
return typeDeclaration.getName().getName();
}
private static final class VariableNameVisitor extends DefaultVisitor {
private String name = null;
private boolean isDollared = false;
private VariableNameVisitor() {
}
private static class SingletonHolder {
public static final VariableNameVisitor INSTANCE = new VariableNameVisitor();
}
public static VariableNameVisitor getInstance() {
return SingletonHolder.INSTANCE;
}
public String findName(Variable var) {
name = null;
scan(var);
return name;
}
@Override
public void visit(Scalar node) {
final String scalarName = node.getStringValue();
if ((scalarName.startsWith("'") && scalarName.endsWith("'"))
|| (scalarName.startsWith("\"") && scalarName.endsWith("\""))) { //NOI18N
name = scalarName.substring(1, scalarName.length() - 1);
} else {
name = scalarName;
}
}
@Override
public void visit(Variable node) {
isDollared = node.isDollared();
super.visit(node);
}
@Override
public void visit(InfixExpression node) {
}
@Override
public void visit(Identifier identifier) {
name = isDollared ? "$" + identifier.getName() : identifier.getName();
}
@Override
public void visit(ArrayAccess node) {
scan(node.getName());
}
}
@CheckForNull // null for RelectionVariable
public static String extractVariableName(Variable var) {
String variableName = VariableNameVisitor.getInstance().findName(var);
if (variableName == null) {
LOGGER.log(Level.FINE, "Can not retrieve variable name: {0}", var);
}
return variableName;
}
@CheckForNull
public static String extractFormalParameterName(FormalParameter param) {
Expression expression = param.getParameterName();
if (expression instanceof Reference) {
expression = ((Reference) expression).getExpression();
}
if (expression instanceof Variadic) {
expression = ((Variadic) expression).getExpression();
}
if (expression instanceof Variable) {
Variable variable = (Variable) expression;
return extractVariableName(variable);
}
return null;
}
public static String extractVariableType(Assignment assignment) {
Expression rightSideExpression = assignment.getRightHandSide();
if (rightSideExpression instanceof Assignment) {
// handle nested assignments, e.g. $l = $m = new ObjectName;
return extractVariableType((Assignment) assignment.getRightHandSide());
} else if (rightSideExpression instanceof Reference) {
Reference ref = (Reference) rightSideExpression;
rightSideExpression = ref.getExpression();
}
if (rightSideExpression instanceof ClassInstanceCreation) {
ClassInstanceCreation classInstanceCreation = (ClassInstanceCreation) rightSideExpression;
Expression className = classInstanceCreation.getClassName().getName();
return CodeUtils.extractUnqualifiedName(className);
} else if (rightSideExpression instanceof ArrayCreation) {
return Type.ARRAY;
} else if (rightSideExpression instanceof FunctionInvocation) {
FunctionInvocation functionInvocation = (FunctionInvocation) rightSideExpression;
String fname = extractFunctionName(functionInvocation);
return FUNCTION_TYPE_PREFIX + fname;
} else if (rightSideExpression instanceof StaticMethodInvocation) {
StaticMethodInvocation staticMethodInvocation = (StaticMethodInvocation) rightSideExpression;
String className = CodeUtils.extractUnqualifiedClassName(staticMethodInvocation);
String methodName = extractFunctionName(staticMethodInvocation.getMethod());
if (className != null && methodName != null) {
return STATIC_METHOD_TYPE_PREFIX + className + '.' + methodName;
}
} else if (rightSideExpression instanceof MethodInvocation) {
MethodInvocation methodInvocation = (MethodInvocation) rightSideExpression;
String varName = null;
if (methodInvocation.getDispatcher() instanceof Variable) {
Variable var = (Variable) methodInvocation.getDispatcher();
varName = extractVariableName(var);
}
String methodName = extractFunctionName(methodInvocation.getMethod());
if (varName != null && methodName != null) {
return METHOD_TYPE_PREFIX + varName + '.' + methodName;
}
}
return null;
}
public static String extractFunctionName(FunctionInvocation functionInvocation) {
return extractFunctionName(functionInvocation.getFunctionName());
}
public static String extractFunctionName(FunctionDeclaration functionDeclaration) {
return functionDeclaration.getFunctionName().getName();
}
public static String extractMethodName(MethodDeclaration methodDeclaration) {
return methodDeclaration.getFunction().getFunctionName().getName();
}
@CheckForNull
public static String extractFunctionName(FunctionName functionName) {
if (functionName.getName() instanceof Identifier) {
Identifier id = (Identifier) functionName.getName();
return id.getName();
} else if (functionName.getName() instanceof NamespaceName) {
return extractUnqualifiedName((NamespaceName) functionName.getName());
} else if (functionName.getName() instanceof Scalar) {
String scalarName = ((Scalar) functionName.getName()).getStringValue();
if (isQuoted(scalarName)) {
return scalarName.substring(1, scalarName.length() - 1);
}
}
if (functionName.getName() instanceof Variable) {
Variable var = (Variable) functionName.getName();
return extractVariableName(var);
}
return null;
}
private static boolean isQuoted(String string) {
return string != null
&& string.length() > 2
&& ((string.startsWith("'") && string.endsWith("'")) || (string.startsWith("\"") && string.endsWith("\""))); // NOI18N
}
@CheckForNull
public static String getParamDefaultValue(FormalParameter param) {
Expression expr = param.getDefaultValue();
//TODO: can be improved
Operator operator = null;
if (expr instanceof UnaryOperation) {
UnaryOperation unaryExpr = (UnaryOperation) expr;
operator = unaryExpr.getOperator();
expr = unaryExpr.getExpression();
}
if (expr instanceof Scalar) {
Scalar scalar = (Scalar) expr;
String returnValue = scalar.getStringValue();
return Operator.MINUS.equals(operator) ? "-" + returnValue : returnValue; // NOI18N
} else if (expr instanceof NamespaceName) {
return extractQualifiedName((NamespaceName) expr);
} else if (expr instanceof ArrayCreation) {
return "array()"; //NOI18N
} else if (expr instanceof StaticConstantAccess) {
StaticConstantAccess staticConstantAccess = (StaticConstantAccess) expr;
Expression dispatcher = staticConstantAccess.getDispatcher();
if (dispatcher instanceof Identifier) {
Identifier i = (Identifier) dispatcher;
return i.getName() + "::" + staticConstantAccess.getConstantName().getName(); // NOI18N
} else if (dispatcher instanceof NamespaceName) {
NamespaceName namespace = (NamespaceName) dispatcher;
StringBuilder sb = new StringBuilder(extractQualifiedName(namespace));
return sb.append("::").append(staticConstantAccess.getConstantName().getName()).toString(); // NOI18N
}
}
return expr == null ? null : " "; //NOI18N
}
public static String getParamDisplayName(FormalParameter param) {
Expression paramNameExpr = param.getParameterName();
StringBuilder paramName = new StringBuilder();
if (paramNameExpr instanceof Variable) {
Variable var = (Variable) paramNameExpr;
Identifier id = (Identifier) var.getName();
if (var.isDollared()) {
paramName.append("$"); //NOI18N
}
paramName.append(id.getName());
} else if (paramNameExpr instanceof Reference) {
paramName.append("&");
Reference reference = (Reference) paramNameExpr;
Expression expression = reference.getExpression();
if (expression instanceof Variadic) {
Variadic variadic = (Variadic) expression;
paramName.append("..."); //NOI18N
expression = variadic.getExpression();
}
if (expression instanceof Variable) {
Variable var = (Variable) reference.getExpression();
if (var.isDollared()) {
paramName.append("$"); //NOI18N
}
Identifier id = (Identifier) var.getName();
paramName.append(id.getName());
}
}
return paramName.length() == 0 ? null : paramName.toString();
}
public static boolean isConstructor(MethodDeclaration node) {
return "__construct".equals(extractMethodName(node)); //NOI18N
}
/**
* Finds common namespace prefixes for the given <b>sorted</b> namespaces.
* <p>
* Note: all returned prefixes start and end with '\\'.
* @param namespaces input namespaces (<b>must be sorted!</b>)
* @return list of common namespace prefixes or empty list, never {@code null}
*/
public static List<String> getCommonNamespacePrefixes(List<String> namespaces) {
if (namespaces.isEmpty()) {
return Collections.emptyList();
}
LinkedList<String> fqNamespaces = new LinkedList<>();
for (String namespace : namespaces) {
fqNamespaces.add(fullyQualifyNamespace(namespace));
}
List<String> prefixes = new ArrayList<>(fqNamespaces.size());
while (!fqNamespaces.isEmpty()) {
String namespace = fqNamespaces.poll();
if (fqNamespaces.isEmpty()) {
break;
}
assert namespace.charAt(0) == '\\' : namespace;
int separatorIndex = namespace.indexOf('\\', 1); // NOI18N
if (separatorIndex == -1) {
// no ns separator
continue;
}
String prefix = namespace.substring(0, separatorIndex + 1);
List<String> prefixedNamespaces = new ArrayList<>(fqNamespaces.size());
// get all namespaces that start with this prefix
for (Iterator<String> iterator = fqNamespaces.iterator(); iterator.hasNext();) {
String ns = iterator.next();
if (ns.startsWith(prefix)) {
prefixedNamespaces.add(ns);
iterator.remove();
} else {
break;
}
}
if (prefixedNamespaces.isEmpty()) {
// not common ns prefix
continue;
}
prefixedNamespaces.add(0, namespace);
if (prefixedNamespaces.size() > 1) {
// find common longest prefix
prefix = null;
for (int i = 1; i < prefixedNamespaces.size(); i++) {
String prev = prefixedNamespaces.get(i - 1);
String next = prefixedNamespaces.get(i);
String tmpPrefix = getCommonNamespacePrefix(prev, next);
assert tmpPrefix != null : prev + " :: " + next;
if (prefix == null) {
prefix = tmpPrefix;
} else if (prefix.length() > tmpPrefix.length()) {
prefix = tmpPrefix;
}
}
assert prefix != null : prefixedNamespaces;
}
prefixes.add(prefix);
}
return prefixes;
}
@CheckForNull
static String getCommonNamespacePrefix(String ns1, String ns2) {
assert ns1 != null;
assert ns2 != null;
String fqns1 = fullyQualifyNamespace(ns1);
String fqns2 = fullyQualifyNamespace(ns2);
int index;
for (index = 0; index < fqns1.length() && index < fqns2.length(); index++) {
if (fqns1.charAt(index) != fqns2.charAt(index)) {
break;
}
}
// check shortest common prefix (e.g. '\A\')
if (index < 3) {
return null;
}
String prefix = fqns1.substring(0, index);
if (prefix.charAt(index - 1) == '\\') { // NOI18N
return prefix;
}
// find last '\' (avoid first '\')
int lastNsIndex = prefix.lastIndexOf('\\'); // NOI18N
if (lastNsIndex <= 0) {
// not found or the first '\'
return null;
}
return prefix.substring(0, lastNsIndex + 1);
}
public static String fullyQualifyNamespace(String namespace) {
assert namespace != null;
if (!namespace.isEmpty()
&& namespace.charAt(0) != '\\') { // NOI18N
return '\\' + namespace; // NOI18N
}
return namespace;
}
/**
* Check whether a type name starts with "?".
*
* @param typeName a type name
* @return {@code true} if the name starts with "?", otherwise
* {@code false}
*/
public static boolean isNullableType(String typeName) {
if (typeName == null || typeName.isEmpty()) {
return false;
}
return typeName.startsWith(NULLABLE_TYPE_PREFIX);
}
/**
* Remove the nullable type prefix("?") from the type name.
*
* @param typeName the type name
* @return the type name from which the prefix is removed if it is a
* nullable type, otherwise itself
*/
public static String removeNullableTypePrefix(String typeName) {
if (isNullableType(typeName)) {
return typeName.substring(1);
}
return typeName;
}
}