diff options
author | Stephan Herrmann | 2021-08-12 11:43:40 +0000 |
---|---|---|
committer | Stephan Herrmann | 2021-08-12 14:15:50 +0000 |
commit | 43b3339093473b2e9632f287b07b19f344c846fe (patch) | |
tree | d0591a7a0c0c754c2e7ee2eaf5b98a0bef7ed6b3 | |
parent | e16e7d340a485767e3f2c423a687bef97afd2327 (diff) | |
download | eclipse.jdt.core-43b3339093473b2e9632f287b07b19f344c846fe.tar.gz eclipse.jdt.core-43b3339093473b2e9632f287b07b19f344c846fe.tar.xz eclipse.jdt.core-43b3339093473b2e9632f287b07b19f344c846fe.zip |
Bug 574978 - [content assist] keywords are not proposed inside blockI20210813-1800I20210812-1800
with subsequent statement
Change-Id: I19d85a5609a6b879c7692af609e727df511aaf29
Reviewed-on: https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/183953
Tested-by: JDT Bot <jdt-bot@eclipse.org>
Reviewed-by: Stephan Herrmann <stephan.herrmann@berlin.de>
4 files changed, 135 insertions, 112 deletions
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java index 2262a2066e..44b0f49356 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java @@ -922,6 +922,7 @@ public void testBug574338_from574215c14() throws CoreException { int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner); assertResults( + "for[KEYWORD]{for, null, null, for, null, 49}\n" + "fooo[LOCAL_VARIABLE_REF]{fooo, null, Ljava.lang.String;, fooo, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_UNQUALIFIED + R_NON_RESTRICTED) + "}", requestor.getResults()); } finally { diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java index 920bfebc8a..b8dc2c669b 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java @@ -3907,8 +3907,15 @@ public final class CompletionEngine if (receiverType != null && receiverType.isValidBinding()) { findVariablesAndMethods(this.completionToken, scope, FakeInvocationSite, scope, false, false); } + // ... or a keyword (possibly starting a new statement): + if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { + if (this.completionToken != null && this.completionToken.length != 0) { + findKeywords(this.completionToken, singleRef.possibleKeywords, false, false); + } else { + findTrueOrFalseKeywords(singleRef.possibleKeywords); + } + } } - } private void completionOnProvidesInterfacesSingleTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope) { diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java index 4dc9c77d81..27eceba93f 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnSingleTypeReference.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2012 IBM Corporation and others. + * Copyright (c) 2000, 2021 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -40,6 +40,8 @@ private int kind = K_TYPE; public boolean isCompletionNode; public boolean isConstructorType; public CompletionOnFieldType fieldTypeCompletionNode; +public char[][] possibleKeywords; +public boolean canBeExplicitConstructor; public CompletionOnSingleTypeReference(char[] source, long pos) { this(source, pos, K_TYPE); @@ -49,6 +51,11 @@ public CompletionOnSingleTypeReference(char[] source, long pos, int kind) { this.isCompletionNode = true; this.kind = kind; } +public CompletionOnSingleTypeReference(char[] assistName, long position, char[][] keywords, boolean canBeSuperCall) { + this(assistName, position); + this.possibleKeywords = keywords; + this.canBeExplicitConstructor = canBeSuperCall; +} @Override public void aboutToResolve(Scope scope) { getTypeBinding(scope); diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java index ff22726742..f49c544041 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java @@ -18,6 +18,8 @@ *******************************************************************************/ package org.eclipse.jdt.internal.codeassist.complete; +import java.util.ArrayList; + /* * Parser able to build specific completion parse nodes, given a cursorLocation. * @@ -29,6 +31,7 @@ package org.eclipse.jdt.internal.codeassist.complete; */ import java.util.HashSet; +import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.compiler.CharOperation; @@ -5130,120 +5133,123 @@ public NameReference createSingleAssistNameReference(char[] assistName, long pos && topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == SWITCH) { return new CompletionOnKeyword3(assistName, position, new char[][]{Keywords.CASE, Keywords.DEFAULT}, false); } else { - char[][] keywords = new char[Keywords.COUNT][]; - int count = 0; + List<char[]> keywordsList = new ArrayList<>(Keywords.COUNT); + canBeExplicitConstructorCall = computeKeywords(kind, keywordsList); + char[][] keywords = keywordsList.toArray(char[][]::new); + return new CompletionOnSingleNameReference(assistName, position, keywords, canBeExplicitConstructorCall, isInsideAttributeValue()); + } + } +} +boolean computeKeywords(int kind, List<char[]> keywords) { + boolean canBeExplicitConstructorCall = false; - if((this.lastModifiers & ClassFileConstants.AccStatic) == 0) { - keywords[count++]= Keywords.SUPER; - keywords[count++]= Keywords.THIS; - } - keywords[count++]= Keywords.NEW; - // https://bugs.eclipse.org/bugs/show_bug.cgi?id=269493: Keywords are not proposed in a for - // loop without block. Completion while at K_CONTROL_STATEMENT_DELIMITER case needs to handled - // similar to the K_BLOCK_DELIMITER with minor differences. - if(kind == K_BLOCK_DELIMITER || kind == K_CONTROL_STATEMENT_DELIMITER || kind == K_LAMBDA_EXPRESSION_DELIMITER - || kind == K_SWITCH_EXPRESSION_DELIMITTER) { - if(this.canBeExplicitConstructor == YES) { - canBeExplicitConstructorCall = true; - } - if (this.options.complianceLevel >= ClassFileConstants.JDK1_4) { - keywords[count++]= Keywords.ASSERT; - } - keywords[count++]= Keywords.DO; - keywords[count++]= Keywords.FOR; - keywords[count++]= Keywords.IF; - keywords[count++]= Keywords.RETURN; - keywords[count++]= Keywords.SWITCH; - keywords[count++]= Keywords.SYNCHRONIZED; - keywords[count++]= Keywords.THROW; - keywords[count++]= Keywords.TRY; - keywords[count++]= Keywords.WHILE; - - keywords[count++]= Keywords.FINAL; - keywords[count++]= Keywords.CLASS; - if (this.options.complianceLevel >= ClassFileConstants.JDK10) { - keywords[count++]= Keywords.VAR; - } - if (this.options.complianceLevel >= ClassFileConstants.JDK16) { - keywords[count++]= Keywords.INTERFACE; - keywords[count++]= Keywords.ENUM; - } + if((this.lastModifiers & ClassFileConstants.AccStatic) == 0) { + keywords.add(Keywords.SUPER); + keywords.add(Keywords.THIS); + } + keywords.add(Keywords.NEW); + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=269493: Keywords are not proposed in a for + // loop without block. Completion while at K_CONTROL_STATEMENT_DELIMITER case needs to handled + // similar to the K_BLOCK_DELIMITER with minor differences. + if(kind == K_BLOCK_DELIMITER || kind == K_CONTROL_STATEMENT_DELIMITER || kind == K_LAMBDA_EXPRESSION_DELIMITER + || kind == K_SWITCH_EXPRESSION_DELIMITTER) { + if(this.canBeExplicitConstructor == YES) { + canBeExplicitConstructorCall = true; + } + if (this.options.complianceLevel >= ClassFileConstants.JDK1_4) { + keywords.add(Keywords.ASSERT); + } + keywords.add(Keywords.DO); + keywords.add(Keywords.FOR); + keywords.add(Keywords.IF); + keywords.add(Keywords.RETURN); + keywords.add(Keywords.SWITCH); + keywords.add(Keywords.SYNCHRONIZED); + keywords.add(Keywords.THROW); + keywords.add(Keywords.TRY); + keywords.add(Keywords.WHILE); - if(this.previousKind == K_BLOCK_DELIMITER) { - switch (this.previousInfo) { - case IF : - keywords[count++]= Keywords.ELSE; - break; - case CATCH : - keywords[count++]= Keywords.CATCH; - keywords[count++]= Keywords.FINALLY; - break; - } - } else if(this.previousKind == K_CONTROL_STATEMENT_DELIMITER && this.previousInfo == IF) { - keywords[count++]= Keywords.ELSE; - } - if(isInsideLoop()) { - keywords[count++]= Keywords.CONTINUE; - } - if(isInsideBreakable()) { - keywords[count++]= Keywords.BREAK; - } - if(isInsideSwitch()) { - keywords[count++]= Keywords.YIELD; - } - } else if (kind == K_BETWEEN_FOR_AND_RIGHT_PAREN) { - if (this.options.complianceLevel >= ClassFileConstants.JDK10) { - keywords[count++]= Keywords.VAR; - } - } else if(kind != K_BETWEEN_CASE_AND_COLON && kind != K_BETWEEN_DEFAULT_AND_COLON) { - if (kind == K_LOCAL_INITIALIZER_DELIMITER && this.options.complianceLevel >= ClassFileConstants.JDK11) { - keywords[count++]= Keywords.VAR; - } - if (kind == K_SELECTOR_QUALIFIER && this.options.complianceLevel >= ClassFileConstants.JDK12) { - keywords[count++] = Keywords.SWITCH; - } - keywords[count++]= Keywords.TRUE; - keywords[count++]= Keywords.FALSE; - keywords[count++]= Keywords.NULL; - if (kind == K_YIELD_KEYWORD) { - keywords[count++]= Keywords.YIELD; - } - if(kind == K_SWITCH_LABEL) { - if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) != DEFAULT) { - keywords[count++]= Keywords.DEFAULT; - } - keywords[count++]= Keywords.BREAK; - keywords[count++]= Keywords.CASE; - keywords[count++]= Keywords.YIELD; - if (this.options.complianceLevel >= ClassFileConstants.JDK1_4) { - keywords[count++]= Keywords.ASSERT; - } - keywords[count++]= Keywords.DO; - keywords[count++]= Keywords.FOR; - keywords[count++]= Keywords.IF; - keywords[count++]= Keywords.RETURN; - keywords[count++]= Keywords.SWITCH; - keywords[count++]= Keywords.SYNCHRONIZED; - keywords[count++]= Keywords.THROW; - keywords[count++]= Keywords.TRY; - keywords[count++]= Keywords.WHILE; - - keywords[count++]= Keywords.FINAL; - keywords[count++]= Keywords.CLASS; - - if (this.options.complianceLevel >= ClassFileConstants.JDK10) { - keywords[count++]= Keywords.VAR; - } - if(isInsideLoop()) { - keywords[count++]= Keywords.CONTINUE; - } - } - } - System.arraycopy(keywords, 0 , keywords = new char[count][], 0, count); + keywords.add(Keywords.FINAL); + keywords.add(Keywords.CLASS); + if (this.options.complianceLevel >= ClassFileConstants.JDK10) { + keywords.add(Keywords.VAR); + } + if (this.options.complianceLevel >= ClassFileConstants.JDK16) { + keywords.add(Keywords.INTERFACE); + keywords.add(Keywords.ENUM); + } - return new CompletionOnSingleNameReference(assistName, position, keywords, canBeExplicitConstructorCall, isInsideAttributeValue()); + if(this.previousKind == K_BLOCK_DELIMITER) { + switch (this.previousInfo) { + case IF : + keywords.add(Keywords.ELSE); + break; + case CATCH : + keywords.add(Keywords.CATCH); + keywords.add(Keywords.FINALLY); + break; + } + } else if(this.previousKind == K_CONTROL_STATEMENT_DELIMITER && this.previousInfo == IF) { + keywords.add(Keywords.ELSE); + } + if(isInsideLoop()) { + keywords.add(Keywords.CONTINUE); + } + if(isInsideBreakable()) { + keywords.add(Keywords.BREAK); + } + if(isInsideSwitch()) { + keywords.add(Keywords.YIELD); + } + } else if (kind == K_BETWEEN_FOR_AND_RIGHT_PAREN) { + if (this.options.complianceLevel >= ClassFileConstants.JDK10) { + keywords.add(Keywords.VAR); + } + } else if(kind != K_BETWEEN_CASE_AND_COLON && kind != K_BETWEEN_DEFAULT_AND_COLON) { + if (kind == K_LOCAL_INITIALIZER_DELIMITER && this.options.complianceLevel >= ClassFileConstants.JDK11) { + keywords.add(Keywords.VAR); + } + if (kind == K_SELECTOR_QUALIFIER && this.options.complianceLevel >= ClassFileConstants.JDK12) { + keywords.add(Keywords.SWITCH); + } + keywords.add(Keywords.TRUE); + keywords.add(Keywords.FALSE); + keywords.add(Keywords.NULL); + if (kind == K_YIELD_KEYWORD) { + keywords.add(Keywords.YIELD); + } + if(kind == K_SWITCH_LABEL) { + if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) != DEFAULT) { + keywords.add(Keywords.DEFAULT); + } + keywords.add(Keywords.BREAK); + keywords.add(Keywords.CASE); + keywords.add(Keywords.YIELD); + if (this.options.complianceLevel >= ClassFileConstants.JDK1_4) { + keywords.add(Keywords.ASSERT); + } + keywords.add(Keywords.DO); + keywords.add(Keywords.FOR); + keywords.add(Keywords.IF); + keywords.add(Keywords.RETURN); + keywords.add(Keywords.SWITCH); + keywords.add(Keywords.SYNCHRONIZED); + keywords.add(Keywords.THROW); + keywords.add(Keywords.TRY); + keywords.add(Keywords.WHILE); + + keywords.add(Keywords.FINAL); + keywords.add(Keywords.CLASS); + + if (this.options.complianceLevel >= ClassFileConstants.JDK10) { + keywords.add(Keywords.VAR); + } + if(isInsideLoop()) { + keywords.add(Keywords.CONTINUE); + } } } + return canBeExplicitConstructorCall; } private TypeReference checkAndCreateModuleSingleAssistTypeReference(char[] assistName, long position) { if (isInUsesStatement()) return new CompletionOnUsesSingleTypeReference(assistName, position); @@ -5251,7 +5257,9 @@ private TypeReference checkAndCreateModuleSingleAssistTypeReference(char[] assis if (isAfterWithClause()) return new CompletionOnProvidesImplementationsSingleTypeReference(assistName, position); return new CompletionOnProvidesInterfacesSingleTypeReference(assistName, position); } - return new CompletionOnSingleTypeReference(assistName,position); + List<char[]> keywords = new ArrayList<>(Keywords.COUNT); + boolean canBeCtorCall = computeKeywords(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER), keywords); + return new CompletionOnSingleTypeReference(assistName,position, keywords.toArray(char[][]::new), canBeCtorCall); } @Override public TypeReference createSingleAssistTypeReference(char[] assistName, long position) { |