org.netbeans.modules.java.hints.UtilityClass Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.java.hints;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.tree.StatementTree;
import com.sun.source.tree.Tree;
import com.sun.source.tree.Tree.Kind;
import com.sun.source.tree.TypeParameterTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath;
import java.util.Collections;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.TreePathHandle;
import org.netbeans.api.java.source.TreeUtilities;
import org.netbeans.api.java.source.WorkingCopy;
import org.netbeans.spi.editor.hints.ErrorDescription;
import org.netbeans.spi.editor.hints.Severity;
import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
import org.netbeans.spi.java.hints.Hint;
import org.netbeans.spi.java.hints.HintContext;
import org.netbeans.spi.java.hints.JavaFix;
import org.netbeans.spi.java.hints.TriggerTreeKind;
import org.openide.util.NbBundle;
/**
*
* @author Jaroslav tulach
*/
public class UtilityClass {
@Hint(id="org.netbeans.modules.java.hints.UtilityClass_1", displayName="#MSG_UtilityClass", description="#HINT_UtilityClass", category="api", enabled=false, severity=Severity.VERIFIER, suppressWarnings="UtilityClassWithoutPrivateConstructor")
@TriggerTreeKind(Kind.CLASS)
public static ErrorDescription utilityClass(HintContext ctx) {
CompilationInfo compilationInfo = ctx.getInfo();
TreePath treePath = ctx.getPath();
Element e = compilationInfo.getTrees().getElement(treePath);
if (e == null) {
return null;
}
if (!isUtilityClass(compilationInfo, e)) return null;
for (ExecutableElement c : ElementFilter.constructorsIn(e.getEnclosedElements())) {
if (!compilationInfo.getElementUtilities().isSynthetic(c)) {
return null;
}
}
return ErrorDescriptionFactory.forName(ctx,
treePath,
NbBundle.getMessage(UtilityClass.class, "MSG_UtilityClass"),
new FixImpl(true,
TreePathHandle.create(e, compilationInfo)
).toEditorFix());
}
@Hint(id="org.netbeans.modules.java.hints.UtilityClass_2", displayName="#MSG_PublicConstructor", description="#HINT_PublicConstructor", category="api", enabled=false, severity=Severity.HINT, suppressWarnings="UtilityClassWithPublicConstructor")
@TriggerTreeKind(Kind.METHOD)
public static ErrorDescription constructor(HintContext ctx) {
CompilationInfo compilationInfo = ctx.getInfo();
TreePath treePath = ctx.getPath();
Element e = compilationInfo.getTrees().getElement(treePath);
if (e == null) {
return null;
}
if ( e.getKind() != ElementKind.CONSTRUCTOR
|| compilationInfo.getElementUtilities().isSynthetic(e)
|| (!e.getModifiers().contains(Modifier.PROTECTED) && !e.getModifiers().contains(Modifier.PUBLIC))) {
return null;
}
if (!isUtilityClass(compilationInfo, e.getEnclosingElement())) return null;
return ErrorDescriptionFactory.forName(ctx,
treePath,
NbBundle.getMessage(UtilityClass.class, "MSG_PublicConstructor"),
new FixImpl(false,
TreePathHandle.create(e, compilationInfo)
).toEditorFix());
}
private static boolean isMainMethod(ExecutableElement m) {
return m.getModifiers().contains(Modifier.STATIC) &&
m.getSimpleName().contentEquals("main") &&
(m.getReturnType().getKind() == TypeKind.VOID) &&
(m.getParameters().size() == 1) &&
(m.getParameters().get(0).asType().toString().equals("java.lang.String[]"));
}
private static boolean isUtilityClass(CompilationInfo compilationInfo, Element clazz) {
if (clazz.getKind() != ElementKind.CLASS) {
return false;
}
TypeMirror supr = ((TypeElement) clazz).getSuperclass();
if (supr == null) {
return false;
}
Element superElem = compilationInfo.getTypes().asElement(supr);
if (superElem instanceof TypeElement) {
Name superName = compilationInfo.getElements().getBinaryName((TypeElement) superElem);
if (superName != null && !superName.contentEquals("java.lang.Object")) {
return false;
}
}
int cnt = 0;
for (Element m : clazz.getEnclosedElements()) {
if (m.getKind() == ElementKind.METHOD && isMainMethod(((ExecutableElement) m))) return false;
if (m.getKind() == ElementKind.METHOD || m.getKind() == ElementKind.FIELD) {
if (!m.getModifiers().contains(Modifier.STATIC)) return false;
cnt++;
}
}
return cnt > 0;
}
private static final class FixImpl extends JavaFix {
private boolean clazz;
public FixImpl(boolean clazz, TreePathHandle handle) {
super(handle);
this.clazz = clazz;
}
public String getText() {
return NbBundle.getMessage(UtilityClass.class, clazz ? "MSG_PrivateConstructor" : "MSG_MakePrivate"); // NOI18N
}
@Override public String toString() {
return "FixUtilityClass"; // NOI18N
}
@Override
protected void performRewrite(TransformationContext ctx) {
WorkingCopy wc = ctx.getWorkingCopy();
TreePath tp = ctx.getPath();
Element e = wc.getTrees().getElement(tp);
if (e == null) {
return;
}
Tree outer = wc.getTrees().getTree(e);
if (clazz) {
if (outer == null || !TreeUtilities.CLASS_TREE_KINDS.contains(outer.getKind())) {
return;
}
ClassTree cls = (ClassTree)outer;
ModifiersTree modifiers = wc.getTreeMaker().Modifiers(Collections.singleton(Modifier.PRIVATE));
MethodTree m = wc.getTreeMaker().Constructor(
modifiers,
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
wc.getTreeMaker().Block(Collections.emptyList(), false)
);
wc.rewrite(cls, wc.getTreeMaker().addClassMember(cls, m));
} else {
if (outer == null || outer.getKind() != Kind.METHOD) {
return;
}
MethodTree met = (MethodTree)outer;
ModifiersTree modifiers = wc.getTreeMaker().Modifiers(Collections.singleton(Modifier.PRIVATE), met.getModifiers().getAnnotations());
wc.rewrite(met.getModifiers(), modifiers);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy