in enterprise/micronaut/src/org/netbeans/modules/micronaut/completion/MicronautExpressionLanguageCompletion.java [76:425]
public <T> Result<T> query(int offset, ItemFactory<T> factory) {
int anchorOffset = -1;
List<T> items = new ArrayList<>();
int d = ts.move(offset);
if (d == 0 && ts.movePrevious() || ts.moveNext() || ts.isEmpty()) {
List<String> kws = null;
List<String> builtins = null;
List<? extends Element> elements = null;
List<ConfigurationMetadataProperty> properties = null;
String prefix = "";
boolean wrapProperties = true;
String pkgPrefix = null;
if (tree == null) {
kws = ctx.getScope().getEnclosingMethod() != null ? Arrays.asList("true", "false", "null", "this", "empty", "not") : Arrays.asList("true", "false", "null", "empty", "not");
builtins = Arrays.asList("T", "()", "ctx", "[]", "env", "[]");
elements = ctx.getContextElements();
anchorOffset = startOffset + offset;
} else {
String tokenText = ts.token().text().subSequence(0, offset - ts.offset()).toString().trim();
if (Pattern.matches(PATTERN, tokenText)) {
prefix = tokenText;
offset -= prefix.length();
}
anchorOffset = startOffset + offset;
ExpressionTree.Path path = ExpressionTree.Path.get(tree, offset);
while (path != null && path.getLeaf().getKind() == ExpressionTree.Kind.ERRONEOUS) {
path = path.getParentPath();
}
if (path == null) {
if (offset <= tree.getStartPosition()) {
kws = ctx.getScope().getEnclosingMethod() != null ? Arrays.asList("true", "false", "null", "this", "empty", "not") : Arrays.asList("true", "false", "null", "empty", "not");
builtins = Arrays.asList("T", "()", "ctx", "[]", "env", "[]");
elements = ctx.getContextElements();
} else {
ExpressionTree lastTree = tree;
if (tree.getKind() == ExpressionTree.Kind.ERRONEOUS) {
for (ExpressionTree errTree : ((ExpressionTree.Erroneous) tree).getErrorTrees()) {
if (offset > errTree.getStartPosition()) {
lastTree = errTree;
}
}
}
TypeMirror treeType = lastTree.getTypeMirror(ctx);
switch (treeType.getKind()) {
case BOOLEAN:
TypeMirror rtm = lastTree instanceof ExpressionTree.BinaryExpression
? ((ExpressionTree.BinaryExpression) lastTree).getRightOperand().getTypeMirror(ctx)
: info.getTypes().getNoType(TypeKind.NONE);
switch (rtm.getKind()) {
case INT:
case LONG:
case FLOAT:
case DOUBLE:
kws = Arrays.asList("and", "or", "div", "mod", "instanceof");
break;
default:
kws = Arrays.asList("and", "or", "instanceof");
}
break;
case INT:
case LONG:
case FLOAT:
case DOUBLE:
kws = Arrays.asList("div", "mod", "instanceof");
break;
case DECLARED:
if ("java.lang.String".contentEquals(((TypeElement) ((DeclaredType) treeType).asElement()).getQualifiedName())) {
kws = Arrays.asList("matches", "instanceof");
break;
}
case ARRAY:
kws = Arrays.asList("instanceof");
break;
case NONE:
String prev = prevNonWSTokenText(prefix);
if ("#".equals(prev)) {
elements = ctx.getContextElements();
}
break;
}
}
} else {
TypeMirror lastTreeType = null;
switch (path.getLeaf().getKind()) {
case STRING_LITERAL:
if (path.getParentPath() == null || path.getParentPath().getLeaf().getKind() != ExpressionTree.Kind.ENVIRONMENT_ACCESS) {
break;
}
String value = (String) ((ExpressionTree.Literal) path.getLeaf()).getValue();
if (value.startsWith(tokenText)) {
prefix = tokenText;
anchorOffset = startOffset + ts.offset();
}
wrapProperties = false;
path = path.getParentPath();
case ENVIRONMENT_ACCESS:
ExpressionTree.EnvironmentAccess ea = (ExpressionTree.EnvironmentAccess) path.getLeaf();
ExpressionTree propertyName = ea.getPropertyName();
if (propertyName.getKind() == ExpressionTree.Kind.ERRONEOUS || offset < propertyName.getEndPosition()) {
Project project = FileOwnerQuery.getOwner(info.getFileObject());
if (project != null) {
properties = MicronautConfigProperties.getProperties(project).values().stream().filter(property -> !property.getId().contains("*")).collect(Collectors.toList());
}
}
break;
case BEAN_CONTEXT_ACCESS:
if (offset > ((ExpressionTree.BeanContextAccess) path.getLeaf()).getTypeReference().getEndPosition()) {
break;
}
builtins = Arrays.asList("T", "()");
path = new ExpressionTree.Path(path, ((ExpressionTree.BeanContextAccess) path.getLeaf()).getTypeReference());
case TYPE_REFERENCE:
ExpressionTree.TypeReference tr = (ExpressionTree.TypeReference) path.getLeaf();
int len = offset - tr.getTypeStartPosition();
if (len <= tr.getTypeName().length()) {
pkgPrefix = len >= 0 && tr.getTypeName().length() > len ? tr.getTypeName().substring(0, len) : tr.getTypeName();
PackageElement pkg = info.getElements().getPackageElement(pkgPrefix.isEmpty() ? "java.lang" : pkgPrefix.substring(0, pkgPrefix.length() - 1));
if (pkg != null) {
elements = pkg.getEnclosedElements().stream().filter(e -> e.getKind().isClass() || e.getKind().isInterface()).collect(Collectors.toList());
}
}
break;
case PLUS:
case MINUS:
case MULTIPLY:
case DIVIDE:
case REMAINDER:
case POWER:
case GREATER_THAN:
case LESS_THAN:
case GREATER_THAN_EQUAL:
case LESS_THAN_EQUAL:
case MATCHES:
ExpressionTree.BinaryExpression binary = (ExpressionTree.BinaryExpression) path.getLeaf();
if (nextNonWSTokenCategory(prefix, binary.getRightOperand().getStartPosition()).startsWith("keyword.operator")) {
lastTreeType = binary.getLeftOperand().getTypeMirror(ctx);
} else {
if (ctx.getScope().getEnclosingMethod() != null) {
kws = Arrays.asList("this");
}
builtins = Arrays.asList("T", "()", "ctx", "[]", "env", "[]");
elements = ctx.getContextElements();
}
break;
case EQUAL_TO:
case NOT_EQUAL_TO:
binary = (ExpressionTree.BinaryExpression) path.getLeaf();
if (nextNonWSTokenCategory(prefix, binary.getRightOperand().getStartPosition()).startsWith("keyword.operator")) {
lastTreeType = binary.getLeftOperand().getTypeMirror(ctx);
} else {
kws = ctx.getScope().getEnclosingMethod() != null ? Arrays.asList("null", "this"): Arrays.asList("null");
builtins = Arrays.asList("T", "()", "ctx", "[]", "env", "[]");
elements = ctx.getContextElements();
}
break;
case AND:
case OR:
binary = (ExpressionTree.BinaryExpression) path.getLeaf();
if (nextNonWSTokenCategory(prefix, binary.getRightOperand().getStartPosition()).startsWith("keyword.operator")) {
lastTreeType = binary.getLeftOperand().getTypeMirror(ctx);
break;
}
case NOT:
kws = ctx.getScope().getEnclosingMethod() != null ? Arrays.asList("true", "false", "not", "empty", "this"): Arrays.asList("true", "false", "not", "empty");
builtins = Arrays.asList("T", "()", "ctx", "[]", "env", "[]");
elements = ctx.getContextElements();
break;
case EMPTY:
builtins = Arrays.asList("T", "()", "ctx", "[]", "env", "[]");
elements = ctx.getContextElements();
break;
case INSTANCE_OF:
ExpressionTree.InstanceOf instanceOf = (ExpressionTree.InstanceOf) path.getLeaf();
if (nextNonWSTokenCategory(prefix, instanceOf.getType().getStartPosition()).startsWith("keyword.operator")) {
lastTreeType = instanceOf.getExpression().getTypeMirror(ctx);
} else {
builtins = Arrays.asList("T", "()");
}
break;
case TERNARY:
ExpressionTree.TernaryExpression ternary = (ExpressionTree.TernaryExpression) path.getLeaf();
String next = nextNonWSTokenCategory(prefix, ternary.getTrueExpression().getStartPosition());
if ("keyword.control.ternary.qmark.mexp".equals(next)) {
lastTreeType = ternary.getCondition().getTypeMirror(ctx);
} else {
String prev = prevNonWSTokenText(prefix);
if ("?". equals(prev) || ":".equals(prev)) {
kws = ctx.getScope().getEnclosingMethod() != null ? Arrays.asList("true", "false", "null", "this", "empty", "not") : Arrays.asList("true", "false", "null", "empty", "not");
builtins = Arrays.asList("T", "()", "ctx", "[]", "env", "[]");
elements = ctx.getContextElements();
}
}
break;
case PROPERTY_ACCESS:
String prev = prevNonWSTokenText(prefix);
if (".".equals(prev) || "?.".equals(prev) || "#".equals(prev)) {
ExpressionTree.PropertyAccess pa = (ExpressionTree.PropertyAccess) path.getLeaf();
ExpressionTree callee = pa.getCallee();
if (callee != null) {
TypeMirror pacTM = callee.getTypeMirror(ctx);
if (pacTM.getKind() == TypeKind.DECLARED) {
elements = ((DeclaredType) pacTM).asElement().getEnclosedElements().stream()
.filter(ee -> callee.getKind() != ExpressionTree.Kind.TYPE_REFERENCE || ee.getModifiers().contains(Modifier.STATIC))
.collect(Collectors.toList());
}
} else {
elements = ctx.getContextElements();
}
}
break;
case METHOD_CALL:
prev = prevNonWSTokenText(prefix);
if (".".equals(prev) || "?.".equals(prev) || "#".equals(prev)) {
ExpressionTree.MethodCall methCall = (ExpressionTree.MethodCall) path.getLeaf();
ExpressionTree callee = methCall.getCallee();
if (callee != null) {
TypeMirror methTM = callee.getTypeMirror(ctx);
if (methTM.getKind() == TypeKind.DECLARED) {
elements = ElementFilter.methodsIn(((DeclaredType) methTM).asElement().getEnclosedElements()).stream()
.filter(ee -> callee.getKind() != ExpressionTree.Kind.TYPE_REFERENCE || ee.getModifiers().contains(Modifier.STATIC))
.collect(Collectors.toList());
}
} else {
elements = ctx.getContextElements();
}
} else if ("(".equals(prev) || ",".equals(prev)) {
kws = ctx.getScope().getEnclosingMethod() != null ? Arrays.asList("true", "false", "null", "this", "empty", "not") : Arrays.asList("true", "false", "null", "empty", "not");
builtins = Arrays.asList("T", "()", "ctx", "[]", "env", "[]");
elements = ctx.getContextElements();
}
break;
}
if (lastTreeType != null) {
switch (lastTreeType.getKind()) {
case BOOLEAN:
TypeMirror rtm = info.getTypes().getNoType(TypeKind.NONE);
if (path.getLeaf().getKind() == ExpressionTree.Kind.TERNARY) {
ExpressionTree.TernaryExpression ternary = (ExpressionTree.TernaryExpression) path.getLeaf();
if (ternary.getCondition() instanceof ExpressionTree.BinaryExpression) {
rtm = ((ExpressionTree.BinaryExpression) ternary.getCondition()).getRightOperand().getTypeMirror(ctx);
}
}
switch (rtm.getKind()) {
case INT:
case LONG:
case FLOAT:
case DOUBLE:
kws = Arrays.asList("and", "or", "div", "mod", "instanceof");
break;
default:
kws = Arrays.asList("and", "or", "instanceof");
}
break;
case INT:
case LONG:
case FLOAT:
case DOUBLE:
ExpressionTree.Path parentPath = path.getParentPath();
TypeMirror ptm = parentPath != null && parentPath.getLeaf() instanceof ExpressionTree.BinaryExpression
? parentPath.getLeaf().getTypeMirror(ctx)
: info.getTypes().getNoType(TypeKind.NONE);
if (ptm.getKind() == TypeKind.BOOLEAN) {
kws = Arrays.asList("and", "or", "div", "mod", "instanceof");
} else {
kws = Arrays.asList("div", "mod", "instanceof");
}
break;
case DECLARED:
if ("java.lang.String".contentEquals(((TypeElement) ((DeclaredType) lastTreeType).asElement()).getQualifiedName())) {
kws = Arrays.asList("matches", "instanceof");
break;
}
case ARRAY:
kws = Arrays.asList("instanceof");
break;
}
}
}
}
if (kws != null) {
for (String kw : kws) {
if (Utils.startsWith(kw, prefix)) {
items.add(factory.createKeywordItem(kw, anchorOffset));
}
}
}
if (builtins != null) {
for (int j = 0; j < builtins.size(); j += 2) {
if (Utils.startsWith(builtins.get(j), prefix)) {
items.add(factory.createBuiltInItem(builtins.get(j), builtins.get(j + 1), anchorOffset));
}
}
}
if (elements != null) {
for (Element element : elements) {
String name = element.getSimpleName().toString();
if (element.getKind() == ElementKind.METHOD) {
TypeMirror enclType = element.getEnclosingElement().asType();
if (enclType.getKind() == TypeKind.DECLARED) {
if (Utils.startsWith(name, prefix) && info.getTrees().isAccessible(ctx.getScope(), element, (DeclaredType) enclType)) {
items.add(factory.createJavaElementItem(info, element, anchorOffset));
}
String propertyName = element.getKind() == ElementKind.METHOD ? ExpressionTree.getPropertyName((ExecutableElement) element) : null;
if (Utils.startsWith(propertyName, prefix) && info.getTrees().isAccessible(ctx.getScope(), element, (DeclaredType) enclType)) {
String returnType = Utils.getTypeName(info, ((ExecutableElement)element).getReturnType(), false, false).toString();
items.add(factory.createBeanPropertyItem(propertyName, returnType, anchorOffset));
}
}
} else if (element.getKind() == ElementKind.RECORD_COMPONENT) {
TypeMirror enclType = element.getEnclosingElement().asType();
if (enclType.getKind() == TypeKind.DECLARED && Utils.startsWith(name, prefix) && info.getTrees().isAccessible(ctx.getScope(), element, (DeclaredType) enclType)) {
items.add(factory.createJavaElementItem(info, element, anchorOffset));
}
} else if (element.getKind() == ElementKind.PARAMETER) {
if (Utils.startsWith(name, prefix)) {
items.add(factory.createJavaElementItem(info, element, anchorOffset));
}
} else if (element.getKind().isClass() || element.getKind().isInterface()) {
if (Utils.startsWith(name, prefix) && info.getTrees().isAccessible(ctx.getScope(), (TypeElement) element)) {
items.add(factory.createJavaElementItem(info, element, anchorOffset));
}
}
}
}
if (properties != null) {
for (ConfigurationMetadataProperty property : properties) {
if (Utils.startsWith(property.getId(), prefix)) {
items.add(factory.createEnvPropertyItem(wrapProperties ? "'" + property.getId() + "'" : property.getId(), new MicronautConfigDocumentation(property).getText(), anchorOffset, startOffset + offset));
}
}
}
if (pkgPrefix != null) {
Set<String> seenPkgs = new HashSet<>();
ModuleElement module = info.getElements().getModuleOf(ctx.getScope().getEnclosingClass());
for (String pkgName : info.getClasspathInfo().getClassIndex().getPackageNames(pkgPrefix, false, EnumSet.allOf(ClassIndex.SearchScope.class))) {
if (Utils.startsWith(pkgName, pkgPrefix + prefix) && (module != null ? info.getElements().getPackageElement(module, pkgName) : info.getElements().getPackageElement(pkgName)) != null) {
String name = pkgName.substring(pkgPrefix.length());
int idx = name.indexOf('.');
if (idx > 0) {
name = name.substring(0, idx);
}
if (seenPkgs.add(name)) {
items.add(factory.createPackageItem(name, anchorOffset));
}
}
}
}
}
return new Result<>(items, anchorOffset);
}