Skip to content

Commit

Permalink
Merge pull request apache#1605 from junichi11/netbeans-1855-cc-improv…
Browse files Browse the repository at this point in the history
…ement

[NETBEANS-1855] Autocomplete for property and method without $this->
  • Loading branch information
tmysik authored Nov 6, 2019
2 parents fb38c4e + fb4357f commit 3e50d3f
Show file tree
Hide file tree
Showing 29 changed files with 765 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ public CodeCompletionResult complete(CodeCompletionContext completionContext) {
autoCompleteTypeNames(completionResult, request, null, true);
autoCompleteConstants(completionResult, request);
autoCompleteKeywords(completionResult, request, PHP_CLASS_CONST_KEYWORDS);
// NETBEANS-1855
if (!request.prefix.contains("\\")) { // NOI18N
// e.g. const CONSTANT = \^Foo\Bar::CONSTANT;
autoCompleteClassConstants(completionResult, request);
}
break;
case HTML:
case OPEN_TAG:
Expand Down Expand Up @@ -1155,6 +1160,14 @@ private void autoCompleteClassMembers(
final PHPCompletionResult completionResult,
PHPCompletionItem.CompletionRequest request,
boolean staticContext) {
autoCompleteClassMembers(completionResult, request, staticContext, false);
}

private void autoCompleteClassMembers(
final PHPCompletionResult completionResult,
PHPCompletionItem.CompletionRequest request,
boolean staticContext,
boolean completeAccessPrefix) {
if (CancelSupport.getDefault().isCancelled()) {
return;
}
Expand Down Expand Up @@ -1209,13 +1222,23 @@ private void autoCompleteClassMembers(
Collection<? extends TypeScope> types = ModelUtils.resolveTypeAfterReferenceToken(model, tokenSequence, request.anchor, specialVariable);
if (types != null) {
TypeElement enclosingType = getEnclosingType(request, types);
if (completeAccessPrefix) {
// NETBEANS-1855
types = ModelUtils.resolveType(model, request.anchor);
}
Set<PhpElement> duplicateElementCheck = new HashSet<>();
for (TypeScope typeScope : types) {
if (CancelSupport.getDefault().isCancelled()) {
return;
}
final StaticOrInstanceMembersFilter staticFlagFilter =
new StaticOrInstanceMembersFilter(staticContext, instanceContext, selfContext, staticLateBindingContext);
final ElementFilter staticFlagFilter = !completeAccessPrefix
? new StaticOrInstanceMembersFilter(staticContext, instanceContext, selfContext, staticLateBindingContext)
: new ElementFilter() { // NETBEANS-1855
@Override
public boolean isAccepted(PhpElement element) {
return true;
}
};

final ElementFilter methodsFilter = ElementFilter.allOf(
ElementFilter.forKind(PhpElementKind.METHOD),
Expand Down Expand Up @@ -1249,7 +1272,7 @@ private void autoCompleteClassMembers(
if (duplicateElementCheck.add(phpElement)) {
if (methodsFilter.isAccepted(phpElement)) {
MethodElement method = (MethodElement) phpElement;
List<MethodElementItem> items = PHPCompletionItem.MethodElementItem.getItems(method, request);
List<MethodElementItem> items = PHPCompletionItem.MethodElementItem.getItems(method, request, completeAccessPrefix);
for (MethodElementItem methodItem : items) {
if (CancelSupport.getDefault().isCancelled()) {
return;
Expand All @@ -1258,11 +1281,11 @@ private void autoCompleteClassMembers(
}
} else if (fieldsFilter.isAccepted(phpElement)) {
FieldElement field = (FieldElement) phpElement;
FieldItem fieldItem = PHPCompletionItem.FieldItem.getItem(field, request);
FieldItem fieldItem = PHPCompletionItem.FieldItem.getItem(field, request, false, completeAccessPrefix);
completionResult.add(fieldItem);
} else if (staticContext && constantsFilter.isAccepted(phpElement)) {
} else if ((staticContext || completeAccessPrefix) && constantsFilter.isAccepted(phpElement)) {
TypeConstantElement constant = (TypeConstantElement) phpElement;
TypeConstantItem constantItem = PHPCompletionItem.TypeConstantItem.getItem(constant, request);
TypeConstantItem constantItem = PHPCompletionItem.TypeConstantItem.getItem(constant, request, completeAccessPrefix);
completionResult.add(constantItem);
}
}
Expand Down Expand Up @@ -1299,6 +1322,38 @@ private static boolean isDynamicAccess(CharSequence varName) {
return false;
}

private void autoCompleteClassConstants(final PHPCompletionResult completionResult, final PHPCompletionItem.CompletionRequest request) {
// NETBANS-1855
// complete access prefix i.e. add "self::" to the top of constant names
if (CancelSupport.getDefault().isCancelled()) {
return;
}
final ElementFilter constantsFilter = ElementFilter.allOf(
ElementFilter.forKind(PhpElementKind.TYPE_CONSTANT),
ElementFilter.forName(NameKind.caseInsensitivePrefix(request.prefix)),
ElementFilter.forInstanceOf(TypeConstantElement.class)
);
Model model = request.result.getModel();
Collection<? extends TypeScope> types = ModelUtils.resolveType(model, request.anchor);
TypeElement enclosingType = getEnclosingType(request, types);
for (TypeScope typeScope : types) {
if (CancelSupport.getDefault().isCancelled()) {
return;
}
for (final PhpElement phpElement : request.index.getAccessibleTypeMembers(typeScope, enclosingType)) {
if (CancelSupport.getDefault().isCancelled()) {
return;
}
if (constantsFilter.isAccepted(phpElement)) {
TypeConstantElement constant = (TypeConstantElement) phpElement;
TypeConstantItem constantItem = PHPCompletionItem.TypeConstantItem.getItem(constant, request, true);
completionResult.add(constantItem);
}
}
}

}

private void autoCompleteClassFields(final PHPCompletionResult completionResult, final PHPCompletionItem.CompletionRequest request) {
if (CancelSupport.getDefault().isCancelled()) {
return;
Expand Down Expand Up @@ -1331,6 +1386,7 @@ private void autoCompleteClassFields(final PHPCompletionResult completionResult,
}
}

@CheckForNull
private TypeElement getEnclosingType(CompletionRequest request, Collection<? extends TypeScope> types) {
final EnclosingType enclosingType = findEnclosingType(request.info, lexerToASTOffset(request.result, request.anchor));
final String enclosingTypeName = enclosingType != null ? enclosingType.extractTypeName() : null;
Expand Down Expand Up @@ -1493,6 +1549,8 @@ private void autoCompleteExpression(final PHPCompletionResult completionResult,
completionResult.add(new PHPCompletionItem.ClassScopeKeywordItem(typeName, keyword, request));
}
}
// NETBEANS-1855
autoCompleteClassMembers(completionResult, request, false, true);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.api.annotations.common.StaticResource;
import org.netbeans.api.editor.EditorRegistry;
import org.netbeans.api.editor.completion.Completion;
import org.netbeans.api.lexer.Token;
Expand Down Expand Up @@ -122,6 +123,7 @@
*/
public abstract class PHPCompletionItem implements CompletionProposal {

@StaticResource
private static final String PHP_KEYWORD_ICON = "org/netbeans/modules/php/editor/resources/php16Key.png"; //NOI18N
protected static final ImageIcon KEYWORD_ICON = new ImageIcon(ImageUtilities.loadImage(PHP_KEYWORD_ICON));
final CompletionRequest request;
Expand Down Expand Up @@ -487,20 +489,44 @@ public boolean isSmart() {

public static class MethodElementItem extends FunctionElementItem {

private final boolean completeAccessPrefix;

/**
* @return more than one instance in case if optional parameters exists
*/
static List<MethodElementItem> getItems(final MethodElement methodElement, CompletionRequest request) {
return getItems(methodElement, request, false);
}

/**
* @return more than one instance in case if optional parameters exists
*/
static List<MethodElementItem> getItems(final MethodElement methodElement, CompletionRequest request, boolean completeAccessPrefix) {
final List<MethodElementItem> retval = new ArrayList<>();
List<FunctionElementItem> items = FunctionElementItem.getItems(methodElement, request);
for (FunctionElementItem functionElementItem : items) {
retval.add(new MethodElementItem(functionElementItem));
retval.add(new MethodElementItem(functionElementItem, completeAccessPrefix));
}
return retval;
}

MethodElementItem(FunctionElementItem function) {
this(function, false);
}

MethodElementItem(FunctionElementItem function, boolean completeAccessPrefix) {
super(function.getBaseFunctionElement(), function.request, function.parameters);
this.completeAccessPrefix = completeAccessPrefix;
}

@Override
public String getCustomInsertTemplate() {
String prefix = ""; // NOI18N
if (completeAccessPrefix) {
Set<Modifier> modifiers = getModifiers();
prefix = modifiers.contains(Modifier.STATIC) ? "self::" : "$this->"; // NOI18N
}
return prefix + super.getCustomInsertTemplate();
}
}

Expand Down Expand Up @@ -822,18 +848,24 @@ protected String getTypeName() {

static class FieldItem extends BasicFieldItem {
private final boolean forceDollared;
private final boolean completeAccessPrefix;

public static FieldItem getItem(FieldElement field, CompletionRequest request) {
return getItem(field, request, false);
}

public static FieldItem getItem(FieldElement field, CompletionRequest request, boolean forceDollared) {
return new FieldItem(field, request, forceDollared);
return new FieldItem(field, request, forceDollared, false);
}

public static FieldItem getItem(FieldElement field, CompletionRequest request, boolean forceDollared, boolean completeAccessPrefix) {
return new FieldItem(field, request, forceDollared, completeAccessPrefix);
}

private FieldItem(FieldElement field, CompletionRequest request, boolean forceDollared) {
private FieldItem(FieldElement field, CompletionRequest request, boolean forceDollared, boolean completeAccessPrefix) {
super(field, null, request);
this.forceDollared = forceDollared;
this.completeAccessPrefix = completeAccessPrefix;
}

FieldElement getField() {
Expand Down Expand Up @@ -861,16 +893,33 @@ protected String getTypeName() {
}
return typeName;
}

@Override
public String getCustomInsertTemplate() {
if (completeAccessPrefix) {
Set<Modifier> modifiers = getModifiers();
String prefix = modifiers.contains(Modifier.STATIC) ? "self::" : "$this->"; // NOI18N
return prefix + getName();
}
return super.getCustomInsertTemplate();
}
}

static class TypeConstantItem extends PHPCompletionItem {

private final boolean completeAccessPrefix;

public static TypeConstantItem getItem(TypeConstantElement constant, CompletionRequest request) {
return new TypeConstantItem(constant, request);
return getItem(constant, request, false);
}

private TypeConstantItem(TypeConstantElement constant, CompletionRequest request) {
public static TypeConstantItem getItem(TypeConstantElement constant, CompletionRequest request, boolean completeAccessPrefix) {
return new TypeConstantItem(constant, request, completeAccessPrefix);
}

private TypeConstantItem(TypeConstantElement constant, CompletionRequest request, boolean completeAccessPrefix) {
super(constant, request);
this.completeAccessPrefix = completeAccessPrefix;
}

TypeConstantElement getConstant() {
Expand Down Expand Up @@ -922,6 +971,14 @@ public String getRhsHtml(HtmlFormatter formatter) {
}
return super.getRhsHtml(formatter);
}

@Override
public String getCustomInsertTemplate() {
if (completeAccessPrefix) {
return "self::" + getName(); // NOI18N
}
return super.getCustomInsertTemplate();
}
}

public static class MethodDeclarationItem extends MethodElementItem {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ public static Collection<? extends TypeScope> resolveType(Model model, Assignmen
return retval;
}

@NonNull
public static Collection<? extends TypeScope> resolveType(Model model, int offset) {
VariableScope variableScope = model.getVariableScope(offset);
TypeScope typeScope = getTypeScope(variableScope);
if (typeScope != null) {
return Collections.singletonList(typeScope);
}
return Collections.emptyList();
}

@NonNull
public static Collection<? extends TypeScope> resolveTypeAfterReferenceToken(Model model, TokenSequence<PHPTokenId> tokenSequence,
int offset, boolean specialVariable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ echo "class property: |$this->name\n";
PACKAGE ANS [PUBLIC] null
PACKAGE CNS [PUBLIC] null
CLASS Book [PUBLIC] issue153707.php
METHOD getName() [PUBLIC] Book
METHOD setName($name) [PUBLIC] Book
VARIABLE ? $name [PUBLIC] issue153707.php
VARIABLE ? name [PUBLIC] Book
CONSTANT TEST 'Simon' [PUBLIC] Book
KEYWORD Book $this-> null
KEYWORD parent:: null
KEYWORD self:: null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Code completion result for source line:
echo "class property: $|this->name\n";
(QueryType=COMPLETION, prefixSearch=true, caseSensitive=true)
VARIABLE ? $name [PUBLIC] issue153707.php
VARIABLE ? name [PUBLIC] Book
KEYWORD Book $this-> null
------------------------------------
VARIABLE $GLOBALS PHP Platform
Expand Down
Loading

0 comments on commit 3e50d3f

Please sign in to comment.