Skip to content

Commit

Permalink
build: Improve Compatibility verification
Browse files Browse the repository at this point in the history
Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Aug 19, 2024
1 parent 869ead4 commit f4d5075
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 397 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,17 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiAnnotationMemberValue;
import com.intellij.psi.PsiAnnotationMethod;
import com.intellij.psi.PsiArrayType;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiCompiledElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiLiteral;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMember;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeParameter;
import com.intellij.psi.PsiVariable;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.ClassUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -288,7 +270,7 @@ public static VirtualFile getRootDirectory(PsiElement element) {
return getRootDirectory(PsiTreeUtil.getParentOfType(element, PsiFile.class));
}

public static VirtualFile getRootDirectory(PsiFile file) {
public static @Nullable VirtualFile getRootDirectory(PsiFile file) {
ProjectFileIndex index = ProjectFileIndex.getInstance(file.getProject());
VirtualFile directory = index.getSourceRootForFile(file.getVirtualFile());
if (directory == null) {
Expand All @@ -297,25 +279,6 @@ public static VirtualFile getRootDirectory(PsiFile file) {
return directory;
}

public static String getLocation(Project project, VirtualFile directory) {
String location = null;
Module module = ProjectFileIndex.getInstance(project).getModuleForFile(directory);
if (module != null) {
VirtualFile moduleRoot = LocalFileSystem.getInstance().findFileByIoFile(new File(module.getModuleFilePath()).getParentFile());
String path = VfsUtilCore.getRelativePath(directory, moduleRoot);
if (path != null) {
location = '/' + module.getName() + '/' + path;
}
}
if (location == null) {
location = directory.getPath();
}
if (location.endsWith("!/")) {
location = location.substring(0, location.length() - 2);
}
return location;
}

public static boolean overlaps(TextRange typeRange, TextRange methodRange) {
if (typeRange == null || methodRange == null) {
return false;
Expand Down Expand Up @@ -347,6 +310,6 @@ public static String getRawResolvedTypeName(PsiMethod method) {
* @return
*/
public static boolean isVoidReturnType(PsiMethod method) {
return PsiType.VOID.equals(method.getReturnType());
return PsiTypes.voidType().equals(method.getReturnType());
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,21 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
* Copyright (c) 2023 Red Hat Inc. and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.graphql.java;


import java.text.MessageFormat;
import java.util.logging.Logger;
import java.util.regex.Matcher;

import com.intellij.openapi.module.Module;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiAnnotationMemberValue;
import com.intellij.psi.PsiArrayInitializerMemberValue;
import com.intellij.psi.PsiArrayType;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiEnumConstant;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiJvmModifiersOwner;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.PsiType;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.diagnostics.JavaDiagnosticsContext;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.validators.JavaASTValidator;
Expand All @@ -38,18 +24,22 @@
import com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.graphql.TypeSystemDirectiveLocation;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;
import org.eclipse.lsp4j.DiagnosticSeverity;
import org.jetbrains.annotations.NotNull;

import java.text.MessageFormat;
import java.util.logging.Logger;

import static com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.AnnotationUtils.getAnnotation;
import static com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.AnnotationUtils.isMatchAnnotation;

/**
* Diagnostics for microprofile-graphql.
*
* <p>
* TODO: We currently don't check directives on input/output objects and their properties, because
* it's not trivial to determine whether a class is used as an input, or an output, or both. That
* will possibly require building the whole GraphQL schema on-the-fly, which might be too expensive.
*
* @see https://download.eclipse.org/microprofile/microprofile-graphql-1.0/microprofile-graphql.html
* @see <a href="https://download.eclipse.org/microprofile/microprofile-graphql-1.0/microprofile-graphql.html">MicroProfile GraphQL</a>
*/
public class MicroProfileGraphQLASTValidator extends JavaASTValidator {

Expand All @@ -67,7 +57,7 @@ public class MicroProfileGraphQLASTValidator extends JavaASTValidator {
@Override
public boolean isAdaptedForDiagnostics(JavaDiagnosticsContext context) {
Module javaProject = context.getJavaProject();
if(PsiTypeUtils.findType(javaProject, MicroProfileGraphQLConstants.QUERY_ANNOTATION) == null) {
if (PsiTypeUtils.findType(javaProject, MicroProfileGraphQLConstants.QUERY_ANNOTATION) == null) {
return false;
}
// void GraphQL operations are allowed in Quarkus 3.1 and higher
Expand All @@ -81,9 +71,9 @@ public boolean isAdaptedForDiagnostics(JavaDiagnosticsContext context) {
}

@Override
public void visitMethod(PsiMethod node) {
public void visitMethod(@NotNull PsiMethod node) {
validateDirectivesOnMethod(node);
if(!allowsVoidReturnFromOperations) {
if (!allowsVoidReturnFromOperations) {
validateNoVoidReturnedFromOperations(node);
}
validateMultiReturnTypeFromSubscriptions(node);
Expand All @@ -92,7 +82,7 @@ public void visitMethod(PsiMethod node) {
}

@Override
public void visitClass(PsiClass node) {
public void visitClass(@NotNull PsiClass node) {
validateDirectivesOnClass(node);
super.visitClass(node);
}
Expand All @@ -115,13 +105,13 @@ private void validateDirectivesOnMethod(PsiMethod node) {

private void validateDirectivesOnClass(PsiClass node) {
// a class with @GraphQLApi may only have directives allowed on SCHEMA
if(getAnnotation(node, MicroProfileGraphQLConstants.GRAPHQL_API_ANNOTATION) != null) {
if (getAnnotation(node, MicroProfileGraphQLConstants.GRAPHQL_API_ANNOTATION) != null) {
validateDirectives(node, TypeSystemDirectiveLocation.SCHEMA);
}
// if an interface has a `@Union` annotation, it may only have directives allowed on UNION
// otherwise it may only have directives allowed on INTERFACE
if (node.isInterface()) {
if(getAnnotation(node, MicroProfileGraphQLConstants.UNION_ANNOTATION) != null) {
if (getAnnotation(node, MicroProfileGraphQLConstants.UNION_ANNOTATION) != null) {
validateDirectives(node, TypeSystemDirectiveLocation.UNION);
} else {
validateDirectives(node, TypeSystemDirectiveLocation.INTERFACE);
Expand All @@ -132,7 +122,7 @@ else if (node.isEnum()) {
validateDirectives(node, TypeSystemDirectiveLocation.ENUM);
// enum values may only have directives allowed on ENUM_VALUE
for (PsiField field : node.getFields()) {
if(field instanceof PsiEnumConstant) {
if (field instanceof PsiEnumConstant) {
validateDirectives(field, TypeSystemDirectiveLocation.ENUM_VALUE);
}
}
Expand Down Expand Up @@ -199,12 +189,11 @@ private PsiClass getDirectiveDeclaration(PsiAnnotation annotation) {

private void validateNoVoidReturnedFromOperations(PsiMethod node) {
// ignore constructors, and non-void methods for now, it's faster than iterating through all annotations
if (node.getReturnTypeElement() == null ||
!PsiType.VOID.equals(node.getReturnType())) {
if (node.getReturnTypeElement() == null || !PsiTypeUtils.isVoidReturnType(node)) {
return;
}
for (PsiAnnotation annotation : node.getAnnotations()) {
if (isMatchAnnotation(annotation, MicroProfileGraphQLConstants.QUERY_ANNOTATION) ) {
if (isMatchAnnotation(annotation, MicroProfileGraphQLConstants.QUERY_ANNOTATION)) {
super.addDiagnostic(NO_VOID_MESSAGE, //
MicroProfileGraphQLConstants.DIAGNOSTIC_SOURCE, //
node.getReturnTypeElement(), //
Expand All @@ -224,12 +213,12 @@ private void validateNoVoidReturnedFromOperations(PsiMethod node) {
* A method annotated with `@Subscription` must return a `Multi` or `Flow.Publisher`.
*/
private void validateMultiReturnTypeFromSubscriptions(PsiMethod node) {
if(node.getReturnType() == null) {
if (node.getReturnType() == null) {
return;
}
for (PsiAnnotation annotation : node.getAnnotations()) {
if (isMatchAnnotation(annotation, MicroProfileGraphQLConstants.SUBSCRIPTION_ANNOTATION)) {
if(node.getReturnType().equals(PsiType.VOID)) {
if (PsiTypeUtils.isVoidReturnType(node)) {
super.addDiagnostic(SUBSCRIPTION_MUST_RETURN_MULTI,
MicroProfileGraphQLConstants.DIAGNOSTIC_SOURCE,
node.getReturnTypeElement(),
Expand Down Expand Up @@ -258,7 +247,7 @@ private void validateMultiReturnTypeFromSubscriptions(PsiMethod node) {
* a `Multi` or `Flow.Publisher` type.
*/
private void validateNoMultiReturnTypeFromQueriesAndMutations(PsiMethod node) {
if(node.getReturnType() == null) {
if (node.getReturnType() == null) {
return;
}
for (PsiAnnotation annotation : node.getAnnotations()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private void collectClassesAndInterfaces(PsiPackage packageRoot, List<JavaTypeIn
}
} else {
// Search classes by the name (without the package name)
PrefixMatcher matcher = new CamelHumpMatcher(typeName, true, false);
PrefixMatcher matcher = new CamelHumpMatcher(typeName, true);
matcher = new BetterPrefixMatcher(matcher, Integer.MIN_VALUE);

final List<String> existing = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,35 +52,6 @@ public static PsiClass findType(Module module, String name) {
GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module));
}

/**
* Returns the resolved type name of the <code>javaElement</code> and null
* otherwise
*
* @param javaElement the Java element
* @return the resolved type name of the <code>javaElement</code> and null
* otherwise
*/
public static String getResolvedTypeName(PsiElement javaElement) {
if (javaElement instanceof PsiVariable) {
return getResolvedTypeName((PsiLocalVariable) javaElement);
} else if (javaElement instanceof PsiField) {
return getResolvedTypeName((PsiField) javaElement);
}
return null;
}

/**
* Returns the resolved type name of the given <code>localVar</code> and null
* otherwise
*
* @param localVar the local variable
* @return the resolved type name of the given <code>localVar</code> and null
* otherwise
*/
public static String getResolvedTypeName(PsiLocalVariable localVar) {
return localVar.getType().getCanonicalText();
}

/**
* Returns the resolved type name of the given <code>field</code> and null
* otherwise
Expand All @@ -93,10 +64,6 @@ public static String getResolvedTypeName(PsiField field) {
return field.getType().getCanonicalText();
}

public static String getPropertyType(PsiClass psiClass, String typeName) {
return psiClass != null ? psiClass.getQualifiedName() : typeName;
}

/**
* Returns true if the given <code>javaElement</code> is from a Java binary, and
* false otherwise
Expand Down Expand Up @@ -216,40 +183,40 @@ public static PsiClass findType(String className, Module javaProject, ProgressIn
* Return true if member is static, and false otherwise
*
* @param member the member to check for static
* @return
* @return true if member is static, and false otherwise
*/
public static boolean isStaticMember(PsiMember member) {
return member.getModifierList().hasExplicitModifier(PsiModifier.STATIC);
return member.getModifierList() != null && member.getModifierList().hasExplicitModifier(PsiModifier.STATIC);
}

/**
* Return true if member is private, and false otherwise
*
* @param member the member to check for private access modifier
* @return
* @return true if member is private, and false otherwise
*/
public static boolean isPrivateMember(PsiMember member) {
return member.getModifierList().hasExplicitModifier(PsiModifier.PRIVATE);
return member.getModifierList() != null && member.getModifierList().hasExplicitModifier(PsiModifier.PRIVATE);
}

/**
* Return true if member is public, and false otherwise
*
* @param member the member to check for public access modifier
* @return
* @return true if member is public, and false otherwise
*/
public static boolean isPublicMember(PsiMember member) {
return member.getModifierList().hasExplicitModifier(PsiModifier.PUBLIC);
return member.getModifierList() != null && member.getModifierList().hasExplicitModifier(PsiModifier.PUBLIC);
}

/**
* Return true if method returns `void`, and false otherwise
*
* @param method the method to check return value of
* @return
* @return true if method returns `void`, and false otherwise
*/
public static boolean isVoidReturnType(PsiMethod method) {
return PsiType.VOID.equals(method.getReturnType());
return PsiTypes.voidType().equals(method.getReturnType());
}

/**
Expand Down
Loading

0 comments on commit f4d5075

Please sign in to comment.