Skip to content

Commit

Permalink
feat: validate BuildItem classes
Browse files Browse the repository at this point in the history
Signed-off-by: Fred Bricon <[email protected]>
  • Loading branch information
fbricon committed Sep 15, 2023
1 parent 870e674 commit 7be13c3
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
*******************************************************************************/
package com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils;

import com.intellij.codeInsight.daemon.impl.analysis.HighlightNamesUtil;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.IPsiUtils;
import org.eclipse.lsp4j.Range;
import org.jetbrains.annotations.NotNull;

/**
* Position utilities.
Expand Down Expand Up @@ -58,12 +60,23 @@ public static Range toNameRange(PsiClass type, IPsiUtils utils) {
* @param method the java type.
* @param utils the JDT utilities.
* @return the LSP range for the given method name.
* @throws JavaModelException
*/
public static Range toNameRange(PsiMethod method, IPsiUtils utils) {
PsiFile openable = method.getContainingFile();
TextRange sourceRange = method.getNameIdentifier().getTextRange();
return utils.toRange(openable, sourceRange.getStartOffset(), sourceRange.getLength());
}

/**
* Returns the LSP Range for the class declaration of the given type
*
* @param type the java type.
* @param utils the JDT utilities.
* @return the LSP range the class declaration of the given type.
*/
public static Range toClassDeclarationRange(@NotNull PsiClass type, @NotNull IPsiUtils utils) {
PsiFile openable = type.getContainingFile();
TextRange sourceRange = HighlightNamesUtil.getClassDeclarationTextRange(type);
return utils.toRange(openable, sourceRange.getStartOffset(), sourceRange.getLength());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*******************************************************************************
* 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.quarkus;

import com.intellij.DynamicBundle;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.PropertyKey;

import java.util.function.Supplier;

/**
* Quarkus messages bundle.
*/
public final class QuarkusBundle extends DynamicBundle {

@NonNls public static final String BUNDLE = "messages.QuarkusBundle";
private static final QuarkusBundle INSTANCE = new QuarkusBundle();

private QuarkusBundle() {
super(BUNDLE);
}

@NotNull
public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
return INSTANCE.getMessage(key, params);
}

@NotNull
public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) {
return INSTANCE.getLazyMessage(key, params);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.redhat.devtools.intellij.quarkus.psi.internal.builditems;

import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.diagnostics.IJavaErrorCode;

public enum QuarkusBuildItemErrorCode implements IJavaErrorCode {

InvalidModifierBuildItem;

@Override
public String getCode() {
return name();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*******************************************************************************
* 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.quarkus.psi.internal.validators;

import com.intellij.openapi.module.Module;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.util.InheritanceUtil;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.diagnostics.IJavaDiagnosticsParticipant;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.java.diagnostics.JavaDiagnosticsContext;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.PositionUtils;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.PsiTypeUtils;
import com.redhat.devtools.intellij.quarkus.QuarkusBundle;
import com.redhat.devtools.intellij.quarkus.psi.internal.builditems.QuarkusBuildItemErrorCode;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.DiagnosticSeverity;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4mp.commons.DocumentFormat;

import java.util.ArrayList;
import java.util.List;

public class QuarkusBuildItemDiagnosticsParticipant implements IJavaDiagnosticsParticipant {

private static final String BUILD_ITEM= "io.quarkus.builder.item.BuildItem";

@Override
public boolean isAdaptedForDiagnostics(JavaDiagnosticsContext context) {
// Collection of diagnostics for Quarkus Build Items is done only if
// io.quarkus.builder.item.BuildItem is on the classpath
Module javaProject = context.getJavaProject();
return PsiTypeUtils.findType(javaProject, BUILD_ITEM) != null;
}

@Override
public List<Diagnostic> collectDiagnostics(JavaDiagnosticsContext context) {
PsiFile typeRoot = context.getTypeRoot();
PsiElement[] elements = typeRoot.getChildren();
List<Diagnostic> diagnostics = new ArrayList<>();
collectDiagnostics(elements, diagnostics, context);
return diagnostics;
}

private static void collectDiagnostics(PsiElement[] elements, List<Diagnostic> diagnostics,
JavaDiagnosticsContext context) {
for (PsiElement element : elements) {
if (element instanceof PsiClass) {
PsiClass psiClass = (PsiClass) element;
if (isBuildItem(psiClass)) {
validateBuildItem(psiClass, diagnostics, context);
}
}
}
}

private static boolean isBuildItem(PsiClass type) {
return InheritanceUtil.isInheritor(type, BUILD_ITEM);
}

private static void validateBuildItem(PsiClass psiClass, List<Diagnostic> diagnostics, JavaDiagnosticsContext context) {
if (psiClass.hasModifierProperty(PsiModifier.FINAL)
|| psiClass.hasModifierProperty(PsiModifier.ABSTRACT)
) {
return;
}
Range range = PositionUtils.toClassDeclarationRange(psiClass, context.getUtils());
Diagnostic d = context.createDiagnostic(context.getUri(),
createDiagnosticMessage(psiClass, context.getDocumentFormat()),
range, "quarkus",
QuarkusBuildItemErrorCode.InvalidModifierBuildItem,
DiagnosticSeverity.Error
);
diagnostics.add(d);
}

private static String createDiagnosticMessage(PsiClass classType, DocumentFormat documentFormat) {
String quote = DocumentFormat.Markdown.equals(documentFormat)?"`":"'";
return QuarkusBundle.message("quarkus.validation.buildItem.invalid", classType.getQualifiedName(), quote);
}
}
1 change: 1 addition & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@
<javaDiagnosticsParticipant implementation="com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.health.java.MicroProfileHealthDiagnosticsParticipant"/>
<javaDiagnosticsParticipant implementation="com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.restclient.java.MicroProfileRestClientDiagnosticsParticipant"/>
<javaDiagnosticsParticipant implementation="com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.metrics.java.MicroProfileMetricsDiagnosticsParticipant"/>
<javaDiagnosticsParticipant implementation="com.redhat.devtools.intellij.quarkus.psi.internal.validators.QuarkusBuildItemDiagnosticsParticipant"/>

<projectLabelProvider implementation="com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.core.providers.MicroProfileProjectLabelProvider"/>

Expand Down
14 changes: 14 additions & 0 deletions src/main/resources/messages/QuarkusBundle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
###############################################################################
# Copyright (c) 2023 Red Hat Inc. and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v2.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v20.html
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# Red Hat Inc. - initial API and implementation
###############################################################################

quarkus.validation.buildItem.invalid=BuildItem class {1}{0}{1} must either be declared final or abstract

0 comments on commit 7be13c3

Please sign in to comment.