diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fe7b40e1..6e8aa6e40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,12 @@ # Changelog -## [Unreleased] -* Improved support for anonymous structures (#1131) -* Fixed incorrect symbol resolve (#968) -* Support for special interface ArrayAccess (#957) -* Added QuickNavigateInfo (ctrl+hover over symbols) -* Prevent automatic asterisk insert for haxedoc +## 1.4.11 +* Added: better support for anonymous structures (#1131) +* Bugfix: Fixed incorrect symbol resolve (#968) +* Added: Support for special interface ArrayAccess (#957) +* Added: Resolve type from ExprOf when used with reification +* Added: QuickNavigateInfo (ctrl+hover over symbols) +* Bugfix: Prevent automatic asterisk insert for HaxeDoc ## 1.4.10 diff --git a/gradle.properties b/gradle.properties index 582b1bbb3..4d4f07288 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ pluginName = Haxe Toolkit Support pluginRepositoryUrl = https://github.com/HaxeFoundation/intellij-haxe # SemVer format -> https://semver.org -pluginVersion = 1.4.11 (beta 1) +pluginVersion = 1.4.11 # IntelliJ Platform Properties -> https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties platformType = IU diff --git a/src/main/java/com/intellij/plugins/haxe/lang/parser/haxe.bnf b/src/main/java/com/intellij/plugins/haxe/lang/parser/haxe.bnf index 5bf18e79f..477f89a29 100644 --- a/src/main/java/com/intellij/plugins/haxe/lang/parser/haxe.bnf +++ b/src/main/java/com/intellij/plugins/haxe/lang/parser/haxe.bnf @@ -236,7 +236,7 @@ questionOperator ::= <> { extends=operator } suffixOperator ::= '!' { extends=operator } // KFROM and KTO are only keywords for abstracts and can be used as identifiers elsewhere in the code (KNEVER is only used for getters/setters) -identifier ::= ID | MACRO_ID | KFROM | KTO | KNEVER +identifier ::= ID | KFROM | KTO | KNEVER | macroIdentifierReification | MACRO_ID {mixin="com.intellij.plugins.haxe.lang.psi.impl.HaxeIdentifierPsiMixinImpl" implements="com.intellij.plugins.haxe.lang.psi.HaxeIdentifierPsiMixin" name="identifier"} thisExpression ::= 'this' diff --git a/src/main/java/com/intellij/plugins/haxe/lang/psi/HaxeResolver.java b/src/main/java/com/intellij/plugins/haxe/lang/psi/HaxeResolver.java index 10840b99a..fe5dbaf03 100644 --- a/src/main/java/com/intellij/plugins/haxe/lang/psi/HaxeResolver.java +++ b/src/main/java/com/intellij/plugins/haxe/lang/psi/HaxeResolver.java @@ -178,6 +178,7 @@ private List doResolveInner(@NotNull HaxeReference referen if (result == null) result = checkIsSuperExpression(reference); if (result == null) result = checkIsClassName(reference); if (result == null) result = checkMemberReference(reference); + if (result == null) result = checkMacroIdentifier(reference); if (result == null) result = checkIsChain(reference); if (result == null) result = checkIsAccessor(reference); if (result == null) result = checkIsSwitchVar(reference); @@ -219,6 +220,20 @@ private List doResolveInner(@NotNull HaxeReference referen return result == null ? EMPTY_LIST : result; } + private List checkMacroIdentifier(HaxeReference reference) { + @NotNull PsiElement[] children = reference.getChildren(); + if (children.length == 1) { + if (children[0] instanceof HaxeIdentifier identifier) { + PsiElement macroId = identifier.getMacroId(); + if (macroId != null) { + String substring = macroId.getText().substring(1); + return checkByTreeWalk(reference, substring); + } + } + } + return null; + } + private List checkMemberReference(HaxeReference reference) { final HaxeReference leftReference = HaxeResolveUtil.getLeftReference(reference); // check if reference is to a member in class or abstract @@ -523,6 +538,13 @@ private List checkByTreeWalk(HaxeReference reference) { LogResolution(reference, "via tree walk."); return result; } + private List checkByTreeWalk(HaxeReference scope, String name) { + final List result = new ArrayList<>(); + PsiTreeUtil.treeWalkUp(new ResolveScopeProcessor(result, name), scope, null, new ResolveState()); + if (result.isEmpty()) return null; + LogResolution(scope, "via tree walk."); + return result; + } private List checkIsAccessor(HaxeReference reference) { if (reference instanceof HaxePropertyAccessor) { diff --git a/src/main/java/com/intellij/plugins/haxe/lang/psi/impl/HaxeReferenceImpl.java b/src/main/java/com/intellij/plugins/haxe/lang/psi/impl/HaxeReferenceImpl.java index 0855c000d..f05f1f3c0 100644 --- a/src/main/java/com/intellij/plugins/haxe/lang/psi/impl/HaxeReferenceImpl.java +++ b/src/main/java/com/intellij/plugins/haxe/lang/psi/impl/HaxeReferenceImpl.java @@ -338,6 +338,50 @@ private boolean isType(Object o, Class clazz) { @NotNull private HaxeResolveResult resolveHaxeClassInternal() { + HaxeResolveResult result = _resolveHaxeClassInternal(); + + //extract type from expression if this is a macro ExprOf before we return result + if (isMacroIdentifier()) { + HaxeResolveResult type = extractTypeFromMacro(result); + if (type != null) result = type; + } + + return result; + } + + @Nullable + private static HaxeResolveResult extractTypeFromMacro(HaxeResolveResult result) { + HaxeClass aClass = result.getHaxeClass(); + if(aClass != null) { + if (aClass.getQualifiedName().equals("haxe.macro.ExprOf") + // TODO : TEMP hack since typeDef is resolved and `ExprOf` is typedef of `Expr` + || aClass.getQualifiedName().equals("haxe.macro.Expr")) { + HaxeGenericResolver resolver = result.getGenericResolver(); + @NotNull ResultHolder[] specifics = resolver.getSpecifics(); + if (specifics.length > 0) { + ResultHolder resolve = resolver.resolve("T"); + if (resolve != null && !resolve.isUnknown()) { + SpecificHaxeClassReference type = resolve.getClassType(); + if (type != null) return type.asResolveResult(); + } + } + } + } + return null; + } + + private boolean isMacroIdentifier() { + PsiElement[] children = this.getChildren(); + if(children.length == 1) { + if (children[0] instanceof HaxeIdentifier identifier) { + if (identifier.getMacroId() != null) return true; + } + } + return false; + } + + @NotNull + private HaxeResolveResult _resolveHaxeClassInternal() { ProgressIndicatorProvider.checkCanceled(); PsiElement resolve = null;