Search in sources :

Example 6 with FullyQualifiedPackageNameNode

use of org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode in project ballerina by ballerina-lang.

the class UnusedImportInspection method checkFile.

@Override
@Nullable
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
    // does not work in tests since CodeInsightTestCase copies file into temporary location
    if (ApplicationManager.getApplication().isUnitTestMode()) {
        return new ProblemDescriptor[0];
    }
    if (!(file instanceof BallerinaFile)) {
        return new ProblemDescriptor[0];
    }
    // This is used to track all packages used in the file.
    List<String> usedPackages = new LinkedList<>();
    LocalQuickFix[] availableFixes = new LocalQuickFix[0];
    List<ProblemDescriptor> problemDescriptors = new LinkedList<>();
    Collection<PackageNameNode> packageNameNodes = PsiTreeUtil.findChildrenOfType(file, PackageNameNode.class);
    for (PackageNameNode packageNameNode : packageNameNodes) {
        ProgressManager.checkCanceled();
        if (packageNameNode == null) {
            continue;
        }
        PackageDeclarationNode packageDeclarationNode = PsiTreeUtil.getParentOfType(packageNameNode, PackageDeclarationNode.class);
        if (packageDeclarationNode != null) {
            continue;
        }
        ImportDeclarationNode importDeclarationNode = PsiTreeUtil.getParentOfType(packageNameNode, ImportDeclarationNode.class);
        if (importDeclarationNode != null) {
            continue;
        }
        XmlAttribNode xmlAttribNode = PsiTreeUtil.getParentOfType(packageNameNode, XmlAttribNode.class);
        if (xmlAttribNode != null) {
            continue;
        }
        PsiElement nameIdentifier = packageNameNode.getNameIdentifier();
        if (nameIdentifier == null) {
            continue;
        }
        usedPackages.add(nameIdentifier.getText());
    }
    // This is used to keep track of fully qualified imported packages. This will be used to identify redeclared
    // import statements.
    List<String> fullyQualifiedImportedPackages = new LinkedList<>();
    // This is used to keep track of last package in import declaration. This will be used to identify importing
    // multiple packages which ends with same name.
    List<String> importedPackages = new LinkedList<>();
    Collection<ImportDeclarationNode> importDeclarationNodes = PsiTreeUtil.findChildrenOfType(file, ImportDeclarationNode.class);
    for (ImportDeclarationNode importDeclarationNode : importDeclarationNodes) {
        ProgressManager.checkCanceled();
        if (importDeclarationNode == null) {
            continue;
        }
        // Check unused imports. No need to check for fully qualified path since we cant import packages of same
        // name.
        List<PackageNameNode> packageNames = new ArrayList<>(PsiTreeUtil.findChildrenOfType(importDeclarationNode, PackageNameNode.class));
        PackageNameNode lastPackage = ContainerUtil.getLastItem(packageNames);
        if (lastPackage == null) {
            continue;
        }
        String lastPackageName = lastPackage.getText();
        if (!usedPackages.contains(lastPackageName)) {
            problemDescriptors.add(createProblemDescriptor(manager, "Unused import", isOnTheFly, importDeclarationNode, availableFixes, ProblemHighlightType.LIKE_UNUSED_SYMBOL));
        }
        // Check conflicting imports (which ends with same package name).
        if (importedPackages.contains(lastPackageName)) {
            problemDescriptors.add(createProblemDescriptor(manager, "Conflicting import", isOnTheFly, importDeclarationNode, availableFixes, ProblemHighlightType.GENERIC_ERROR));
        }
        importedPackages.add(lastPackageName);
        // Check redeclared imports.
        FullyQualifiedPackageNameNode fullyQualifiedPackageName = PsiTreeUtil.getChildOfType(importDeclarationNode, FullyQualifiedPackageNameNode.class);
        if (fullyQualifiedPackageName == null) {
            continue;
        }
        if (fullyQualifiedImportedPackages.contains(fullyQualifiedPackageName.getText())) {
            problemDescriptors.add(createProblemDescriptor(manager, "Redeclared import", isOnTheFly, importDeclarationNode, availableFixes, ProblemHighlightType.GENERIC_ERROR));
        }
        fullyQualifiedImportedPackages.add(fullyQualifiedPackageName.getText());
    }
    return problemDescriptors.toArray(new ProblemDescriptor[problemDescriptors.size()]);
}
Also used : BallerinaFile(org.ballerinalang.plugins.idea.psi.BallerinaFile) ImportDeclarationNode(org.ballerinalang.plugins.idea.psi.ImportDeclarationNode) ProblemDescriptor(com.intellij.codeInspection.ProblemDescriptor) ArrayList(java.util.ArrayList) LocalQuickFix(com.intellij.codeInspection.LocalQuickFix) PackageDeclarationNode(org.ballerinalang.plugins.idea.psi.PackageDeclarationNode) LinkedList(java.util.LinkedList) FullyQualifiedPackageNameNode(org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode) PackageNameNode(org.ballerinalang.plugins.idea.psi.PackageNameNode) FullyQualifiedPackageNameNode(org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode) XmlAttribNode(org.ballerinalang.plugins.idea.psi.XmlAttribNode) PsiElement(com.intellij.psi.PsiElement) Nullable(org.jetbrains.annotations.Nullable)

