Skip to content
Snippets Groups Projects
Commit e2a25dff authored by Tobias Ask's avatar Tobias Ask
Browse files

Merge branch '9-validate-correspondence-between-fxml-and-java' into 'master'

Resolve "Validate correspondence between FXML and Java"

Closes #9

See merge request !15
parents 1376235d 73763db6
No related branches found
No related tags found
1 merge request!15Resolve "Validate correspondence between FXML and Java"
Pipeline #
Showing
with 652 additions and 13 deletions
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-9">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="resources"/>
<classpathentry kind="src" path="src/"/>
<classpathentry kind="src" path="resources/"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.codegen.targetPlatform=9
org.eclipse.jdt.core.compiler.compliance=9
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.compiler.source=9
......@@ -12,5 +12,7 @@ Require-Bundle: no.tobask.sb4e;bundle-version="0.9.0",
org.eclipse.ui;bundle-version="3.109.0"
Import-Package: org.eclipse.core.resources,
org.eclipse.core.runtime;version="3.5.0",
org.eclipse.e4.core.contexts;version="1.6.0",
org.eclipse.jdt.core,
org.eclipse.jdt.core.compiler,
org.eclipse.swt.widgets
......@@ -2,7 +2,7 @@
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane xmlns:fx="http://javafx.com/fxml/1">
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" fx:id="mainWindow">
<!-- TODO Add Nodes -->
</AnchorPane>
package no.tobask.sb4e.test;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.jdt.core.compiler.BuildContext;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
import org.mockito.ArgumentCaptor;
import javafx.embed.swt.FXCanvas;
import no.tobask.sb4e.FxControllerProblem;
import no.tobask.sb4e.FxControllerValidator;
import no.tobask.sb4e.FxmlDocumentListener;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.*;
import java.net.MalformedURLException;
public class FxControllerValidatorTest {
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject("testProject");
@Rule
public final ExternalResource projectResource = new JavaProjectResource(project);
@Test
public void buildStarting_discoversAndReportsProblems_whenThereAreProblems() throws MalformedURLException {
FxControllerValidator validator = new FxControllerValidator();
FxmlDocumentListener documentListener = mock(FxmlDocumentListener.class);
validator.setDocumentListener(documentListener);
BuildContext buildContext = mock(BuildContext.class);
IFile controller = project.getFolder("src").getFile("TestController.java");
IFile document = project.getFolder("src").getFile("Test.fxml");
when(buildContext.getFile()).thenReturn(controller);
when(documentListener.isAssignedController("src.TestController")).thenReturn(true);
when(documentListener.getDocument("src.TestController"))
.thenReturn(document.getLocationURI().toURL());
validator.buildStarting(new BuildContext[] {buildContext}, true);
ArgumentCaptor<CategorizedProblem[]> problems = ArgumentCaptor
.forClass(CategorizedProblem[].class);
verify(buildContext).recordNewProblems(problems.capture());
CategorizedProblem[] recordedProblems = problems.getValue();
assertEquals(1, recordedProblems.length);
FxControllerProblem problem = (FxControllerProblem) recordedProblems[0];
String[] arguments = problem.getArguments();
assertEquals(1, arguments.length);
assertEquals("mainWindow;javafx.scene.layout.AnchorPane", arguments[0]);
}
}
......@@ -48,12 +48,13 @@ public class JavaProjectResource extends ExternalResource {
private String getContents(String fileName) throws IOException {
StringBuilder builder = new StringBuilder();
InputStream stream = getClass().getResourceAsStream(fileName);
try (InputStream stream = getClass().getResourceAsStream(fileName)) {
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
}
return builder.toString();
}
......
......@@ -27,8 +27,13 @@ Import-Package: com.oracle.javafx.scenebuilder.kit.editor,
org.eclipse.e4.core.di.annotations;version="1.6.0",
org.eclipse.e4.ui.di,
org.eclipse.jdt.core,
org.eclipse.jdt.core.compiler,
org.eclipse.jdt.core.dom,
org.eclipse.jdt.launching
org.eclipse.jdt.core.dom.rewrite,
org.eclipse.jdt.launching,
org.eclipse.jdt.ui.text.java,
org.eclipse.jdt.ui.text.java.correction,
org.eclipse.text.edits
Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .
Export-Package: no.tobask.sb4e,
......
......@@ -80,5 +80,44 @@
class="no.tobask.sb4e.handlers.IncludeFxmlHandler">
</handler>
</extension>
<extension
point="org.eclipse.jdt.core.compilationParticipant">
<compilationParticipant
class="no.tobask.sb4e.FxControllerValidator"
id="FxControllerValidator"
createsProblems="true">
<managedMarker
markerType="no.tobask.sb4e.fxcontrollerproblemmarker">
</managedMarker>
</compilationParticipant>
</extension>
<extension
id="no.tobask.sb4e.fxcontrollerproblemmarker"
name="Fx controller problem"
point="org.eclipse.core.resources.markers">
<super
type="org.eclipse.jdt.core.problem">
</super>
</extension>
<extension
point="org.eclipse.jdt.ui.quickFixProcessors">
<quickFixProcessor
class="no.tobask.sb4e.MissingFxIdsFixer"
id="no.tobask.sb4e.missingfxidsfixer"
name="Missing fxids fixer">
<handledMarkerTypes>
<markerType
id="no.tobask.sb4e.fxcontrollerproblemmarker">
</markerType>
</handledMarkerTypes>
<enablement>
<with variable="projectNatures">
<iterate operator="or">
<equals value="org.eclipse.jdt.core.javanature"/>
</iterate>
</with>
</enablement>
</quickFixProcessor>
</extension>
</plugin>
package no.tobask.sb4e;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.ResourcesPlugin;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator {
private static BundleContext context;
private static FxmlDocumentListener fxmlDocumentListener =
new FxmlDocumentListener();
private static EclipseProjectsClassLoader classLoader = new EclipseProjectsClassLoader();
public static BundleContext getContext() {
return context;
}
public static FxmlDocumentListener getFxmlDocumentListener() {
return fxmlDocumentListener;
}
public static EclipseProjectsClassLoader getClassLoader() {
return classLoader;
}
/*
* (non-Javadoc)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext bundleContext) throws Exception {
Activator.context = bundleContext;
ResourcesPlugin.getWorkspace().addResourceChangeListener(fxmlDocumentListener,
IResourceChangeEvent.POST_CHANGE);
}
/*
......@@ -25,6 +40,7 @@ public class Activator implements BundleActivator {
*/
public void stop(BundleContext bundleContext) throws Exception {
Activator.context = null;
ResourcesPlugin.getWorkspace().removeResourceChangeListener(fxmlDocumentListener);
}
}
package no.tobask.sb4e;
import java.util.List;
import org.eclipse.core.resources.IResource;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
public class FxControllerProblem extends CategorizedProblem {
List<String> missingIds;
IResource resource;
public FxControllerProblem(List<String> missingIds, IResource resource) {
this.missingIds = missingIds;
this.resource = resource;
}
@Override
public String[] getArguments() {
return missingIds.toArray(new String[0]);
}
@Override
public int getID() {
return 1234;
}
@Override
public String getMessage() {
return "One or more fx:ids from associated FXML document do not have corresponding fields";
}
@Override
public char[] getOriginatingFileName() {
return resource.getName().toCharArray();
}
@Override
public int getSourceEnd() {
return -1;
}
@Override
public int getSourceLineNumber() {
return 1;
}
@Override
public int getSourceStart() {
return 0;
}
@Override
public boolean isError() {
return false;
}
@Override
public boolean isWarning() {
return true;
}
@Override
public void setSourceEnd(int sourceEnd) {
// TODO Auto-generated method stub
}
@Override
public void setSourceLineNumber(int lineNumber) {
// TODO Auto-generated method stub
}
@Override
public void setSourceStart(int sourceStart) {
// TODO Auto-generated method stub
}
@Override
public int getCategoryID() {
return CAT_POTENTIAL_PROGRAMMING_PROBLEM;
}
@Override
public String getMarkerType() {
return "no.tobask.sb4e.fxcontrollerproblemmarker";
}
}
package no.tobask.sb4e;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.resources.IResource;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.BuildContext;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CompilationParticipant;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.ui.PlatformUI;
import com.oracle.javafx.scenebuilder.kit.i18n.I18N;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMDocument;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMInstance;
import com.oracle.javafx.scenebuilder.kit.fxom.FXOMObject;
public class FxControllerValidator extends CompilationParticipant {
FxmlDocumentListener documentListener;
public FxControllerValidator() {
documentListener = Activator.getFxmlDocumentListener();
}
public void setDocumentListener(FxmlDocumentListener documentListener) {
this.documentListener = documentListener;
}
@Override
public void buildStarting(BuildContext[] files, boolean isBatch) {
for (BuildContext file : files) {
ICompilationUnit clazz = (ICompilationUnit) JavaCore.create(file.getFile());
String className = clazz.findPrimaryType().getFullyQualifiedName();
if (documentListener.isAssignedController(className)) {
URL documentLocation = documentListener.getDocument(className);
try {
String fxmlContent = FXOMDocument.readContentFromURL(documentLocation);
FXOMDocument document = new FXOMDocument(fxmlContent, documentLocation,
Activator.getClassLoader(), I18N.getBundle());
CompilationUnit ast = getAst(clazz);
file.recordNewProblems(getProblems(ast, document));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private CompilationUnit getAst(ICompilationUnit source) {
ASTParser parser = ASTParser.newParser(AST.JLS10);
parser.setSource(source);
parser.setResolveBindings(true);
return (CompilationUnit) parser.createAST(null);
}
@Override
public boolean isActive(IJavaProject project) {
return true;
}
private CategorizedProblem[] getProblems(CompilationUnit ast, FXOMDocument document) {
FxControllerVisitor visitor = new FxControllerVisitor();
ast.accept(visitor);
Map<String, String> controllerIds = visitor.getFxIds();
Map<String, FXOMObject> documentIds = document.collectFxIds();
List<String> missingIds = new ArrayList<>();
for (Entry<String, FXOMObject> id : documentIds.entrySet()) {
if (!controllerIds.containsKey(id.getKey())) {
FXOMObject fxomObject = id.getValue();
if (fxomObject instanceof FXOMInstance) {
FXOMInstance instance = (FXOMInstance) fxomObject;
missingIds.add(id.getKey() + ";" + instance.getDeclaredClass().getName());
}
}
}
if (!missingIds.isEmpty()) {
try {
IResource resource = ast.getTypeRoot().getCorrespondingResource();
return new CategorizedProblem[] {new FxControllerProblem(missingIds, resource)};
} catch (JavaModelException e) {
e.printStackTrace();
}
}
return new CategorizedProblem[0];
}
}
package no.tobask.sb4e;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IExtendedModifier;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.Type;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import javafx.fxml.FXML;
public class FxControllerVisitor extends ASTVisitor {
private Map<String, String> fxIds = new HashMap<>(); // var name -> type
private static final String FXML_ANNOTATION = FXML.class.getSimpleName();
@Override
public boolean visit(FieldDeclaration node) {
if (isFxIdCandidate(node)) {
Type type = node.getType();
ITypeBinding typeBinding = type.resolveBinding();
String typeName;
if (typeBinding != null) {
typeName = typeBinding.getQualifiedName();
} else {
if (type.isSimpleType()) {
typeName = ((SimpleType) type).getName().getFullyQualifiedName();
} else {
typeName = "UNKNOWN";
}
}
List<VariableDeclarationFragment> fragments = node.fragments();
String variableName = fragments.get(0).getName().toString();
fxIds.put(variableName, typeName);
}
return super.visit(node);
}
public Map<String, String> getFxIds() {
return fxIds;
}
private boolean isFxIdCandidate(FieldDeclaration field) {
List<IExtendedModifier> modifiers = field.modifiers();
if (Modifier.isPublic(field.getModifiers())) {
return true;
}
boolean hasFxmlAnnotation = false;
for (IExtendedModifier modifier : modifiers) {
if (modifier.isAnnotation()) {
String annotationName = ((Annotation) modifier).getTypeName().toString();
hasFxmlAnnotation = hasFxmlAnnotation || annotationName.equals(FXML_ANNOTATION);
}
}
return hasFxmlAnnotation;
}
}
package no.tobask.sb4e;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
public class FxmlDocumentListener implements IResourceChangeListener {
private Map<String, URL> controllers = new HashMap<>();
private boolean discoveryPerformed = false;
@Override
public void resourceChanged(IResourceChangeEvent event) {
try {
event.getDelta().accept(this::visit);
} catch (CoreException e) {
e.printStackTrace();
}
}
private boolean visit(IResourceDelta delta) {
IResource resource = delta.getResource();
if (resource != null && resource.getType() == IResource.FILE) {
IFile file = (IFile) resource;
String extension = file.getFileExtension();
if (extension != null && extension.equals("fxml")) {
try {
updateControllers(file);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
return true;
}
private void updateControllers(IFile fxmlFile) throws IOException {
String controller = getController(fxmlFile);
if (controller != null) {
if (fxmlFile.exists()) {
controllers.put(controller, fxmlFile.getLocationURI().toURL());
} else {
controllers.remove(controller);
}
}
}
private String getController(IFile fxmlFile) throws IOException {
try (InputStream inputStream = fxmlFile.getLocationURI().toURL().openStream()) {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
String[] tokens = line.split(" ");
for (String token : tokens) {
if (token.startsWith("fx:controller=")) {
return token.split("=")[1].replaceAll("[^a-zA-Z0-9\\.]", "");
}
}
}
}
return null;
}
public boolean isAssignedController(String controllerName) {
if (!discoveryPerformed) {
discoverControllers();
discoveryPerformed = true;
}
return controllers.containsKey(controllerName);
}
public URL getDocument(String controllerName) {
if (!discoveryPerformed) {
discoverControllers();
discoveryPerformed = true;
}
return controllers.get(controllerName);
}
private void discoverControllers() {
try {
for (IFile fxmlFile : getAllFxmlFilesInWorkspace()) {
updateControllers(fxmlFile);
}
} catch (JavaModelException | IOException e) {
e.printStackTrace();
}
}
private Collection<IFile> getAllFxmlFilesInWorkspace() throws JavaModelException {
Collection<IFile> files = new ArrayList<>();
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
for (IProject project : root.getProjects()) {
IJavaProject javaProject = JavaCore.create(project);
files.addAll(getFxmlFiles(javaProject));
}
return files;
}
private Collection<IFile> getFxmlFiles(IJavaProject javaProject) throws JavaModelException {
Collection<IFile> files = new ArrayList<>();
for (IPackageFragmentRoot pkgRoot : javaProject.getPackageFragmentRoots()) {
if (pkgRoot.getKind() == IPackageFragmentRoot.K_SOURCE) {
files.addAll(getFxmlFiles(pkgRoot));
}
}
return files;
}
private List<IFile> getFxmlFiles(IPackageFragmentRoot pkgRoot) throws JavaModelException {
List<IFile> files = new ArrayList<>();
for (IJavaElement child : pkgRoot.getChildren()) {
if (child.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
files.addAll(getFxmlFiles((IPackageFragment) child));
}
}
return files;
}
private List<IFile> getFxmlFiles(IPackageFragment pkg) throws JavaModelException {
List<IFile> files = new ArrayList<>();
for (Object resource : pkg.getNonJavaResources()) {
if (resource instanceof IFile) {
IFile file = (IFile) resource;
String extension = file.getFileExtension();
if (extension != null && extension.equals("fxml")) {
files.add(file);
}
}
}
return files;
}
}
package no.tobask.sb4e;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.ui.text.java.IInvocationContext;
import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
import org.eclipse.jdt.ui.text.java.IProblemLocation;
import org.eclipse.jdt.ui.text.java.IQuickFixProcessor;
import org.eclipse.jdt.ui.text.java.correction.ASTRewriteCorrectionProposal;
public class MissingFxIdsFixer implements IQuickFixProcessor {
@Override
public boolean hasCorrections(ICompilationUnit unit, int problemId) {
return problemId == 1234;
}
@Override
public IJavaCompletionProposal[] getCorrections(IInvocationContext context, IProblemLocation[] locations)
throws CoreException {
CompilationUnit unit = context.getASTRoot();
AST unitAst = unit.getAST();
TypeDeclaration type = (TypeDeclaration) unit.types().get(0);
ASTRewrite rewrite = ASTRewrite.create(unitAst);
ListRewrite bodyDeclarationsRewrite = rewrite.getListRewrite(type,
TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
ListRewrite importsRewrite = rewrite.getListRewrite(unit, CompilationUnit.IMPORTS_PROPERTY);
List<ImportDeclaration> imports = unit.imports();
List<String> importNames = imports.stream().map(i -> i.getName().getFullyQualifiedName())
.collect(Collectors.toList());
String[] missingIds = locations[0].getProblemArguments();
for (String missingId : missingIds) {
String[] parts = missingId.split(";");
String variableName = parts[0];
String variableType = parts[1];
String[] variableTypeParts = variableType.split("\\.");
VariableDeclarationFragment variableFragment = unitAst.newVariableDeclarationFragment();
variableFragment.setName(unitAst.newSimpleName(variableName));
FieldDeclaration field = unitAst.newFieldDeclaration(variableFragment);
String simpleTypeName = variableTypeParts[variableTypeParts.length-1];
field.setType(unitAst.newSimpleType(unitAst.newName(simpleTypeName)));
AST fieldAst = field.getAST();
MarkerAnnotation annotation = fieldAst.newMarkerAnnotation();
annotation.setTypeName(unitAst.newSimpleName("FXML"));
field.modifiers().add(annotation);
ASTNode lastField = getLastField(type);
if (lastField == null) {
bodyDeclarationsRewrite.insertFirst(field, null);
} else {
bodyDeclarationsRewrite.insertAfter(field, lastField, null);
}
if (!importNames.contains(variableType)) {
ImportDeclaration importDeclaration = unitAst.newImportDeclaration();
importDeclaration.setName(unitAst.newName(variableType));
importsRewrite.insertLast(importDeclaration, null);
}
}
ASTRewriteCorrectionProposal fix = new ASTRewriteCorrectionProposal("Add missing fields",
context.getCompilationUnit(), rewrite, 1);
return new IJavaCompletionProposal[] {fix};
}
private ASTNode getLastField(TypeDeclaration type) {
List<BodyDeclaration> bodyDeclarations = type.bodyDeclarations();
ASTNode lastField = null;
for (BodyDeclaration bodyDeclaration : bodyDeclarations) {
if (bodyDeclaration.getNodeType() == ASTNode.FIELD_DECLARATION) {
lastField = bodyDeclaration;
}
}
return lastField;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment