Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion php/php.editor/nbproject/project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
nbjavac.ignore.missing.enclosing=**/CUP$ASTPHP5Parser$actions.class
nbm.needs.restart=true
spec.version.base=2.37.0
spec.version.base=2.38.0
release.external/predefined_vars-1.0.zip=docs/predefined_vars.zip
sigtest.gen.fail.on.error=false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public final class CodeUtils {
public static final String EMPTY_STRING = ""; // NOI18N
public static final String NEW_LINE = "\n"; // NOI18N
public static final String THIS_VARIABLE = "$this"; // NOI18N
public static final String NS_SEPARATOR = "\\"; // NOI18N

public static final Pattern WHITE_SPACES_PATTERN = Pattern.compile("\\s+"); // NOI18N
public static final Pattern SPLIT_TYPES_PATTERN = Pattern.compile("[()|&]+"); // NOI18N
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,17 @@ public interface Index extends ElementQuery {

Set<EnumElement> getEnums(NameKind query, Set<AliasedName> aliases, AliasedElement.Trait trait);

/**
* Get traits.
*
* @param query the query
* @param aliases aliased names
* @param trait the trait
* @return traits
* @since 2.38.0
*/
Set<TraitElement> getTraits(NameKind query, Set<AliasedName> aliases, AliasedElement.Trait trait);

Set<TraitElement> getTraits(final NameKind query);

Set<EnumElement> getEnums(final NameKind query);
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/

package org.netbeans.modules.php.editor.codegen;

import java.util.ArrayList;
Expand All @@ -32,6 +31,8 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.lib.editor.codetemplates.spi.CodeTemplateInsertRequest;
import org.netbeans.lib.editor.codetemplates.spi.CodeTemplateParameter;
import org.netbeans.lib.editor.codetemplates.spi.CodeTemplateProcessor;
Expand All @@ -44,6 +45,7 @@
import org.netbeans.modules.parsing.spi.ParseException;
import org.netbeans.modules.parsing.spi.Parser;
import org.netbeans.modules.php.api.util.StringUtils;
import org.netbeans.modules.php.editor.CodeUtils;
import org.netbeans.modules.php.editor.model.Model;
import org.netbeans.modules.php.editor.model.ModelUtils;
import org.netbeans.modules.php.editor.model.TypeScope;
Expand Down Expand Up @@ -87,6 +89,71 @@ public void updateDefaultValues() {
param.setValue(value);
}
}
updateImport();
}

private void updateImport() {
final AutoImport.Hints autoImportHints = getAutoImportHints();
if (autoImportHints != null) {
JTextComponent component = request.getComponent();
if (component == null) {
return;
}
final Document doc = component.getDocument();
if (doc == null) {
return;
}
RP.schedule(() -> {
try {
PHPParseResult[] result = new PHPParseResult[1];
ParserManager.parse(Collections.singleton(Source.create(doc)), new UserTask() {

@Override
public void run(ResultIterator resultIterator) throws Exception {
Parser.Result parserResult = resultIterator.getParserResult();
if (parserResult instanceof PHPParseResult) {
result[0] = (PHPParseResult) parserResult;
}
}
});
AutoImport.get(result[0]).insert(autoImportHints, component.getCaretPosition());
} catch (ParseException ex) {
LOGGER.log(Level.WARNING, null, ex);
}
}, 300, TimeUnit.MILLISECONDS);
}
}

