# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: D:\ws\main # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: java.hints/src/org/netbeans/modules/java/hints/errors/Bundle.properties --- java.hints/src/org/netbeans/modules/java/hints/errors/Bundle.properties +++ java.hints/src/org/netbeans/modules/java/hints/errors/Bundle.properties @@ -105,8 +105,8 @@ # 1: interface # 2: enum # 3: annotation type -FIX_CreateClassInPackage=Create {2,choice,0#class|1#interface|2#enum|3#annotation type} "{0}" in package {1} -FIX_CreateClassAndCtorInPackage=Create {2,choice,0#class|1#interface|2#enum|3#annotation type} "{0}" with constructor "{0}({3})" in package {1} +FIX_CreateClassInPackage=Create {2,choice,0#class|1#interface|2#enum|3#annotation type} "{0}" in package {1} ({3}) +FIX_CreateClassAndCtorInPackage=Create {2,choice,0#class|1#interface|2#enum|3#annotation type} "{0}" with constructor "{0}({3})" in package {1} ({4}) #{0}: new class simple name #{1}: target class name Index: java.hints/src/org/netbeans/modules/java/hints/errors/CreateClassFix.java --- java.hints/src/org/netbeans/modules/java/hints/errors/CreateClassFix.java +++ java.hints/src/org/netbeans/modules/java/hints/errors/CreateClassFix.java @@ -68,6 +68,7 @@ import org.netbeans.api.java.source.WorkingCopy; import org.netbeans.modules.java.hints.infrastructure.ErrorHintsProvider; import org.netbeans.spi.editor.hints.ChangeInfo; +import org.netbeans.spi.editor.hints.EnhancedFix; import org.netbeans.spi.editor.hints.Fix; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; @@ -79,11 +80,12 @@ * * @author Jan lahoda */ -public abstract class CreateClassFix implements Fix { +public abstract class CreateClassFix implements EnhancedFix { protected Set modifiers; protected List argumentTypes; //if a specific constructor should be created protected List argumentNames; //dtto. + private Integer prio; private List superTypes; protected ElementKind kind; private int numTypeParameters; @@ -243,22 +245,43 @@ public abstract String toDebugString(CompilationInfo info); + /** + * Will be used in {@link #getSortText()} + * + * @param prio + */ + protected void setPriority(Integer prio) { + this.prio = prio; + } + + @Override + public CharSequence getSortText() { + //see usage at org.netbeans.modules.editor.hints.FixData.getSortText + if (null == prio) { + return getText(); + } + + return String.format("%04d-%s", prio, getText()); + } + static final class CreateOuterClassFix extends CreateClassFix { private FileObject targetSourceRoot; private String packageName; + private String relativePath; private String simpleName; - public CreateOuterClassFix(CompilationInfo info, FileObject targetSourceRoot, String packageName, String simpleName, Set modifiers, List argumentTypes, List argumentNames, TypeMirror superType, ElementKind kind, int numTypeParameters) { + public CreateOuterClassFix(CompilationInfo info, FileObject targetSourceRoot, String packageName, String simpleName, Set modifiers, List argumentTypes, List argumentNames, TypeMirror superType, ElementKind kind, int numTypeParameters, String relativePath) { super(info, modifiers, argumentTypes, argumentNames, superType, kind, numTypeParameters); this.targetSourceRoot = targetSourceRoot; this.packageName = packageName; this.simpleName = simpleName; + this.relativePath = relativePath; } public String getText() { if (argumentNames == null || argumentNames.isEmpty()) - return NbBundle.getMessage(CreateClassFix.class, "FIX_CreateClassInPackage", simpleName, packageName, valueForBundle(kind)); + return NbBundle.getMessage(CreateClassFix.class, "FIX_CreateClassInPackage", simpleName, packageName, valueForBundle(kind), relativePath); else { StringBuffer buf = new StringBuffer(); for (TypeMirror tm : argumentTypeMirrors) { @@ -266,7 +289,7 @@ buf.append(","); } String ctorParams = buf.toString(); - Object[] params = new Object[] {simpleName, packageName, valueForBundle(kind), ctorParams.substring(0, ctorParams.length() - 1)}; + Object[] params = new Object[] {simpleName, packageName, valueForBundle(kind), ctorParams.substring(0, ctorParams.length() - 1), relativePath}; return NbBundle.getMessage(CreateClassFix.class, "FIX_CreateClassAndCtorInPackage", params); } } Index: java.hints/src/org/netbeans/modules/java/hints/errors/CreateElement.java --- java.hints/src/org/netbeans/modules/java/hints/errors/CreateElement.java +++ java.hints/src/org/netbeans/modules/java/hints/errors/CreateElement.java @@ -60,10 +60,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -77,12 +79,15 @@ import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeVariable; -import org.netbeans.api.java.classpath.ClassPath; -import org.netbeans.api.java.source.ClasspathInfo.PathKind; +import org.netbeans.api.java.project.JavaProjectConstants; import org.netbeans.api.java.source.CompilationInfo; import org.netbeans.api.java.source.ElementHandle; import org.netbeans.api.java.source.SourceUtils; import org.netbeans.api.java.source.TreeUtilities; +import org.netbeans.api.project.FileOwnerQuery; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.SourceGroup; +import org.netbeans.api.project.SourceGroupModifier; import org.netbeans.modules.java.hints.errors.CreateClassFix.CreateInnerClassFix; import org.netbeans.modules.java.hints.errors.CreateClassFix.CreateOuterClassFix; import org.netbeans.modules.java.hints.infrastructure.ErrorHintsProvider; @@ -96,14 +101,18 @@ import static org.netbeans.modules.java.hints.errors.CreateElementUtilities.*; import org.netbeans.modules.java.hints.errors.ErrorFixesFakeHint.FixKind; import org.netbeans.modules.java.hints.errors.Utilities.MethodArguments; +import org.openide.filesystems.FileUtil; import org.openide.util.Pair; /** * * @author Jan Lahoda + * @author markiewb (contributions) */ public final class CreateElement implements ErrorRule { private static final Logger LOG = Logger.getLogger(CreateElement.class.getName()); + private static final int PRIO_TESTSOURCEGROUP = 500; + private static final int PRIO_MAINSOURCEGROUP = 1000; /** Creates a new instance of CreateElement */ public CreateElement() { @@ -518,6 +527,67 @@ return Collections.singletonList(new CreateMethodFix(info, simpleName, modifiers, target, returnType, formalArguments.parameterTypes, formalArguments.parameterNames, formalArguments.typeParameterTypes, formalArguments.typeParameterNames, targetFile)); } + /** + * Gets the possible sourceGroups based on the current file. + *
    + *
  • If it is a file from src/main/java it will return only + * src/main/java.
  • + *
  • If it is a file from src/test/java it will return src/main/java AND + * src/test/java. (src/test/java will have a higher prio than src/main/java)
  • + *
+ * + * @param fileObject + * @return map of sourceGroup and its hint-priority + */ + private static Map getPossibleSourceGroups(FileObject fileObject) { + Boolean isInTestSources = isInTestSources(fileObject); + if (null == isInTestSources) { + return Collections.emptyMap(); + } + + Project p = FileOwnerQuery.getOwner(fileObject); + if (null == p) { + return Collections.emptyMap(); + } + + SourceGroup sourceGroup = SourceGroupModifier.createSourceGroup(p, JavaProjectConstants.SOURCES_TYPE_JAVA, JavaProjectConstants.SOURCES_HINT_MAIN); + SourceGroup testSourceGroup = SourceGroupModifier.createSourceGroup(p, JavaProjectConstants.SOURCES_TYPE_JAVA, JavaProjectConstants.SOURCES_HINT_TEST); + + Map list = new HashMap<>(); + if (isInTestSources) { + //in test sources (f.e. src/test/java) -> return main sources and test sources + if (null != sourceGroup) { + list.put(sourceGroup, PRIO_MAINSOURCEGROUP); + } + + if (null != testSourceGroup) { + //test source group has a higher prio -> before main source group + list.put(testSourceGroup, PRIO_TESTSOURCEGROUP); + } + + } else { + //in sources (f.e. src/main/java) -> return only main sources + if (null != sourceGroup) { + list.put(sourceGroup, PRIO_MAINSOURCEGROUP); + } + } + return list; + } + + private static Boolean isInTestSources(FileObject fileObject) { + Project p = FileOwnerQuery.getOwner(fileObject); + if (null == p) { + return null; + } + + SourceGroup testSourceGroup = SourceGroupModifier.createSourceGroup(p, JavaProjectConstants.SOURCES_TYPE_JAVA, JavaProjectConstants.SOURCES_HINT_TEST); + boolean isInTestSources = false; + if (null != testSourceGroup) { + isInTestSources = FileUtil.isParentOf(testSourceGroup.getRootFolder(), fileObject); + } + return isInTestSources; + } + private static List prepareCreateOuterClassFix(CompilationInfo info, TreePath invocation, Element source, Set modifiers, String simpleName, List realArguments, TypeMirror superType, ElementKind kind, int numTypeParameters) { Pair, List> formalArguments = invocation != null ? Utilities.resolveArguments(info, invocation, realArguments, null) : Pair., List>of(null, null); @@ -528,19 +598,37 @@ if (superType != null && (superType.getKind() == TypeKind.OTHER)) { return Collections.emptyList(); } + final FileObject fileObject = info.getFileObject(); + Project p = FileOwnerQuery.getOwner(fileObject); + if (null == p) { + return Collections.emptyList(); + } + List fixes = new ArrayList<>(); - ClassPath cp = info.getClasspathInfo().getClassPath(PathKind.SOURCE); - FileObject root = cp.findOwnerRoot(info.getFileObject()); + FileObject projectDirectory = p.getProjectDirectory(); - if (root == null) { //File not part of any project - return Collections.emptyList(); - } + for (Map.Entry entrySet : getPossibleSourceGroups(fileObject).entrySet()) { + SourceGroup sourceGroup = entrySet.getKey(); + Integer value = entrySet.getValue(); + final FileObject sourceGroupRoot = sourceGroup.getRootFolder(); + String relativePath = FileUtil.getRelativePath(projectDirectory, sourceGroupRoot); + + if (null != relativePath) { PackageElement packageElement = (PackageElement) (source instanceof PackageElement ? source : info.getElementUtilities().outermostTypeElement(source).getEnclosingElement()); - return Collections.singletonList(new CreateOuterClassFix(info, root, packageElement.getQualifiedName().toString(), simpleName, modifiers, formalArguments.first(), formalArguments.second(), superType, kind, numTypeParameters)); + final CreateOuterClassFix fix = new CreateOuterClassFix(info, sourceGroupRoot, packageElement.getQualifiedName().toString(), simpleName, modifiers, formalArguments.first(), formalArguments.second(), superType, kind, numTypeParameters, relativePath); + fix.setPriority(value); + + fixes.add(fix); } + } + + + return fixes; + } + private static List prepareCreateInnerClassFix(CompilationInfo info, TreePath invocation, TypeElement target, Set modifiers, String simpleName, List realArguments, TypeMirror superType, ElementKind kind, int numTypeParameters) { Pair, List> formalArguments = invocation != null ? Utilities.resolveArguments(info, invocation, realArguments, target) : Pair., List>of(null, null);