From 6963f60471623c2f193414aa95933718ccf72daa Mon Sep 17 00:00:00 2001 From: Patrick Scheibe Date: Tue, 8 May 2018 07:36:04 +0200 Subject: [PATCH] Fix local and global resolving - Fix issue, where completion and resolving showed symbols that came from a completely different project. The reason was that GlobalSearchScope does not work as one would expect. This issue is fixed now and resolving of external symbols from other files or libraries should work correctly. - Fix for a minor issue in resolving patterns from Rule. In a_ -> a, the a_ should be green while the a is a global symbol - External Mathematica libraries are now regarded as "being compiled" to make navigation and resolving work correctly. You need to recreate your libraries in your project settings! - Fix local resolving of Condition expressions - Fix for the FullForm viewer --- build.gradle | 2 +- .../mathematica/MathematicaBundle.properties | 2 + .../mathematica/MathematicaNotification.java | 61 ++++++++ .../actions/MathematicaFullFormViewer.java | 27 ++-- .../providers/ImportedSymbolCompletion.java | 96 ------------- .../providers/ImportedSymbolCompletion.kt | 85 +++++++++++ .../MathematicaCodeFoldingSettingsImpl.java | 19 ++- .../MathematicaExpressionFoldingBuilder.java | 35 +++-- .../lang/psi/impl/pattern/ConditionImpl.java | 23 ++- .../lang/psi/impl/rules/RuleImpl.java | 22 ++- .../psi/util/MathematicaPatternVisitor2.kt | 39 ++--- .../lang/psi/util/PatternSymbolExtractor.kt | 35 +++-- .../MathematicaGlobalResolveCache.java | 24 ++++ .../MathematicaGlobalSymbolResolver.java | 135 ------------------ .../MathematicaGlobalSymbolResolver.kt | 115 +++++++++++++++ .../LocalDefinitionResolveProcessor.kt | 80 +++++------ ...maticaLibraryRootsComponentDescriptor.java | 35 +++-- 17 files changed, 459 insertions(+), 376 deletions(-) create mode 100644 src/de/halirutan/mathematica/MathematicaNotification.java delete mode 100644 src/de/halirutan/mathematica/codeinsight/completion/providers/ImportedSymbolCompletion.java create mode 100644 src/de/halirutan/mathematica/codeinsight/completion/providers/ImportedSymbolCompletion.kt delete mode 100644 src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalSymbolResolver.java create mode 100644 src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalSymbolResolver.kt diff --git a/build.gradle b/build.gradle index 1d1b1459..429ef0f2 100644 --- a/build.gradle +++ b/build.gradle @@ -65,7 +65,7 @@ task wrapper(type: Wrapper) { // Information about the plugin // Plugin version number -version '3.0pre12' +version '3.0pre13' intellij { version = '2018.1.2' diff --git a/resources/de/halirutan/mathematica/MathematicaBundle.properties b/resources/de/halirutan/mathematica/MathematicaBundle.properties index 1c92875c..81e8368f 100644 --- a/resources/de/halirutan/mathematica/MathematicaBundle.properties +++ b/resources/de/halirutan/mathematica/MathematicaBundle.properties @@ -61,3 +61,5 @@ doc.navi.invalid=Cannot resolve symbol {0} doc.navi.navto=Navigate to definition of {0} doc.navi.builtin=Built-in symbol {0} module.settings.language.level=Module Language Level +mathematica.notification.group=Mathematica Notifications +fullform.viewer.no.file=No file in editor open. Open a file to view its FullForm or select code in an editor to inspect the FullForm of an expression. diff --git a/src/de/halirutan/mathematica/MathematicaNotification.java b/src/de/halirutan/mathematica/MathematicaNotification.java new file mode 100644 index 00000000..e2c1f442 --- /dev/null +++ b/src/de/halirutan/mathematica/MathematicaNotification.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 Patrick Scheibe + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package de.halirutan.mathematica; + +import com.intellij.notification.NotificationDisplayType; +import com.intellij.notification.NotificationGroup; +import com.intellij.notification.NotificationType; +import de.halirutan.mathematica.util.MathematicaIcons; + +/** + * @author patrick (06.05.18). + */ +public class MathematicaNotification { + private static final NotificationGroup GROUP = new NotificationGroup( + MathematicaBundle.message("mathematica.notification.group"), + NotificationDisplayType.BALLOON, + false, + null, + MathematicaIcons.FILE_ICON); + + public static void info(String message) { + showNotification(message, NotificationType.INFORMATION); + } + + public static void warning(String message) { + showNotification(message, NotificationType.WARNING); + } + + public static void error(String message) { + showNotification(message, NotificationType.ERROR); + } + + private static void showNotification(String message, NotificationType type) { + GROUP.createNotification( + MathematicaBundle.message("language.name"), + message, + type, + null).notify(null); + } + +} diff --git a/src/de/halirutan/mathematica/actions/MathematicaFullFormViewer.java b/src/de/halirutan/mathematica/actions/MathematicaFullFormViewer.java index fc40d33d..1a08c706 100644 --- a/src/de/halirutan/mathematica/actions/MathematicaFullFormViewer.java +++ b/src/de/halirutan/mathematica/actions/MathematicaFullFormViewer.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2017 Patrick Scheibe + * Copyright (c) 2018 Patrick Scheibe + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -7,16 +8,16 @@ * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.halirutan.mathematica.actions; @@ -25,7 +26,6 @@ import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; @@ -36,7 +36,8 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.codeStyle.CodeStyleManager; -import de.halirutan.mathematica.file.MathematicaFileType; +import de.halirutan.mathematica.MathematicaBundle; +import de.halirutan.mathematica.MathematicaNotification; import de.halirutan.mathematica.lang.MathematicaLanguage; import de.halirutan.mathematica.lang.psi.util.MathematicaFullFormCreator; import de.halirutan.mathematica.lang.psi.util.MathematicaPsiElementFactory; @@ -53,7 +54,12 @@ public void actionPerformed(AnActionEvent e) { assert project != null; final FileEditorManagerEx editorManagerEx = FileEditorManagerEx.getInstanceEx(project); final VirtualFile currentFile = editorManagerEx.getCurrentFile(); - if (currentFile != null && currentFile.getFileType().equals(MathematicaFileType.INSTANCE)) { + if (currentFile == null) { + MathematicaNotification.error(MathematicaBundle.message("fullform.viewer.no.file")); + return; + } + final PsiFile psiFile = PsiManager.getInstance(project).findFile(currentFile); + if (psiFile != null && MathematicaLanguage.INSTANCE.equals(psiFile.getLanguage())) { MathematicaFullFormCreator fullFormCreator = new MathematicaFullFormCreator(); PsiElement expression = null; if (editor != null) { @@ -65,10 +71,7 @@ public void actionPerformed(AnActionEvent e) { expression = factory.createDummyFile(selectedText); } } else { - final PsiFile psiFile = PsiManager.getInstance(project).findFile(currentFile); - if (psiFile != null) { - expression = psiFile; - } + expression = psiFile; } } diff --git a/src/de/halirutan/mathematica/codeinsight/completion/providers/ImportedSymbolCompletion.java b/src/de/halirutan/mathematica/codeinsight/completion/providers/ImportedSymbolCompletion.java deleted file mode 100644 index d8d553e6..00000000 --- a/src/de/halirutan/mathematica/codeinsight/completion/providers/ImportedSymbolCompletion.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2018 Patrick Scheibe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package de.halirutan.mathematica.codeinsight.completion.providers; - -import com.intellij.codeInsight.completion.*; -import com.intellij.codeInsight.lookup.LookupElementBuilder; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtilCore; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.project.Project; -import com.intellij.patterns.PsiElementPattern.Capture; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.ProcessingContext; -import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.indexing.IdFilter; -import de.halirutan.mathematica.index.packageexport.MathematicaPackageExportIndex; -import de.halirutan.mathematica.lang.parsing.MathematicaElementTypes; -import de.halirutan.mathematica.lang.psi.api.Symbol; -import org.jetbrains.annotations.NotNull; - -import java.util.Objects; - -import static com.intellij.patterns.PlatformPatterns.psiElement; -import static de.halirutan.mathematica.codeinsight.completion.MathematicaCompletionContributor.IMPORT_VARIABLE_PRIORITY; - - -/** - * Accesses the file index to provide completion for functions that are defined in other packages. - */ -public class ImportedSymbolCompletion extends MathematicaCompletionProvider { - - @Override - public void addTo(CompletionContributor contributor) { - final Capture symbolPattern = psiElement().withElementType(MathematicaElementTypes.IDENTIFIER); - contributor.extend(CompletionType.BASIC, symbolPattern, this); - } - - @Override - protected void addCompletions(@NotNull CompletionParameters parameters, ProcessingContext context, @NotNull CompletionResultSet result) { - final PsiElement callingSymbol = parameters.getPosition().getParent(); - final Project project = callingSymbol.getProject(); - - String prefix = findCurrentText(parameters, parameters.getPosition()); - if (parameters.getInvocationCount() == 0 && prefix.isEmpty() && !(callingSymbol instanceof Symbol)) { - return; - } - final PsiFile originalFile = parameters.getOriginalFile(); - final Module module = - ModuleUtilCore.findModuleForFile(originalFile.getVirtualFile(), project); - if (module != null) { - if (!parameters.isExtendedCompletion() || !(prefix.isEmpty() || Character.isDigit(prefix.charAt(0)))) { - - final GlobalSearchScope moduleScope = module.getModuleWithDependenciesAndLibrariesScope(true); - final FileBasedIndex index = FileBasedIndex.getInstance(); - - index.processAllKeys( - MathematicaPackageExportIndex.INDEX_ID, - key -> { - ProgressManager.checkCanceled(); - if (key.isExported() && !Objects.equals(key.getFileName(), originalFile.getName()) && - !index.getContainingFiles(MathematicaPackageExportIndex.INDEX_ID, key, moduleScope).isEmpty()) { - result.addElement(PrioritizedLookupElement.withPriority( - LookupElementBuilder.create(key.getSymbol()).withTypeText("(" + key.getFileName() + ")", true), - IMPORT_VARIABLE_PRIORITY)); - } - return true; - }, - moduleScope, - IdFilter.getProjectIdFilter(project, false) - ); - } - } - } -} diff --git a/src/de/halirutan/mathematica/codeinsight/completion/providers/ImportedSymbolCompletion.kt b/src/de/halirutan/mathematica/codeinsight/completion/providers/ImportedSymbolCompletion.kt new file mode 100644 index 00000000..21848878 --- /dev/null +++ b/src/de/halirutan/mathematica/codeinsight/completion/providers/ImportedSymbolCompletion.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018 Patrick Scheibe + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package de.halirutan.mathematica.codeinsight.completion.providers + +import com.intellij.codeInsight.completion.CompletionContributor +import com.intellij.codeInsight.completion.CompletionParameters +import com.intellij.codeInsight.completion.CompletionResultSet +import com.intellij.codeInsight.completion.CompletionType +import com.intellij.codeInsight.completion.PrioritizedLookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.module.ModuleUtilCore +import com.intellij.openapi.progress.ProgressManager +import com.intellij.patterns.PlatformPatterns.psiElement +import com.intellij.util.ProcessingContext +import com.intellij.util.indexing.FileBasedIndex +import de.halirutan.mathematica.codeinsight.completion.MathematicaCompletionContributor.IMPORT_VARIABLE_PRIORITY +import de.halirutan.mathematica.index.packageexport.MathematicaPackageExportIndex +import de.halirutan.mathematica.lang.parsing.MathematicaElementTypes +import de.halirutan.mathematica.lang.psi.api.Symbol + + +/** + * Accesses the file index to provide completion for functions that are defined in other packages. + */ +class ImportedSymbolCompletion : MathematicaCompletionProvider() { + + override fun addTo(contributor: CompletionContributor) { + val symbolPattern = psiElement().withElementType(MathematicaElementTypes.IDENTIFIER) + contributor.extend(CompletionType.BASIC, symbolPattern, this) + } + + override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) { + val callingSymbol = parameters.position.parent + val project = callingSymbol.project + + val prefix = findCurrentText(parameters, parameters.position) + if (parameters.invocationCount == 0 && prefix.isEmpty() || callingSymbol !is Symbol) { + return + } + val originalFile = parameters.originalFile + val module = ModuleUtilCore.findModuleForFile(originalFile.virtualFile, project) + if (module != null) { + val moduleScope = module.getModuleWithDependenciesAndLibrariesScope(true) + val index = FileBasedIndex.getInstance() + val indexID = MathematicaPackageExportIndex.INDEX_ID + index.getAllKeys(indexID, project).forEach { + it?.let { + val inScope = !index.processValues( + indexID, + it, + null, + { _, _ -> false }, + moduleScope + ) + ProgressManager.checkCanceled() + if (inScope && it.isExported) { + result.addElement(PrioritizedLookupElement.withPriority( + LookupElementBuilder.create(it.symbol).withTypeText("(" + it.fileName + ")", true), + IMPORT_VARIABLE_PRIORITY)) + } + } + } + } + } +} diff --git a/src/de/halirutan/mathematica/codeinsight/folding/MathematicaCodeFoldingSettingsImpl.java b/src/de/halirutan/mathematica/codeinsight/folding/MathematicaCodeFoldingSettingsImpl.java index 8e5d8a97..9a4fb962 100644 --- a/src/de/halirutan/mathematica/codeinsight/folding/MathematicaCodeFoldingSettingsImpl.java +++ b/src/de/halirutan/mathematica/codeinsight/folding/MathematicaCodeFoldingSettingsImpl.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2015 Patrick Scheibe + * Copyright (c) 2018 Patrick Scheibe + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -7,22 +8,26 @@ * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.halirutan.mathematica.codeinsight.folding; -import com.intellij.openapi.components.*; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; import com.intellij.util.xmlb.XmlSerializerUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -57,7 +62,7 @@ public MathematicaCodeFoldingSettingsImpl getState() { } @Override - public void loadState(final MathematicaCodeFoldingSettingsImpl state) { + public void loadState(@NotNull final MathematicaCodeFoldingSettingsImpl state) { XmlSerializerUtil.copyBean(state, this); } } diff --git a/src/de/halirutan/mathematica/codeinsight/folding/MathematicaExpressionFoldingBuilder.java b/src/de/halirutan/mathematica/codeinsight/folding/MathematicaExpressionFoldingBuilder.java index eebaf087..5d801481 100644 --- a/src/de/halirutan/mathematica/codeinsight/folding/MathematicaExpressionFoldingBuilder.java +++ b/src/de/halirutan/mathematica/codeinsight/folding/MathematicaExpressionFoldingBuilder.java @@ -1,24 +1,23 @@ /* - * Copyright (c) 2017 Patrick Scheibe + * Copyright (c) 2018 Patrick Scheibe * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.halirutan.mathematica.codeinsight.folding; @@ -83,7 +82,7 @@ public FoldingDescriptor[] buildFoldRegions(@NotNull final ASTNode node, @NotNul List descriptors = new ArrayList<>(); collectRegionsRecursively(node, document, descriptors); - return descriptors.toArray(new FoldingDescriptor[descriptors.size()]); + return descriptors.toArray(FoldingDescriptor.EMPTY); } private void collectRegionsRecursively(@NotNull final ASTNode node, diff --git a/src/de/halirutan/mathematica/lang/psi/impl/pattern/ConditionImpl.java b/src/de/halirutan/mathematica/lang/psi/impl/pattern/ConditionImpl.java index 7f81f2ea..2b290d49 100644 --- a/src/de/halirutan/mathematica/lang/psi/impl/pattern/ConditionImpl.java +++ b/src/de/halirutan/mathematica/lang/psi/impl/pattern/ConditionImpl.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2013 Patrick Scheibe + * Copyright (c) 2018 Patrick Scheibe + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -7,22 +8,25 @@ * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.halirutan.mathematica.lang.psi.impl.pattern; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.ResolveState; +import com.intellij.psi.scope.PsiScopeProcessor; import de.halirutan.mathematica.lang.psi.MathematicaVisitor; import de.halirutan.mathematica.lang.psi.api.pattern.Condition; import de.halirutan.mathematica.lang.psi.impl.OperatorNameProviderImpl; @@ -36,6 +40,15 @@ public ConditionImpl(@NotNull ASTNode node) { super(node); } + @Override + public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { + if (lastParent.getParent() != this) { + return true; + } + return processor.execute(this, state); + } + + @Override public void accept(@NotNull PsiElementVisitor visitor) { if (visitor instanceof MathematicaVisitor) { diff --git a/src/de/halirutan/mathematica/lang/psi/impl/rules/RuleImpl.java b/src/de/halirutan/mathematica/lang/psi/impl/rules/RuleImpl.java index fd2dc905..de0856a2 100644 --- a/src/de/halirutan/mathematica/lang/psi/impl/rules/RuleImpl.java +++ b/src/de/halirutan/mathematica/lang/psi/impl/rules/RuleImpl.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 2013 Patrick Scheibe + * Copyright (c) 2018 Patrick Scheibe + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -7,22 +8,25 @@ * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.halirutan.mathematica.lang.psi.impl.rules; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.ResolveState; +import com.intellij.psi.scope.PsiScopeProcessor; import de.halirutan.mathematica.lang.psi.MathematicaVisitor; import de.halirutan.mathematica.lang.psi.api.rules.Rule; import de.halirutan.mathematica.lang.psi.impl.OperatorNameProviderImpl; @@ -36,6 +40,14 @@ public RuleImpl(@NotNull ASTNode node) { super(node); } + @Override + public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { + if (lastParent.getParent() != this) { + return true; + } + return processor.execute(this, state); + } + @Override public void accept(@NotNull PsiElementVisitor visitor) { if (visitor instanceof MathematicaVisitor) { diff --git a/src/de/halirutan/mathematica/lang/psi/util/MathematicaPatternVisitor2.kt b/src/de/halirutan/mathematica/lang/psi/util/MathematicaPatternVisitor2.kt index 4cb7663a..ad6bd297 100644 --- a/src/de/halirutan/mathematica/lang/psi/util/MathematicaPatternVisitor2.kt +++ b/src/de/halirutan/mathematica/lang/psi/util/MathematicaPatternVisitor2.kt @@ -1,24 +1,23 @@ /* - * Copyright (c) 2017 Patrick Scheibe + * Copyright (c) 2018 Patrick Scheibe * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.halirutan.mathematica.lang.psi.util @@ -29,6 +28,7 @@ import de.halirutan.mathematica.lang.psi.api.Symbol import de.halirutan.mathematica.lang.psi.api.assignment.SetDelayed import de.halirutan.mathematica.lang.psi.api.assignment.TagSet import de.halirutan.mathematica.lang.psi.api.assignment.TagSetDelayed +import de.halirutan.mathematica.lang.psi.api.pattern.Condition import de.halirutan.mathematica.lang.psi.api.rules.RuleDelayed /** @@ -75,5 +75,10 @@ class MathematicaPatternVisitor2 : MathematicaVisitor() { extractPatternVariables(lhs) } + override fun visitCondition(condition: Condition) { + condition.firstChild?.let { + extractPatternVariables(it) + } + } } diff --git a/src/de/halirutan/mathematica/lang/psi/util/PatternSymbolExtractor.kt b/src/de/halirutan/mathematica/lang/psi/util/PatternSymbolExtractor.kt index 7e301f65..4c1e6f56 100644 --- a/src/de/halirutan/mathematica/lang/psi/util/PatternSymbolExtractor.kt +++ b/src/de/halirutan/mathematica/lang/psi/util/PatternSymbolExtractor.kt @@ -1,24 +1,23 @@ /* - * Copyright (c) 2017 Patrick Scheibe + * Copyright (c) 2018 Patrick Scheibe * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.halirutan.mathematica.lang.psi.util @@ -85,7 +84,7 @@ class PatternSymbolExtractor : MathematicaVisitor() { } override fun visitFunctionCall(functionCall: FunctionCall) { - val head = functionCall.firstChild + val head = functionCall.head if (head is Symbol) { val functionName = head.symbolName if (myDiveInFirstChild.contains(functionName)) { diff --git a/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalResolveCache.java b/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalResolveCache.java index 275d178e..6f377406 100644 --- a/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalResolveCache.java +++ b/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalResolveCache.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2018 Patrick Scheibe + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + package de.halirutan.mathematica.lang.resolve; import com.intellij.openapi.components.ServiceManager; @@ -94,12 +116,14 @@ public SymbolResolveResult cacheInvalidFileSymbol(@NotNull Symbol symbol, PsiEle } + @NotNull public SymbolResolveResult cacheBuiltInSymbol(@NotNull Symbol symbol) { final LightBuiltInSymbol lightSymbol = new LightBuiltInSymbol(symbol); return myCachedBuiltinSymbols.computeIfAbsent(lightSymbol, k -> new SymbolResolveResult(lightSymbol, LocalizationConstruct.MScope.KERNEL_SCOPE, null, true)); } + @NotNull public SymbolResolveResult cacheExternalSymbol(@NotNull Symbol symbol, @NotNull Symbol externalSymbol, PsiElement scopeElement) { final LightExternalSymbol lightSymbol = new LightExternalSymbol(symbol); return myCachedExternalSymbols.computeIfAbsent(lightSymbol, diff --git a/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalSymbolResolver.java b/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalSymbolResolver.java deleted file mode 100644 index 7b51c0ca..00000000 --- a/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalSymbolResolver.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2018 Patrick Scheibe - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package de.halirutan.mathematica.lang.resolve; - -import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtilCore; -import com.intellij.openapi.progress.ProgressManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import com.intellij.psi.ResolveResult; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.ProjectScope; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.indexing.FileBasedIndex; -import com.intellij.util.indexing.IdFilter; -import de.halirutan.mathematica.index.packageexport.MathematicaPackageExportIndex; -import de.halirutan.mathematica.lang.psi.api.MathematicaPsiFile; -import de.halirutan.mathematica.lang.psi.api.Symbol; -import de.halirutan.mathematica.lang.resolve.processors.GlobalDefinitionResolveProcessor; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import static de.halirutan.mathematica.lang.psi.util.MathematicaPsiUtilities.isBuiltInSymbol; - -/** - * The symbol resolver works currently in 3 steps to find a possible definition of a symbol that appears in the code. - * It will check if the symbol is a built-in symbol - * It will make a tree-walk upwards to check if the symbol is in any localization construct - * It will check the file, if the symbol is defined as a global symbol like a function at file-scope - * It will check the file-index and look for symbols that are exported from other files - * - * @author patrick (08.07.17). - */ -public class MathematicaGlobalSymbolResolver { - - @NotNull - public ResolveResult[] resolve(@NotNull Symbol ref, @NotNull PsiFile containingFile) { - - if (!containingFile.equals(ref.getContainingFile())) { - return ResolveResult.EMPTY_ARRAY; - } - - final MathematicaGlobalResolveCache symbolCache = - MathematicaGlobalResolveCache.getInstance(containingFile.getProject()); - - if (symbolCache.containsSymbol(ref)) { - return new ResolveResult[]{symbolCache.getValue(ref)}; - } - - if (isBuiltInSymbol(ref)) { - final SymbolResolveResult result = symbolCache.cacheBuiltInSymbol(ref); - return new ResolveResult[]{result}; - } - - GlobalDefinitionResolveProcessor globalProcessor = new GlobalDefinitionResolveProcessor(ref); - PsiTreeUtil.processElements(containingFile, globalProcessor); - - final Symbol resolveResult = globalProcessor.getResolveResult(); - if (resolveResult != null) { - final SymbolResolveResult result = symbolCache.cacheFileSymbol(resolveResult, containingFile); - if (containingFile instanceof MathematicaPsiFile) { - ((MathematicaPsiFile) containingFile).cacheLocalDefinition(result); - } - return new ResolveResult[]{result}; - } - - final Project project = containingFile.getProject(); - final Module module = - ModuleUtilCore.findModuleForFile(containingFile.getVirtualFile(), project); - if (module != null) { - final List references = new ArrayList<>(); - final PsiManager psiManager = PsiManager.getInstance(project); - final FileBasedIndex fileIndex = FileBasedIndex.getInstance(); - final GlobalSearchScope moduleScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) - .union(ProjectScope.getLibrariesScope(project)); - fileIndex.processAllKeys( - MathematicaPackageExportIndex.INDEX_ID, - key -> { - ProgressManager.checkCanceled(); - if (key.isExported() && key.getSymbol().equals(ref.getSymbolName())) { - final Collection containingFiles = - fileIndex.getContainingFiles(MathematicaPackageExportIndex.INDEX_ID, key, moduleScope); - containingFiles.forEach(file -> { - final PsiFile psiFile = psiManager.findFile(file); - if (psiFile != null) { - final Symbol externalSymbol = - PsiTreeUtil.findElementOfClassAtOffset(psiFile, key.getOffset(), Symbol.class, true); - if (externalSymbol != null) { - final SymbolResolveResult result = symbolCache.cacheExternalSymbol(ref, externalSymbol, psiFile); - references.add(result); - } - } - }); - } - return true; - }, - moduleScope, - IdFilter.getProjectIdFilter(project, false) - ); - fileIndex.getAllKeys(MathematicaPackageExportIndex.INDEX_ID, project); - if (!references.isEmpty()) { - return references.toArray(new ResolveResult[0]); - } - } - - final SymbolResolveResult result = symbolCache.cacheInvalidFileSymbol(ref, containingFile); - return new ResolveResult[]{result}; - } - -} diff --git a/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalSymbolResolver.kt b/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalSymbolResolver.kt new file mode 100644 index 00000000..0250b8a7 --- /dev/null +++ b/src/de/halirutan/mathematica/lang/resolve/MathematicaGlobalSymbolResolver.kt @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018 Patrick Scheibe + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package de.halirutan.mathematica.lang.resolve + +import com.intellij.openapi.module.ModuleUtilCore +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import com.intellij.psi.ResolveResult +import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.util.PsiTreeUtil +import com.intellij.util.indexing.FileBasedIndex +import de.halirutan.mathematica.index.packageexport.MathematicaPackageExportIndex +import de.halirutan.mathematica.lang.psi.api.MathematicaPsiFile +import de.halirutan.mathematica.lang.psi.api.Symbol +import de.halirutan.mathematica.lang.psi.util.MathematicaPsiUtilities.isBuiltInSymbol +import de.halirutan.mathematica.lang.resolve.processors.GlobalDefinitionResolveProcessor +import java.util.* + +/** + * The symbol resolver works currently in 3 steps to find a possible definition of a symbol that appears in the code. + * It will check if the symbol is a built-in symbol + * It will make a tree-walk upwards to check if the symbol is in any localization construct + * It will check the file, if the symbol is defined as a global symbol like a function at file-scope + * It will check the file-index and look for symbols that are exported from other files + * + * @author patrick (08.07.17). + */ +class MathematicaGlobalSymbolResolver { + + private val packageIndex = MathematicaPackageExportIndex.INDEX_ID + + fun resolve(ref: Symbol, containingFile: PsiFile): Array { + + if (containingFile != ref.containingFile) { + return ResolveResult.EMPTY_ARRAY + } + + val symbolCache = MathematicaGlobalResolveCache.getInstance(containingFile.project) + + if (symbolCache.containsSymbol(ref)) { + return arrayOf(symbolCache.getValue(ref)) + } + + if (isBuiltInSymbol(ref)) { + val result = symbolCache.cacheBuiltInSymbol(ref) + return arrayOf(result) + } + + val globalProcessor = GlobalDefinitionResolveProcessor(ref) + PsiTreeUtil.processElements(containingFile, globalProcessor) + + val resolveResult = globalProcessor.resolveResult + resolveResult?.let { + val result = symbolCache.cacheFileSymbol(resolveResult, containingFile) + if (containingFile is MathematicaPsiFile) { + containingFile.cacheLocalDefinition(result) + } + return arrayOf(result) + } + + val cacheInvalidResult: () -> Array = { arrayOf(symbolCache.cacheInvalidFileSymbol(ref, containingFile)) } + + val project = containingFile.project + val virtualFile = containingFile.virtualFile ?: return cacheInvalidResult() + val module = ModuleUtilCore.findModuleForFile(virtualFile, project) ?: return cacheInvalidResult() + val references = ArrayList() + val psiManager = PsiManager.getInstance(project) + val fileIndex = FileBasedIndex.getInstance() ?: return cacheInvalidResult() + val moduleScope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) + fileIndex.getAllKeys(packageIndex, project).forEach { + it?.let { + val fileForKey = arrayListOf() + val inScope = !fileIndex.processValues( + packageIndex, + it, + null, + { file, _ -> fileForKey.add(file); false }, + moduleScope + ) + + if (fileForKey.isNotEmpty() && inScope && it.isExported && it.symbol == ref.fullSymbolName) { + val psiFile = psiManager.findFile(fileForKey.first()) ?: return@forEach + val externalSymbol = PsiTreeUtil.findElementOfClassAtOffset(psiFile, it.offset, Symbol::class.java, true) + ?: return@forEach + val result = symbolCache.cacheExternalSymbol(ref, externalSymbol, psiFile) + references.add(result) + return references.toTypedArray() + } + } + } + return cacheInvalidResult() + } + +} diff --git a/src/de/halirutan/mathematica/lang/resolve/processors/LocalDefinitionResolveProcessor.kt b/src/de/halirutan/mathematica/lang/resolve/processors/LocalDefinitionResolveProcessor.kt index d7106832..0f195c08 100644 --- a/src/de/halirutan/mathematica/lang/resolve/processors/LocalDefinitionResolveProcessor.kt +++ b/src/de/halirutan/mathematica/lang/resolve/processors/LocalDefinitionResolveProcessor.kt @@ -1,24 +1,23 @@ /* - * Copyright (c) 2017 Patrick Scheibe + * Copyright (c) 2018 Patrick Scheibe * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.halirutan.mathematica.lang.resolve.processors @@ -26,7 +25,6 @@ package de.halirutan.mathematica.lang.resolve.processors import com.intellij.psi.PsiElement import com.intellij.psi.ResolveState import com.intellij.psi.scope.PsiScopeProcessor -import com.intellij.psi.util.PsiTreeUtil import de.halirutan.mathematica.lang.psi.LocalizationConstruct import de.halirutan.mathematica.lang.psi.LocalizationConstruct.MScope import de.halirutan.mathematica.lang.psi.api.FunctionCall @@ -34,8 +32,9 @@ import de.halirutan.mathematica.lang.psi.api.Symbol import de.halirutan.mathematica.lang.psi.api.assignment.Set import de.halirutan.mathematica.lang.psi.api.assignment.SetDelayed import de.halirutan.mathematica.lang.psi.api.assignment.TagSetDelayed +import de.halirutan.mathematica.lang.psi.api.pattern.Condition +import de.halirutan.mathematica.lang.psi.api.rules.Rule import de.halirutan.mathematica.lang.psi.api.rules.RuleDelayed -import de.halirutan.mathematica.lang.psi.util.MathematicaPatternVisitor import de.halirutan.mathematica.lang.psi.util.MathematicaPatternVisitor2 import de.halirutan.mathematica.lang.psi.util.PatternSymbolExtractor import de.halirutan.mathematica.lang.resolve.SymbolResolveResult @@ -45,39 +44,33 @@ import de.halirutan.mathematica.lang.resolve.resolvers.ModuleLikeResolver import de.halirutan.mathematica.lang.resolve.resolvers.TableLikeResolver /** - * TODO: Rewrite comment - * Provides the functionality of resolving local references. This means, this class takes care to find out where a local - * variable was defined and it can be used to find all references of a variable inside a scope. "Local" in this context - * means that the variable must be localized with Module, Block, Table, Compile, etc.. + * Provides the functionality of resolving local references. * + * "Local" means that symbols can be *bound* by constructs like `Module`, `With`, `Block`, `Plot`, `Table` or even `:=`. + * From a very practical way, the `x` in `x_ :> x` can regarded as local and it doesn't care about other `x`s that are + * defined outside this scope. * - * This class is for instance used by but to give an overview of a complete flow let me - * explain this in more detail: + * This class takes care to find out where a local + * variable was defined and it can be used to find all references of a variable inside a scope. * + * This class is used by by GoToDeclaration or my reference highlighting. An example: * * Let's assume you have "Preferences" -> "Editor" -> "Highlight usages of symbol under cursor" turned on and when you * browse through the code and stop on a variable, the variable itself and all its usages are highlighted. The moment * you move the cursor over the variable, IDEA calls [Symbol.getReference] in order to find the place where this - * variable is defined. The first finds the correct PsiElement for which the reference should + * variable is defined. First, it finds the correct PsiElement for which the reference should * be searched. Usually, this is always the [Symbol] over which the cursor is. * - * - * Now searches clever for the place where the variable could be defined. This - * process depends on the language; in Mathematica, I use currently the following approach: I walk the parsing tree + * The search process depends on the language; in Mathematica, I use currently the following approach: I walk the parsing tree * upwards and check every Module, Block, ... I find on my way. Checking means I look in the definition list whether my - * variable is defined there. If not, I go further upwards. This is why you find a [ ][PsiTreeUtil.treeWalkUp] in this method. On every step - * upwards the [.execute] method is called and exactly here I extract all locally + * variable is defined there. If not, I go further upwards. On every step + * upwards the [LocalDefinitionResolveProcessor.execute] method is called and exactly here I extract all locally * defined variables I find and check whether any of it has the same name as my original variable whose definition I * want to find. * - * * If I find it in any of the localization constructs like Module, Block.. I stop and return the PsiElement which is the * place of definition. * - * - * Finding all usages works btw the same way: First I find the definition of a variable and then I find all variables - * which resolve to the exact same place of definition. - * * @author patrick (5/22/13) */ class LocalDefinitionResolveProcessor(private val myStartElement: Symbol) : PsiScopeProcessor { @@ -107,7 +100,6 @@ class LocalDefinitionResolveProcessor(private val myStartElement: Symbol) : PsiS */ override fun execute(element: PsiElement, state: ResolveState): Boolean { if (element is FunctionCall) { - if (element.isScopingConstruct) { val scopingConstruct = element.scopingConstruct @@ -120,13 +112,10 @@ class LocalDefinitionResolveProcessor(private val myStartElement: Symbol) : PsiS } resolveResult?.let { return false } } - } else if (element is SetDelayed || element is TagSetDelayed || element is Set) { - - val p2 = MathematicaPatternVisitor2() - element.accept(p2) - - val patternVisitor = MathematicaPatternVisitor() + } else if (element is SetDelayed || element is TagSetDelayed || element is Set || element is Condition) { + val patternVisitor = MathematicaPatternVisitor2() element.accept(patternVisitor) + for (p in patternVisitor.patternSymbols) { if (p.fullSymbolName == myStartElement.fullSymbolName) { if (element is Set && myStartElement !== p) { @@ -136,12 +125,15 @@ class LocalDefinitionResolveProcessor(private val myStartElement: Symbol) : PsiS return false } } - } else if (element is RuleDelayed) { + } else if (element is RuleDelayed || element is Rule) { val patternExtractor = PatternSymbolExtractor() element.accept(patternExtractor) for (symbol in patternExtractor.patternSymbols) { if (symbol.fullSymbolName == myStartElement.fullSymbolName) { + if (element is Rule && myStartElement !== symbol) { + continue + } resolveResult = SymbolResolveResult(symbol, MScope.RULEDELAYED_SCOPE, element, true) return false } diff --git a/src/de/halirutan/mathematica/library/MathematicaLibraryRootsComponentDescriptor.java b/src/de/halirutan/mathematica/library/MathematicaLibraryRootsComponentDescriptor.java index e9e67fed..f9f02775 100644 --- a/src/de/halirutan/mathematica/library/MathematicaLibraryRootsComponentDescriptor.java +++ b/src/de/halirutan/mathematica/library/MathematicaLibraryRootsComponentDescriptor.java @@ -1,24 +1,23 @@ /* - * Copyright (c) 2017 Patrick Scheibe + * Copyright (c) 2018 Patrick Scheibe * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ package de.halirutan.mathematica.library; @@ -41,7 +40,7 @@ public class MathematicaLibraryRootsComponentDescriptor extends DefaultLibraryRo @NotNull @Override public List getRootDetectors() { - return Lists.newArrayList(new MathematicaLibraryRootDetector(OrderRootType.SOURCES, false, "Mathematica Library")); + return Lists.newArrayList(new MathematicaLibraryRootDetector(OrderRootType.CLASSES, false, "Mathematica Library")); } }