Example 7 with FullyQualifiedPackageNameNode

use of org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode in project ballerina by ballerina-lang.

the class WrongPackageStatementInspection method checkFile.

@Override
@Nullable
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
    // does not work in tests since CodeInsightTestCase copies file into temporary location
    if (ApplicationManager.getApplication().isUnitTestMode()) {
        return new ProblemDescriptor[0];
    }
    if (!(file instanceof BallerinaFile)) {
        return new ProblemDescriptor[0];
    }
    Module module = ModuleUtil.findModuleForFile(file.getVirtualFile(), file.getProject());
    boolean isBallerinaModule = BallerinaSdkService.getInstance(file.getProject()).isBallerinaModule(module);
    if (!isBallerinaModule) {
        return new ProblemDescriptor[0];
    }
    BallerinaFile ballerinaFile = (BallerinaFile) file;
    PsiDirectory directory = ballerinaFile.getContainingDirectory();
    if (directory == null) {
        return new ProblemDescriptor[0];
    }
    List<ProblemDescriptor> problemDescriptors = new LinkedList<>();
    String packageName = BallerinaUtil.suggestPackageNameForDirectory(directory);
    PackageDeclarationNode packageDeclarationNode = PsiTreeUtil.findChildOfType(file, PackageDeclarationNode.class);
    Collection<DefinitionNode> definitionNodes = PsiTreeUtil.findChildrenOfType(file, DefinitionNode.class);
    for (DefinitionNode definitionNode : definitionNodes) {
        PsiElement firstChild = definitionNode.getFirstChild();
        if (firstChild == null || !(firstChild instanceof IdentifierDefSubtree)) {
            return new ProblemDescriptor[0];
        }
        PsiElement nameIdentifier = ((IdentifierDefSubtree) firstChild).getNameIdentifier();
        if (nameIdentifier == null) {
            return new ProblemDescriptor[0];
        }
        if (!Comparing.strEqual(packageName, "", true) && packageDeclarationNode == null) {
            String description = "Missing package statement: '" + packageName + "'";
            ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(nameIdentifier, description, new AdjustPackageNameFix(nameIdentifier, packageName), ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly);
            problemDescriptors.add(problemDescriptor);
        }
    }
    if (!problemDescriptors.isEmpty()) {
        return problemDescriptors.toArray(new ProblemDescriptor[problemDescriptors.size()]);
    }
    if (packageDeclarationNode == null) {
        return new ProblemDescriptor[0];
    }
    FullyQualifiedPackageNameNode fullyQualifiedPackageNameNode = PsiTreeUtil.findChildOfType(packageDeclarationNode, FullyQualifiedPackageNameNode.class);
    if (fullyQualifiedPackageNameNode == null || fullyQualifiedPackageNameNode.getText().isEmpty()) {
        return new ProblemDescriptor[0];
    }
    Collection<PackageNameNode> packageNames = PsiTreeUtil.findChildrenOfType(packageDeclarationNode, PackageNameNode.class);
    if (packageNames.isEmpty()) {
        return new ProblemDescriptor[0];
    }
    LinkedList<PackageNameNode> packageNameNodes = new LinkedList<>();
    packageNameNodes.addAll(packageNames);
    PackageNameNode lastElement = packageNameNodes.getLast();
    if (lastElement == null) {
        return new ProblemDescriptor[0];
    }
    List<LocalQuickFix> availableFixes = new ArrayList<>();
    availableFixes.add(new AdjustPackageNameFix(fullyQualifiedPackageNameNode, packageName));
    PsiElement packageNameIdentifier = lastElement.getNameIdentifier();
    if (packageNameIdentifier == null) {
        return getProblemDescriptors(manager, isOnTheFly, packageName, availableFixes, fullyQualifiedPackageNameNode, lastElement);
    }
    PsiReference reference = packageNameIdentifier.getReference();
    if (reference == null) {
        return getProblemDescriptors(manager, isOnTheFly, packageName, availableFixes, fullyQualifiedPackageNameNode, lastElement);
    }
    PsiElement resolvedElement = reference.resolve();
    if (!(resolvedElement instanceof PsiDirectory)) {
        return getProblemDescriptors(manager, isOnTheFly, packageName, availableFixes, fullyQualifiedPackageNameNode, lastElement);
    }
    String containingDirectoryPackageName = BallerinaUtil.suggestPackageNameForDirectory(((PsiDirectory) resolvedElement));
    if (!Comparing.equal(packageName, containingDirectoryPackageName, true)) {
        if (!availableFixes.isEmpty()) {
            return getProblemDescriptors(manager, isOnTheFly, packageName, availableFixes, fullyQualifiedPackageNameNode, lastElement);
        }
    }
    return new ProblemDescriptor[0];
}
Also used : IdentifierDefSubtree(org.antlr.jetbrains.adaptor.psi.IdentifierDefSubtree) BallerinaFile(org.ballerinalang.plugins.idea.psi.BallerinaFile) ProblemDescriptor(com.intellij.codeInspection.ProblemDescriptor) ArrayList(java.util.ArrayList) LocalQuickFix(com.intellij.codeInspection.LocalQuickFix) PsiReference(com.intellij.psi.PsiReference) PackageDeclarationNode(org.ballerinalang.plugins.idea.psi.PackageDeclarationNode) LinkedList(java.util.LinkedList) DefinitionNode(org.ballerinalang.plugins.idea.psi.DefinitionNode) FullyQualifiedPackageNameNode(org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode) FullyQualifiedPackageNameNode(org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode) PackageNameNode(org.ballerinalang.plugins.idea.psi.PackageNameNode) PsiDirectory(com.intellij.psi.PsiDirectory) Module(com.intellij.openapi.module.Module) PsiElement(com.intellij.psi.PsiElement) Nullable(org.jetbrains.annotations.Nullable)

