/*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at http://www.netbeans.org/cddl.html
* or http://www.netbeans.org/cddl.txt.
*
* When distributing Covered Code, include this CDDL Header Notice in each file
* and include the License file at http://www.netbeans.org/cddl.txt.
* If applicable, add the following below the CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.gwt4nb;
import com.sun.source.tree.Tree;
import com.sun.source.util.TreePath;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.NoType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import org.netbeans.api.java.source.CancellableTask;
import org.netbeans.api.java.source.CompilationInfo;
import org.netbeans.api.java.source.ElementHandle;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.java.source.JavaSource.Priority;
import org.netbeans.api.java.source.support.EditorAwareJavaSourceTaskFactory;
import org.netbeans.modules.gwt4nb.hints.HintsUtils;
import org.netbeans.spi.editor.hints.ErrorDescription;
import org.netbeans.spi.editor.hints.HintsController;
import org.netbeans.spi.project.support.ant.EditableProperties;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle;
/**
* Searches for missing keys in the corresponding .properties file for a
* class that extends com.google.gwt.i18n.client.Constants
*/
public class ConstantsHintsFactory extends EditorAwareJavaSourceTaskFactory {
public ConstantsHintsFactory(){
super(Phase.RESOLVED, Priority.LOW);
}
public CancellableTask<CompilationInfo> createTask(final FileObject file) {
return new CancellableTask<CompilationInfo>() {
public void cancel() {
}
public void run(CompilationInfo p) throws Exception {
run0(file, p);
}
};
}
private void run0(FileObject file, CompilationInfo info) throws IOException {
List<ErrorDescription> problemsFound = new ArrayList<ErrorDescription>();
NoType noType =
info.getTypes().getNoType(TypeKind.NONE);
// iterate over all the types (classes, interfaces) defined in this file
for (Tree tree: info.getCompilationUnit().getTypeDecls()){
if (tree.getKind() == Tree.Kind.CLASS){
TreePath path = info.getTrees().getPath(
info.getCompilationUnit(), tree);
TypeElement c = (TypeElement) info.getTrees().
getElement(path);
TypeMirror superclass = c.getSuperclass();
// only interfaces and java.lang.Object have
// superclass.kind=None
if (superclass.equals(noType)) {
List<? extends TypeMirror> interfaces = c.getInterfaces();
boolean extendsConstants = false;
for (TypeMirror tm: interfaces) {
Name qn =((TypeElement) ((DeclaredType) tm).
asElement()).getQualifiedName();
if (qn.contentEquals(
"com.google.gwt.i18n.client.Constants")) { // NOI18N
extendsConstants = true;
break;
}
}
if (extendsConstants) {
runOnInterface(problemsFound, file, info, c);
}
}
}
}
HintsController.setErrors(info.getFileObject(),
getClass().getName(), problemsFound);
}
/**
* Creates hints for an interface that extends
* com.google.gwt.i18n.client.Constants
*
* @param problemsFound problems will be stored here
* @param file .java file
* @param info compilation unit
* @param c interface a extends com.google.gwt.i18n.client.Constants
*/
private void runOnInterface(List<ErrorDescription> problemsFound,
FileObject file, CompilationInfo info, TypeElement c)
throws IOException {
FileObject p =
FileUtil.findBrother(file, "properties"); // NOI18N
if (p != null) {
EditableProperties ep = new EditableProperties(false);
InputStream is = p.getInputStream();
try {
ep.load(is);
} finally {
is.close();
}
List<ExecutableElement> ms =
new ArrayList<ExecutableElement>();
for (ExecutableElement m: ElementFilter.methodsIn(
c.getEnclosedElements())) {
String methodName = m.getSimpleName().toString();
if (!ep.containsKey(methodName)) {
ms.add(m);
}
}
if (ms.size() > 0) {
String msg = NbBundle.getMessage(
ConstantsHintsFactory.class,
"ConstantsHintsFactory.MissingKeys"); // NOI18N
List<ElementHandle<ExecutableElement>> ehs =
new ArrayList<ElementHandle<ExecutableElement>>();
for (ExecutableElement m: ms)
ehs.add(ElementHandle.create(m));
ErrorDescription error = HintsUtils.createProblem(
c, info, msg,
new ConstantsCreateKeyFix(file, ehs, ep));
problemsFound.add(error);
}
}
}
}