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()]);
}
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];
}
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;
}
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;
}
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);
}
Aggregations