Example 8 with FullyQualifiedPackageNameNode

use of org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode in project ballerina by ballerina-lang.

the class BallerinaExternalAnnotator method getPackageName.

/**
 * Return the package name correspond to the provided file. This method will also consider the directory structure
 * as well. If the directory structure is different than the declared package in the file, relative directory
 * structure will be converted to package name and will be returned. Following 2 scenarios need to be considered.
 * <p>
 * Scenario 1 - Incorrect package declared in file. Correct directory structure.
 * Scenario 2 - Package declared in files in project root.
 *
 * @param file a psi file
 * @return package name correspond to the provided file
 */
private String getPackageName(PsiFile file) {
    // Get the package name specified in the file.
    PackageDeclarationNode packageDeclarationNode = PsiTreeUtil.findChildOfType(file, PackageDeclarationNode.class);
    if (packageDeclarationNode == null) {
        return null;
    }
    FullyQualifiedPackageNameNode packageNameNode = PsiTreeUtil.getChildOfType(packageDeclarationNode, FullyQualifiedPackageNameNode.class);
    if (packageNameNode == null) {
        return null;
    }
    String packageNameInFile = packageNameNode.getText();
    // Get the parent directory.
    PsiDirectory psiDirectory = file.getParent();
    if (psiDirectory == null) {
        return packageNameInFile;
    }
    // Package declaration might have an incorrect package declaration. So need to validate against directory name.
    if (packageNameInFile.endsWith(psiDirectory.getName())) {
        return packageNameInFile;
    }
    // Get the current module.
    Module module = ModuleUtilCore.findModuleForPsiElement(file);
    // Calculate the source root. This is used to get the relative directory path.
    String sourceRoot = file.getProject().getBasePath();
    if (module != null && FileUtil.exists(module.getModuleFilePath())) {
        sourceRoot = StringUtil.trimEnd(PathUtil.getParentPath(module.getModuleFilePath()), BallerinaConstants.IDEA_CONFIG_DIRECTORY);
    }
    // Get the package according to the directory structure.
    String directoryPath = psiDirectory.getVirtualFile().getPath();
    if (sourceRoot == null) {
        return packageNameInFile;
    }
    String packageName = directoryPath.replace(sourceRoot, "").replaceAll("[/\\\\]", "\\.");
    // If the package name is empty, that means the file is in the project root.
    if (packageName.isEmpty()) {
        return null;
    }
    // Otherwise return the calculated package path.
    return packageName;
}
Also used : FullyQualifiedPackageNameNode(org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode) PsiDirectory(com.intellij.psi.PsiDirectory) Module(com.intellij.openapi.module.Module) PackageDeclarationNode(org.ballerinalang.plugins.idea.psi.PackageDeclarationNode)