@CheckForNull
private AutoImport.Hints getAutoImportHints() {
String fqName = CodeUtils.EMPTY_STRING;
String aliasName = CodeUtils.EMPTY_STRING;
String useType = CodeUtils.EMPTY_STRING;
for (CodeTemplateParameter param : request.getMasterParameters()) {
if (param.getName().equals(AutoImport.PARAM_NAME)) {
for (Entry<String, String> entry : param.getHints().entrySet()) {
String key = entry.getKey();
switch (key) {
case AutoImport.PARAM_KEY_FQ_NAME:
fqName = entry.getValue();
break;
case AutoImport.PARAM_KEY_ALIAS_NAME:
aliasName = entry.getValue();
break;
case AutoImport.PARAM_KEY_USE_TYPE:
useType = entry.getValue();
break;
default:
// noop
break;
}
}
if (!fqName.isEmpty() && !useType.isEmpty()) {
return new AutoImport.Hints(fqName, useType, aliasName);
}
}
}
return null;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1025,7 +1025,9 @@ private void autoCompleteAfterUseTrait(final PHPCompletionResult completionResul
completionResult.add(new PHPCompletionItem.NamespaceItem(namespace, request, QualifiedNameKind.FULLYQUALIFIED));
}
final NameKind nameQuery = NameKind.caseInsensitivePrefix(request.prefix);
for (TraitElement trait : request.index.getTraits(nameQuery)) {
Model model = request.result.getModel();
Set<TraitElement> traits = request.index.getTraits(nameQuery, ModelUtils.getAliasedNames(model, request.anchor), Trait.ALIAS);
for (TraitElement trait : traits) {
if (CancelSupport.getDefault().isCancelled()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import javax.swing.ImageIcon;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.editor.EditorRegistry;
import org.netbeans.api.editor.completion.Completion;
Expand Down Expand Up @@ -105,7 +106,9 @@
import static org.netbeans.modules.php.editor.PredefinedSymbols.Attributes.OVERRIDE;
import org.netbeans.modules.php.editor.api.elements.EnumCaseElement;
import org.netbeans.modules.php.editor.api.elements.EnumElement;
import org.netbeans.modules.php.editor.codegen.AutoImport;
import org.netbeans.modules.php.editor.elements.ElementUtils;
import org.netbeans.modules.php.editor.options.CodeCompletionPanel;
import org.netbeans.modules.php.editor.options.CodeCompletionPanel.CodeCompletionType;
import org.netbeans.modules.php.editor.options.OptionsUtils;
import org.netbeans.modules.php.editor.parser.PHPParseResult;
Expand All @@ -129,16 +132,23 @@ public abstract class PHPCompletionItem implements CompletionProposal {
protected static final ImageIcon KEYWORD_ICON = IconsUtils.loadKeywordIcon();
protected static final ImageIcon ENUM_CASE_ICON = IconsUtils.loadEnumCaseIcon();
private static final int TYPE_NAME_MAX_LENGTH = Integer.getInteger("nb.php.editor.ccTypeNameMaxLength", 30); // NOI18N
final CompletionRequest request;
private final ElementHandle element;
private QualifiedNameKind generateAs;
private static ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
private static final Cache<FileObject, PhpLanguageProperties> PROPERTIES_CACHE
= new Cache<>(new WeakHashMap<>());
private static final String AUTO_IMPORT_PARAM_FORMAT = "%s${php-auto-import default=\"\" fqName=%s aliasName=\"%s\" useType=%s editable=false}"; // NOI18N
private static ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
private static volatile Boolean ADD_FIRST_CLASS_CALLABLE = null; // for unit tests

final CompletionRequest request;
private final ElementHandle element;
private final boolean isPlatform;
private final boolean isDeprecated;
private QualifiedNameKind generateAs;

// for unit tests
private PhpVersion phpVersion;
private static volatile Boolean ADD_FIRST_CLASS_CALLABLE = null; // for unit tests
private CodeCompletionType codeCompletionType;
private Boolean isAutoImport = null;
private Boolean isGlobalItemImportable = null;

PHPCompletionItem(ElementHandle element, CompletionRequest request, QualifiedNameKind generateAs) {
this.request = request;
Expand Down Expand Up @@ -289,19 +299,23 @@ public String getInsertPrefix() {
}
if (props.getPhpVersion() != PhpVersion.PHP_5) {
if (generateAs == null) {
CodeCompletionType codeCompletionType = OptionsUtils.codeCompletionType();
switch (codeCompletionType) {
CodeCompletionType completionType = getCodeCompletionType();
switch (completionType) {
case FULLY_QUALIFIED:
template.append(ifq.getFullyQualifiedName());
return template.toString();
case UNQUALIFIED:
String autoImportTemplate = createAutoImportTemplate(ifq);
if (autoImportTemplate != null) {
return autoImportTemplate;
}
template.append(getName());
return template.toString();
case SMART:
generateAs = qn.getKind();
break;
default:
assert false : codeCompletionType;
assert false : completionType;
}
}
} else {
Expand Down Expand Up @@ -359,12 +373,121 @@ public String getInsertPrefix() {
assert false : "[" + tpl + "] should start with [" + extraPrefix + "]";
}
}
String autoImportTemplate = createAutoImportTemplate(ifq);
if (autoImportTemplate != null) {
return autoImportTemplate;
}
return tpl;
}

return getName();
}

@CheckForNull
private String createAutoImportTemplate(FullyQualifiedElement fullyQualifiedElement) {
if (isAutoImport()) {
String fqName = fullyQualifiedElement.getFullyQualifiedName().toString().substring(CodeUtils.NS_SEPARATOR.length());
String name = getName();
String useType = getUseType();
String aliasName = CodeUtils.EMPTY_STRING;
boolean isGlobalNamespace = !fqName.contains(CodeUtils.NS_SEPARATOR);
Model model = request.result.getModel();
NamespaceDeclaration namespaceDeclaration = findEnclosingNamespace(request.result, request.anchor);
NamespaceScope namespaceScope = ModelUtils.getNamespaceScope(namespaceDeclaration, model.getFileScope());
if (!useType.isEmpty() && isImportableScope() && !AutoImport.sameUseNameExists(name, fqName, AutoImport.getUseScopeType(useType), namespaceScope)) {
if (isAutoImportContext(request.context) && !fullyQualifiedElement.isAliased() && isGlobalItemImportable(isGlobalNamespace)) {
// note: add an empty parameter(hidden parameter) after a name to avoid filtering completion items
// if we add a default value to the parameter template, completion items are removed(filtered) from a completion list when we move the caret.
// see: org.netbeans.modules.csl.editor.completion.GsfCompletionProvider.JavaCompletionQuery.getFilteredData()
return String.format(AUTO_IMPORT_PARAM_FORMAT, name, fqName, aliasName, useType);
}
}
}
return null;
}

// for unit tests
void setAutoImport(boolean isAutoImport) {
this.isAutoImport = isAutoImport;
}

private boolean isAutoImport() {
if (isAutoImport != null) {
// for unit tests
return isAutoImport;
}
return OptionsUtils.autoImport();
}

// for unit tests
void setCodeCompletionType(CodeCompletionType codeCompletionType) {
this.codeCompletionType = codeCompletionType;
}

private CodeCompletionType getCodeCompletionType() {
if (codeCompletionType != null) {
// for unit tests
return codeCompletionType;
}
return OptionsUtils.codeCompletionType();
}

// for unit tests
void setGlobalItemImportable(boolean isGlobalItemImportable) {
this.isGlobalItemImportable = isGlobalItemImportable;
}

private boolean isGlobalItemImportable(boolean isGlobalNamespace) {
if (isGlobalNamespace) {
if (isGlobalItemImportable != null) {
// for unit tests
return isGlobalItemImportable;
}
CodeCompletionPanel.GlobalNamespaceAutoImportType globalNSImport = null;
switch (getUseType()) {
case AutoImport.USE_TYPE:
globalNSImport = OptionsUtils.globalNSImportType();
break;
case AutoImport.USE_FUNCTION:
globalNSImport = OptionsUtils.globalNSImportFunction();
break;
case AutoImport.USE_CONST:
globalNSImport = OptionsUtils.globalNSImportConst();
break;
default:
assert false : "Unknown use type: " + getUseType(); // NOI18N
}
return globalNSImport == CodeCompletionPanel.GlobalNamespaceAutoImportType.IMPORT;
}
return true;
}

private boolean isImportableScope() {
Model model = request.result.getModel();
Collection<? extends NamespaceScope> declaredNamespaces = model.getFileScope().getDeclaredNamespaces();
NamespaceDeclaration namespaceDeclaration = findEnclosingNamespace(request.result, request.anchor);
if (declaredNamespaces.size() > 1 && namespaceDeclaration == null) {
return false;
} else if (declaredNamespaces.size() == 1) {
return OptionsUtils.autoImportFileScope();
} else if (namespaceDeclaration != null) {
return OptionsUtils.autoImportNamespaceScope();
}
return false;
}

private String getUseType() {
String useType = CodeUtils.EMPTY_STRING;
if (getKind() == ElementKind.CLASS || getKind() == ElementKind.CONSTRUCTOR) {
useType = AutoImport.USE_TYPE;
} else if (this instanceof ConstantItem) {
useType = AutoImport.USE_CONST;
} else if (this instanceof FunctionElementItem) {
useType = AutoImport.USE_FUNCTION;
}
return useType;
}

@Override
public String getRhsHtml(HtmlFormatter formatter) {
if (element instanceof TypeMemberElement) {
Expand Down Expand Up @@ -478,6 +601,15 @@ private boolean isNewClassContext(CompletionContext context) {
|| context.equals(CompletionContext.ATTRIBUTE);
}

private boolean isAutoImportContext(CompletionContext context) {
return context != CompletionContext.GROUP_USE_KEYWORD
&& context != CompletionContext.GROUP_USE_FUNCTION_KEYWORD
&& context != CompletionContext.GROUP_USE_CONST_KEYWORD
&& context != CompletionContext.USE_KEYWORD
&& context != CompletionContext.USE_FUNCTION_KEYWORD
&& context != CompletionContext.USE_CONST_KEYWORD;
}

static class NewClassItem extends MethodElementItem {

/**
Expand Down Expand Up @@ -1794,6 +1926,11 @@ public String getName() {
return super.getName();
}

@Override
public String getCustomInsertTemplate() {
return super.getInsertPrefix();
}

@Override
public String getLhsHtml(HtmlFormatter formatter) {
ElementHandle element = getElement();
Expand Down Expand Up @@ -1844,6 +1981,10 @@ public ElementKind getKind() {
return ElementKind.CLASS;
}

@Override
public String getCustomInsertTemplate() {
return super.getInsertPrefix();
}
}

static class ClassItem extends PHPCompletionItem {
Expand Down
Loading