Skip to content
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1869,9 +1869,13 @@ private void insideMemberSelect(Env env) throws IOException {
if (el != null && (el.getKind().isClass() || el.getKind().isInterface())) {
if (parent.getKind() == Tree.Kind.NEW_CLASS && ((NewClassTree) parent).getIdentifier() == fa && prefix != null) {
String typeName = controller.getElementUtilities().getElementName(el, true) + "." + prefix; //NOI18N
TypeMirror tm = controller.getTreeUtilities().parseType(typeName, env.getScope().getEnclosingClass());
TypeMirror tm = controller.getTreeUtilities().parseType(typeName, env.getScope());
if (tm != null && tm.getKind() == TypeKind.DECLARED) {
addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, false, switchItemAdder);
TypeElement te = (TypeElement) ((DeclaredType) tm).asElement();
addMembers(env, tm, te, EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, false, switchItemAdder);
if (shouldExcludeTypeInNewClass(te, env)) {
env.addToExcludes(te);
}
}
}
}
Expand Down Expand Up @@ -1917,9 +1921,13 @@ private void insideMemberSelect(Env env) throws IOException {
if (el != null && el.getKind() == PACKAGE) {
if (parent.getKind() == Tree.Kind.NEW_CLASS && ((NewClassTree) parent).getIdentifier() == fa && prefix != null) {
String typeName = controller.getElementUtilities().getElementName(el, true) + "." + prefix; //NOI18N
TypeMirror tm = controller.getTreeUtilities().parseType(typeName, env.getScope().getEnclosingClass());
TypeMirror tm = controller.getTreeUtilities().parseType(typeName, env.getScope());
if (tm != null && tm.getKind() == TypeKind.DECLARED) {
addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, false, switchItemAdder);
TypeElement te = (TypeElement) ((DeclaredType) tm).asElement();
addMembers(env, tm, te, EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, false, switchItemAdder);
if (shouldExcludeTypeInNewClass(te, env)) {
env.addToExcludes(te);
}
}
}
if (exs != null && !exs.isEmpty()) {
Expand Down Expand Up @@ -2051,7 +2059,7 @@ private void insideMethodInvocation(Env env) throws IOException {
if (path.getParentPath().getLeaf().getKind() == Kind.CONSTANT_CASE_LABEL) {
CompilationController controller = env.getController();
controller.toPhase(Phase.RESOLVED);
TypeMirror tm = controller.getTreeUtilities().parseType(fullName(mi.getMethodSelect()), env.getScope().getEnclosingClass());
TypeMirror tm = controller.getTreeUtilities().parseType(fullName(mi.getMethodSelect()), env.getScope());
if (tm != null && tm.getKind() == TypeKind.DECLARED) {
TypeElement te = (TypeElement) ((DeclaredType) tm).asElement();
if (te.getKind() == RECORD) {
Expand All @@ -2062,7 +2070,7 @@ private void insideMethodInvocation(Env env) throws IOException {
if (ts != null && (ts.token().id() == JavaTokenId.LPAREN || ts.token().id() == JavaTokenId.COMMA)) {
if (componentType.getKind() == TypeKind.DECLARED) {
if (prefix != null) {
TypeMirror ptm = controller.getTreeUtilities().parseType(prefix, env.getScope().getEnclosingClass());
TypeMirror ptm = controller.getTreeUtilities().parseType(prefix, env.getScope());
if (ptm != null && ptm.getKind() == TypeKind.DECLARED) {
TypeElement pte = (TypeElement) ((DeclaredType) ptm).asElement();
if (pte != null && pte.getKind() == RECORD) {
Expand Down Expand Up @@ -2135,12 +2143,11 @@ private void insideNewClass(Env env) throws IOException {
? controller.getTypes().getDeclaredType(tel) : null;
TypeElement toExclude = null;
if (nc.getIdentifier().getKind() == Tree.Kind.IDENTIFIER && prefix != null) {
TypeMirror tm = controller.getTreeUtilities().parseType(prefix, env.getScope().getEnclosingClass());
TypeMirror tm = controller.getTreeUtilities().parseType(prefix, env.getScope());
if (tm != null && tm.getKind() == TypeKind.DECLARED) {
TypeElement te = (TypeElement) ((DeclaredType) tm).asElement();
addMembers(env, tm, te, EnumSet.of(CONSTRUCTOR), base, false, true, false);
if ((te.getTypeParameters().isEmpty() || SourceVersion.RELEASE_5.compareTo(controller.getSourceVersion()) > 0)
&& !hasAccessibleInnerClassConstructor(te, env.getScope(), controller.getTrees())) {
if (shouldExcludeTypeInNewClass(te, env)) {
toExclude = te;
}
}
Expand Down Expand Up @@ -2227,6 +2234,13 @@ private void insideNewClass(Env env) throws IOException {
}
}

private boolean shouldExcludeTypeInNewClass(TypeElement te, Env env) throws IOException {
CompilationController controller = env.getController();

return (te.getTypeParameters().isEmpty() || SourceVersion.RELEASE_5.compareTo(controller.getSourceVersion()) > 0)
&& !hasAccessibleInnerClassConstructor(te, env.getScope(), controller.getTrees());
}

private void insideTry(Env env) throws IOException {
CompilationController controller = env.getController();
TokenSequence<JavaTokenId> last = findLastNonWhitespaceToken(env, env.getPath().getLeaf(), env.getOffset());
Expand Down Expand Up @@ -2550,7 +2564,7 @@ private void insideCase(Env env) throws IOException {
} else {
if (env.getController().getSourceVersion().compareTo(RELEASE_21) >= 0) {
if (prefix != null) {
TypeMirror ptm = controller.getTreeUtilities().parseType(prefix, env.getScope().getEnclosingClass());
TypeMirror ptm = controller.getTreeUtilities().parseType(prefix, env.getScope());
if (ptm != null && ptm.getKind() == TypeKind.DECLARED) {
TypeElement pte = (TypeElement) ((DeclaredType) ptm).asElement();
if (pte != null && pte.getKind() == RECORD) {
Expand Down Expand Up @@ -2754,7 +2768,7 @@ private void insideTypeCheck(Env env) throws IOException {
TokenSequence<JavaTokenId> ts = findLastNonWhitespaceToken(env, iot, env.getOffset());
if (ts != null && ts.token().id() == JavaTokenId.INSTANCEOF) {
if (prefix != null && controller.getSourceVersion().compareTo(RELEASE_21) >= 0) {
TypeMirror tm = controller.getTreeUtilities().parseType(prefix, env.getScope().getEnclosingClass());
TypeMirror tm = controller.getTreeUtilities().parseType(prefix, env.getScope());
if (tm != null && tm.getKind() == TypeKind.DECLARED) {
TypeElement te = (TypeElement) ((DeclaredType) tm).asElement();
if (te != null && te.getKind() == RECORD) {
Expand Down Expand Up @@ -3485,7 +3499,7 @@ private void insideDeconstructionRecordPattern(final Env env) throws IOException
TypeMirror componentType = recordComponents.get(size - 1).getAccessor().getReturnType();
if (componentType.getKind() == TypeKind.DECLARED) {
if (prefix != null) {
TypeMirror ptm = controller.getTreeUtilities().parseType(prefix, env.getScope().getEnclosingClass());
TypeMirror ptm = controller.getTreeUtilities().parseType(prefix, env.getScope());
if (ptm != null && ptm.getKind() == TypeKind.DECLARED) {
TypeElement pte = (TypeElement) ((DeclaredType) ptm).asElement();
if (pte != null && pte.getKind() == RECORD) {
Expand Down Expand Up @@ -4088,6 +4102,9 @@ private void addMembers(final Env env, final TypeMirror type, final Element elem
ElementUtilities.ElementAcceptor acceptor = new ElementUtilities.ElementAcceptor() {
@Override
public boolean accept(Element e, TypeMirror t) {
if (!(env.getExcludes() == null || !env.getExcludes().contains(e))) {
return false; //TODO: correct?
}
switch (simplifyElementKind(e.getKind())) {
case FIELD:
if (!startsWith(env, e.getSimpleName().toString())) {
Expand Down Expand Up @@ -4889,6 +4906,7 @@ private void addAttributeValues(Env env, Element element, AnnotationMirror annot
CharSequence fqn = ((TypeElement) ((DeclaredType) type).asElement()).getQualifiedName();
if (JAVA_LANG_CLASS.contentEquals(fqn)) {
String name = value.endsWith(".class") ? value.substring(0, value.length() - 6) : value; //NOI18N
//NOTE: for annotations, not sure if keeping this is not more sensible. Can annotations realistically use local classes as attribute values?
TypeMirror tm = tu.parseType(name, eu.outermostTypeElement(element));
typeElement = tm != null && tm.getKind() == TypeKind.DECLARED ? (TypeElement) ((DeclaredType) tm).asElement() : null;
if (typeElement != null && startsWith(env, typeElement.getSimpleName().toString())) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Local
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Local()
Local(int i)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Local(int i)
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,61 @@ public void testRecordPatternCompletion_5() throws Exception {
performTest("RecordPattern", 1107, null, "AutoCompletion_RecordPattern_5.pass", SOURCE_LEVEL);
}

public void testRecordPatternLocalClass1() throws Exception {
performTest("Method", 935,
"""
record Local(int i) {}
Object o = null;
switch (o) {
case Loc""",
"LocalClass.pass",
SOURCE_LEVEL);
}

public void testRecordPatternLocalClass2() throws Exception {
performTest("Method", 935,
"""
record Local(int i) {}
Object o = null;
switch (o) {
case Local""",
"LocalRecordPattern.pass",
SOURCE_LEVEL);
}

public void testRecordPatternLocalClass3() throws Exception {
performTest("Method", 935,
"""
record Local(int i) {}
Object o = null;
boolean b = o instanceof Local""",
"LocalRecordPattern.pass",
SOURCE_LEVEL);
}

public void testRecordPatternLocalClass4() throws Exception {
performTest("Method", 935,
"""
record Local(int i) {}
record Box(Local l) {}
Object o = null;
boolean b = o instanceof Box(Local""",
"LocalRecordPattern.pass",
SOURCE_LEVEL);
}

public void testRecordPatternLocalClass5() throws Exception {
performTest("Method", 935,
"""
record Local(int i) {}
record Box(Local l) {}
Object o = null;
switch (o) {
case Box(Local""",
"LocalRecordPattern.pass",
SOURCE_LEVEL);
}

public void testCaseLabels_1() throws Exception {
performTest("SwitchPatternMatching", 971, null, "AutoCompletion_CaseLabels_PatternMatchingSwitch_1.pass", SOURCE_LEVEL);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -958,4 +958,35 @@ public void testGenericMethod1() throws Exception {
public void testGenericMethod2() throws Exception {
performTest("GenericMethodInvocation", 1231, "run2(\"\", arg", "GenericMethodInvocation2.pass");
}

public void testLocalClassConstructor1() throws Exception {
performTest("Method", 935,
"""
class Local {
Local() {}
Local(int i) {}
}
new Local""",
"LocalClassConstructor.pass");
}

public void testLocalClassConstructor2() throws Exception {
performTest("Method", 935,
"""
class LocalOuter {
static class Local {
Local() {}
Local(int i) {}
}
}
new LocalOuter.Local""",
"LocalClassConstructor.pass");
}

public void testConstructorFromPackage() throws Exception {
performTest("Method", 935,
"""
new java.lang.String""",
"stringConstructors.pass");
}
}
15 changes: 14 additions & 1 deletion java/java.source.base/apichanges.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,25 @@
under the License.
-->
<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../../nbbuild/javadoctools/apichanges.dtd">
<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.1//EN" "../../nbbuild/javadoctools/apichanges-1.1.dtd">
<apichanges>
<apidefs>
<apidef name="javasource_base">Java Source API</apidef>
</apidefs>
<changes>
<change id="parseTypeScope">
<api name="javasource_base" />
<summary>Adding TreeUtilities.parseType(String, Scope) method overload</summary>
<version major="1" minor="2.84"/>
<date day="17" month="3" year="2026"/>
<author login="jlahoda"/>
<compatibility addition="yes" binary="compatible" source="compatible"/>
<description>
Adding TreeUtilities.parseType(String, Scope) method overload
to support more exact type parsing.
</description>
<class name="TreeUtilities" package="org.netbeans.api.java.source"/>
</change>
<change id="ModuleImports">
<api name="javasource_base" />
<summary>API Support for module imports</summary>
Expand Down
2 changes: 1 addition & 1 deletion java/java.source.base/nbproject/project.properties
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ javadoc.name=Java Source Base
javadoc.title=Java Source Base
javadoc.arch=${basedir}/arch.xml
javadoc.apichanges=${basedir}/apichanges.xml
spec.version.base=2.83.0
spec.version.base=2.84.0
test.qa-functional.cp.extra=${refactoring.java.dir}/modules/ext/nb-javac-api.jar
test.unit.run.cp.extra=${o.n.core.dir}/core/core.jar:\
${o.n.core.dir}/lib/boot.jar:\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,26 @@ public TypeMirror parseType(String expr, TypeElement scope) {
}
}

/**Parses given type in given context.
*
* @param expr type specification
* @param scope in which simple names should be resolved
* @return parsed {@link TypeMirror} or null if the given specification cannot be parsed
* @since 2.84
*/
public TypeMirror parseType(String expr, Scope scope) {
Env<AttrContext> env = getEnv(scope);
if (scope instanceof NBScope && ((NBScope)scope).areAccessibilityChecksDisabled()) {
NBResolve.instance(info.impl.getJavacTask().getContext()).disableAccessibilityChecks();
}
try {
Tree type = parseType(expr);
return attributeTree(info.impl.getJavacTask(), env.toplevel, (JCTree) type, scope, true, new ArrayList<>());
} finally {
NBResolve.instance(info.impl.getJavacTask().getContext()).restoreAccessbilityChecks();
}
}

/**Parses given type in given context.
*
* @param expr type specification
Expand Down Expand Up @@ -922,7 +942,7 @@ public TypeMirror attributeTree(Tree tree, Scope scope) {
NBResolve.instance(info.impl.getJavacTask().getContext()).disableAccessibilityChecks();
}
try {
return attributeTree(info.impl.getJavacTask(), env.toplevel, (JCTree) tree, scope, new ArrayList<>());
return attributeTree(info.impl.getJavacTask(), env.toplevel, (JCTree) tree, scope, false, new ArrayList<>());
} finally {
NBResolve.instance(info.impl.getJavacTask().getContext()).restoreAccessbilityChecks();
}
Expand All @@ -949,7 +969,7 @@ public TypeMirror reattributeTree(Tree tree, Scope scope) {
NBResolve.instance(info.impl.getJavacTask().getContext()).disableAccessibilityChecks();
}
try {
return attributeTree(info.impl.getJavacTask(), env.toplevel, (JCTree)tree, scope, new ArrayList<>());
return attributeTree(info.impl.getJavacTask(), env.toplevel, (JCTree)tree, scope, false, new ArrayList<>());
} finally {
NBResolve.instance(info.impl.getJavacTask().getContext()).restoreAccessbilityChecks();
}
Expand All @@ -968,7 +988,7 @@ public Scope reattributeTreeTo(Tree tree, Scope scope, Tree to) {
}

//from org/netbeans/modules/java/hints/spiimpl/Utilities.java:
private static TypeMirror attributeTree(JavacTaskImpl jti, CompilationUnitTree cut, Tree tree, Scope scope, final List<Diagnostic<? extends JavaFileObject>> errors) {
private static TypeMirror attributeTree(JavacTaskImpl jti, CompilationUnitTree cut, Tree tree, Scope scope, boolean attributeAsType, final List<Diagnostic<? extends JavaFileObject>> errors) {
Log log = Log.instance(jti.getContext());
JavaFileObject prev = log.useSource(new DummyJFO());
Log.DiagnosticHandler discardHandler = log.new DiscardDiagnosticHandler() {
Expand All @@ -986,6 +1006,9 @@ public void reportReady(JCDiagnostic diag) {
try {
Attr attr = Attr.instance(jti.getContext());
Env<AttrContext> env = getEnv(scope);
if (attributeAsType) {
return attr.attribType((JCTree) tree, env);
}
if (tree instanceof JCExpression)
return attr.attribExpr((JCTree) tree,env, Type.noType);
return attr.attribStat((JCTree) tree,env);
Expand Down
Loading
Loading