Example 9 with FullyQualifiedPackageNameNode

use of org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode in project ballerina by ballerina-lang.

the class BallerinaPsiImplUtil method resolveDirectory.

/**
 * Resolves a package name to matching directories.
 *
 * @param identifier the package name identifier which we need to resolve to the directory
 * @return resolved directory
 */
@NotNull
public static List<PsiDirectory> resolveDirectory(@NotNull IdentifierPSINode identifier) {
    List<PsiDirectory> results = new LinkedList<>();
    PsiElement parent;
    PsiElement tempParent = identifier.getParent();
    if (tempParent == null) {
        return results;
    }
    PsiElement superParent = tempParent.getParent();
    AliasNode aliasNode = PsiTreeUtil.getParentOfType(superParent, AliasNode.class);
    if (aliasNode != null) {
        PsiElement temp = superParent;
        while (temp != null && !(temp instanceof FullyQualifiedPackageNameNode)) {
            temp = temp.getPrevSibling();
        }
        if (temp != null) {
            parent = temp.getLastChild();
        } else {
            return results;
        }
    } else {
        parent = tempParent;
    }
    // This is used to store all the packages which need to resolve the current package.
    List<PsiElement> packages = new ArrayList<>();
    packages.add(parent);
    // Find all previous PackageNameNode elements.
    PsiElement sibling = parent.getPrevSibling();
    while (sibling != null) {
        if (sibling instanceof PackageNameNode) {
            // Add the sibling to the index 0 because we are traversing backward.
            packages.add(0, sibling);
        }
        sibling = sibling.getPrevSibling();
    }
    Project project = identifier.getProject();
    PsiFile containingFile = identifier.getContainingFile();
    PsiFile originalFile = containingFile.getOriginalFile();
    VirtualFile virtualFile = originalFile.getVirtualFile();
    if (virtualFile == null) {
        return results;
    }
    Module module = ModuleUtilCore.findModuleForFile(virtualFile, project);
    if (module == null) {
        return results;
    }
    results.addAll(findAllMatchingPackages(module, packages));
    return results;
}
Also used : VirtualFile(com.intellij.openapi.vfs.VirtualFile) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Project(com.intellij.openapi.project.Project) FullyQualifiedPackageNameNode(org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode) FullyQualifiedPackageNameNode(org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode) PackageNameNode(org.ballerinalang.plugins.idea.psi.PackageNameNode) PsiDirectory(com.intellij.psi.PsiDirectory) PsiFile(com.intellij.psi.PsiFile) Module(com.intellij.openapi.module.Module) PsiElement(com.intellij.psi.PsiElement) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) AliasNode(org.ballerinalang.plugins.idea.psi.AliasNode) NotNull(org.jetbrains.annotations.NotNull)

Example 10 with FullyQualifiedPackageNameNode

use of org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode in project ballerina by ballerina-lang.

the class BallerinaPsiImplUtil method resolveAliasNode.

/**
 * Resolves the given alias node to the corresponding directory.
 *
 * @param aliasNode an alias node
 * @return {@link PsiDirectory} which is the definition of the alias node.
 */
@Nullable
public static PsiDirectory resolveAliasNode(@NotNull AliasNode aliasNode) {
    ImportDeclarationNode importDeclarationNode = PsiTreeUtil.getParentOfType(aliasNode, ImportDeclarationNode.class);
    FullyQualifiedPackageNameNode fullyQualifiedPackageNameNode = PsiTreeUtil.getChildOfType(importDeclarationNode, FullyQualifiedPackageNameNode.class);
    if (fullyQualifiedPackageNameNode == null) {
        return null;
    }
    PackageNameNode[] packageNameNodes = PsiTreeUtil.getChildrenOfType(fullyQualifiedPackageNameNode, PackageNameNode.class);
    if (packageNameNodes == null) {
        return null;
    }
    PackageNameNode lastElement = ArrayUtil.getLastElement(packageNameNodes);
    if (lastElement == null) {
        return null;
    }
    PsiElement packageName = lastElement.getNameIdentifier();
    if (!(packageName instanceof IdentifierPSINode)) {
        return null;
    }
    List<PsiDirectory> directories = BallerinaPsiImplUtil.resolveDirectory(((IdentifierPSINode) packageName));
    if (directories.isEmpty()) {
        return null;
    }
    return directories.get(0);
}
Also used : FullyQualifiedPackageNameNode(org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode) ImportDeclarationNode(org.ballerinalang.plugins.idea.psi.ImportDeclarationNode) FullyQualifiedPackageNameNode(org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode) PackageNameNode(org.ballerinalang.plugins.idea.psi.PackageNameNode) PsiDirectory(com.intellij.psi.PsiDirectory) IdentifierPSINode(org.ballerinalang.plugins.idea.psi.IdentifierPSINode) PsiElement(com.intellij.psi.PsiElement) LeafPsiElement(com.intellij.psi.impl.source.tree.LeafPsiElement) Nullable(org.jetbrains.annotations.Nullable)

Aggregations

FullyQualifiedPackageNameNode (org.ballerinalang.plugins.idea.psi.FullyQualifiedPackageNameNode)12 PackageDeclarationNode (org.ballerinalang.plugins.idea.psi.PackageDeclarationNode)7 PackageNameNode (org.ballerinalang.plugins.idea.psi.PackageNameNode)7 PsiElement (com.intellij.psi.PsiElement)6 ArrayList (java.util.ArrayList)6 ImportDeclarationNode (org.ballerinalang.plugins.idea.psi.ImportDeclarationNode)6 Module (com.intellij.openapi.module.Module)4 PsiDirectory (com.intellij.psi.PsiDirectory)4 PsiFile (com.intellij.psi.PsiFile)4 LinkedList (java.util.LinkedList)4 AliasNode (org.ballerinalang.plugins.idea.psi.AliasNode)3 BallerinaFile (org.ballerinalang.plugins.idea.psi.BallerinaFile)3 XmlAttribNode (org.ballerinalang.plugins.idea.psi.XmlAttribNode)3 NotNull (org.jetbrains.annotations.NotNull)3 LocalQuickFix (com.intellij.codeInspection.LocalQuickFix)2 ProblemDescriptor (com.intellij.codeInspection.ProblemDescriptor)2 LeafPsiElement (com.intellij.psi.impl.source.tree.LeafPsiElement)2 DefinitionNode (org.ballerinalang.plugins.idea.psi.DefinitionNode)2 FunctionDefinitionNode (org.ballerinalang.plugins.idea.psi.FunctionDefinitionNode)2 ServiceDefinitionNode (org.ballerinalang.plugins.idea.psi.ServiceDefinitionNode)2