Merge branch 'master' of git@git.labs.intellij.net:idea/community

This commit is contained in:
Eugene Kudelevsky
2010-06-28 19:44:20 +04:00
75 changed files with 4074 additions and 213 deletions
@@ -280,7 +280,7 @@ public class ChangeContextUtil {
return refMemberClass;
}
private static boolean canRemoveQualifier(PsiReferenceExpression refExpr) {
public static boolean canRemoveQualifier(PsiReferenceExpression refExpr) {
try{
PsiExpression qualifier = refExpr.getQualifierExpression();
if (!(qualifier instanceof PsiReferenceExpression)) return false;
@@ -27,9 +27,9 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
@@ -91,7 +91,7 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
}
});
((PsiReferenceExpressionImpl)refExpr).bindToElementViaStaticImport(((PsiMember)resolved).getContainingClass(), ((PsiNamedElement)resolved).getName(), ((PsiJavaFile)file).getImportList());
RefactoringUtil.bindToElementViaStaticImport(((PsiMember)resolved).getContainingClass(), ((PsiNamedElement)resolved).getName(), ((PsiJavaFile)file).getImportList());
file.accept(new JavaRecursiveElementVisitor() {
@Override public void visitReferenceExpression(PsiReferenceExpression expression) {
@@ -134,4 +134,4 @@ public class AddSingleMemberStaticImportAction extends PsiElementBaseIntentionAc
}
});
}
}
}
@@ -15,28 +15,35 @@
*/
package com.intellij.codeInspection.actions;
import com.intellij.codeInsight.ChangeContextUtil;
import com.intellij.codeInsight.CodeInsightUtilBase;
import com.intellij.codeInsight.TargetElementUtilBase;
import com.intellij.codeInsight.actions.OptimizeImportsProcessor;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.DirectClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.*;
public class ReplaceImplementsWithStaticImportAction implements IntentionAction {
public class ReplaceImplementsWithStaticImportAction extends PsiElementBaseIntentionAction {
private static final Logger LOG = Logger.getInstance("#" + ReplaceImplementsWithStaticImportAction.class.getName());
@NonNls private static final String FIND_CONSTANT_FIELD_USAGES = "Find constant field usages...";
@NotNull
public String getText() {
@@ -48,8 +55,14 @@ public class ReplaceImplementsWithStaticImportAction implements IntentionAction
return getText();
}
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (!(file instanceof PsiJavaFile)) return false;
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
if (!(element.getContainingFile() instanceof PsiJavaFile)) return false;
if (element instanceof PsiIdentifier) {
final PsiElement parent = element.getParent();
if (parent instanceof PsiClass) {
return isEmptyClass(project, (PsiClass)parent) && DirectClassInheritorsSearch.search((PsiClass)parent).findFirst() != null;
}
}
final PsiReference psiReference = TargetElementUtilBase.findReference(editor);
if (psiReference == null) return false;
@@ -64,11 +77,13 @@ public class ReplaceImplementsWithStaticImportAction implements IntentionAction
final PsiElement target = psiReference.resolve();
if (target == null || !(target instanceof PsiClass)) return false;
PsiClass targetClass = (PsiClass)target;
return isEmptyClass(project, (PsiClass)target);
}
private static boolean isEmptyClass(Project project, PsiClass targetClass) {
if (!targetClass.isInterface()) {
return false;
}
final PsiReferenceList extendsList = targetClass.getExtendsList();
LOG.assertTrue(extendsList != null);
if (extendsList.getReferencedTypes().length > 0) {
@@ -78,7 +93,8 @@ public class ReplaceImplementsWithStaticImportAction implements IntentionAction
if (objectClass == null) return false;
methods.removeAll(Arrays.asList(objectClass.getMethods()));
if (methods.size() > 0) return false;
} else if (targetClass.getMethods().length > 0){
}
else if (targetClass.getMethods().length > 0) {
return false;
}
return targetClass.getAllFields().length > 0;
@@ -87,30 +103,202 @@ public class ReplaceImplementsWithStaticImportAction implements IntentionAction
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
if (!CodeInsightUtilBase.preparePsiElementForWrite(file)) return;
final PsiReference psiReference = file.findReferenceAt(editor.getCaretModel().getOffset());
LOG.assertTrue(psiReference != null);
final int offset = editor.getCaretModel().getOffset();
final PsiReference psiReference = file.findReferenceAt(offset);
if (psiReference != null) {
final PsiElement element = psiReference.getElement();
final PsiElement element = psiReference.getElement();
final PsiClass psiClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
LOG.assertTrue(psiClass != null);
final PsiClass psiClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
LOG.assertTrue(psiClass != null);
final PsiElement target = psiReference.resolve();
LOG.assertTrue(target instanceof PsiClass);
final PsiElement target = psiReference.resolve();
LOG.assertTrue(target instanceof PsiClass);
final PsiClass targetClass = (PsiClass)target;
new WriteCommandAction(project, getText()) {
protected void run(Result result) throws Throwable {
for (PsiField constField : targetClass.getAllFields()) {
final String fieldName = constField.getName();
final PsiClass containingClass = constField.getContainingClass();
for (PsiReference ref : ReferencesSearch.search(constField)) {
final PsiElement psiElement = ref.getElement();
if (ref instanceof PsiReferenceExpression) {
final PsiElement qualifier = ((PsiReferenceExpression)ref).getQualifier();
if (qualifier != null) {
if (qualifier instanceof PsiReferenceExpression) {
final PsiElement resolved = ((PsiReferenceExpression)qualifier).resolve();
if (resolved instanceof PsiClass && !InheritanceUtil.isInheritorOrSelf(psiClass, (PsiClass)resolved, true)) {
continue;
}
}
qualifier.putCopyableUserData(ChangeContextUtil.CAN_REMOVE_QUALIFIER_KEY,
ChangeContextUtil.canRemoveQualifier((PsiReferenceExpression)ref));
}
}
bindReference(psiElement.getContainingFile(), constField, containingClass, fieldName, ref, project);
}
}
element.delete();
JavaCodeStyleManager.getInstance(project).optimizeImports(file);
}
}.execute();
}
else {
final PsiElement identifier = file.findElementAt(offset);
LOG.assertTrue(identifier instanceof PsiIdentifier);
final PsiElement element = identifier.getParent();
LOG.assertTrue(element instanceof PsiClass);
final PsiClass targetClass = (PsiClass)element;
final Map<PsiFile, Map<PsiField, Set<PsiReference>>> refs = new HashMap<PsiFile, Map<PsiField, Set<PsiReference>>>();
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
for (PsiField field : targetClass.getAllFields()) {
final PsiClass containingClass = field.getContainingClass();
for (PsiReference reference : ReferencesSearch.search(field)) {
if (reference == null) {
continue;
}
final PsiElement refElement = reference.getElement();
if (encodeQualifier(containingClass, reference, targetClass)) continue;
final PsiFile psiFile = refElement.getContainingFile();
if (psiFile instanceof PsiJavaFile) {
Map<PsiField, Set<PsiReference>> references = refs.get(psiFile);
if (references == null) {
references = new HashMap<PsiField, Set<PsiReference>>();
refs.put(psiFile, references);
}
Set<PsiReference> fieldsRefs = references.get(field);
if (fieldsRefs == null) {
fieldsRefs = new HashSet<PsiReference>();
references.put(field, fieldsRefs);
}
fieldsRefs.add(reference);
}
}
}
}
}, FIND_CONSTANT_FIELD_USAGES, true, project)) {
return;
}
final PsiClass targetClass = (PsiClass)target;
final Set<PsiJavaCodeReferenceElement> refs2Unimplement = new HashSet<PsiJavaCodeReferenceElement>();
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
for (PsiClass psiClass : DirectClassInheritorsSearch.search(targetClass)) {
PsiFile containingFile = psiClass.getContainingFile();
if (!refs.containsKey(containingFile)) {
refs.put(containingFile, new HashMap<PsiField, Set<PsiReference>>());
}
if (collectExtendsImplements(targetClass, psiClass.getExtendsList(), refs2Unimplement)) continue;
collectExtendsImplements(targetClass, psiClass.getImplementsList(), refs2Unimplement);
}
}
}, "Find references in implement/extends lists...", true, project)) {
return;
}
for (PsiField constField : targetClass.getAllFields()) {
for (PsiReference ref : ReferencesSearch.search(constField, new LocalSearchScope(psiClass))) {
((PsiReferenceExpressionImpl)ref).bindToElementViaStaticImport(targetClass, constField.getName(), ((PsiJavaFile)file).getImportList());
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
for (PsiFile psiFile : refs.keySet()) {
final Map<PsiField, Set<PsiReference>> map = refs.get(psiFile);
for (PsiField psiField : map.keySet()) {
final PsiClass containingClass = psiField.getContainingClass();
final String fieldName = psiField.getName();
for (PsiReference reference : map.get(psiField)) {
bindReference(psiFile, psiField, containingClass, fieldName, reference, project);
}
}
}
for (PsiJavaCodeReferenceElement referenceElement : refs2Unimplement) {
referenceElement.delete();
}
}
});
final Set<SmartPsiElementPointer<PsiImportStatementBase>> redundant = new HashSet<SmartPsiElementPointer<PsiImportStatementBase>>();
final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(project);
final SmartPointerManager pointerManager = SmartPointerManager.getInstance(project);
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable(){
public void run() {
for (PsiFile psiFile : refs.keySet()) {
final Collection<PsiImportStatementBase> red = codeStyleManager.findRedundantImports((PsiJavaFile)psiFile);
if (red != null) {
for (PsiImportStatementBase statementBase : red) {
redundant.add(pointerManager.createSmartPsiElementPointer(statementBase));
}
}
}
}
}, "Collect redundant imports...", true, project)) return;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
for (SmartPsiElementPointer<PsiImportStatementBase> pointer : redundant) {
final PsiImportStatementBase statementBase = pointer.getElement();
if (statementBase != null) statementBase.delete();
}
}
});
}
}
private static boolean encodeQualifier(PsiClass containingClass, PsiReference reference, PsiClass targetClass) {
if (reference instanceof PsiReferenceExpression) {
final PsiElement qualifier = ((PsiReferenceExpression)reference).getQualifier();
if (qualifier != null) {
if (qualifier instanceof PsiReferenceExpression) {
final PsiElement resolved = ((PsiReferenceExpression)qualifier).resolve();
if (resolved == containingClass || resolved instanceof PsiClass && InheritanceUtil.isInheritorOrSelf(targetClass, (PsiClass)resolved, true)) {
return true;
}
}
qualifier.putCopyableUserData(ChangeContextUtil.CAN_REMOVE_QUALIFIER_KEY,
ChangeContextUtil.canRemoveQualifier((PsiReferenceExpression)reference));
}
}
return false;
}
element.delete();
new OptimizeImportsProcessor(project, file).run();
private static void bindReference(PsiFile psiFile,
PsiField psiField,
PsiClass containingClass,
String fieldName,
PsiReference reference,
Project project) {
if (reference instanceof PsiReferenceExpression) {
RefactoringUtil.bindToElementViaStaticImport(containingClass, fieldName, ((PsiJavaFile)psiFile).getImportList());
final PsiElement qualifier = ((PsiReferenceExpression)reference).getQualifier();
if (qualifier != null) {
final Boolean canRemoveQualifier = qualifier.getCopyableUserData(ChangeContextUtil.CAN_REMOVE_QUALIFIER_KEY);
if (canRemoveQualifier != null && canRemoveQualifier.booleanValue()) {
qualifier.delete();
} else {
final PsiJavaCodeReferenceElement classReferenceElement =
JavaPsiFacade.getElementFactory(project).createReferenceExpression(containingClass);
qualifier.replace(classReferenceElement);
}
}
} else if (reference.getElement() instanceof PsiDocMethodOrFieldRef){
reference.bindToElement(psiField); //todo refs through inheritors
}
}
private static boolean collectExtendsImplements(final PsiClass targetClass,
final PsiReferenceList referenceList,
final Set<PsiJavaCodeReferenceElement> refs) {
if (referenceList != null) {
for (PsiJavaCodeReferenceElement referenceElement : referenceList.getReferenceElements()) {
if (referenceElement.resolve() == targetClass) {
refs.add(referenceElement);
return true;
}
}
}
return false;
}
public boolean startInWriteAction() {
return true;
return false;
}
}
@@ -17,7 +17,6 @@ package com.intellij.psi.impl.source.tree.java;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.TextRange;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
@@ -47,9 +46,9 @@ import com.intellij.psi.scope.processor.MethodResolverProcessor;
import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.tree.ChildRoleBase;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.CharTable;
import com.intellij.util.Function;
@@ -59,8 +58,6 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements PsiReferenceExpression, SourceJavaCodeReference {
@@ -105,7 +102,7 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements
doImportStatic = false;
}
if (doImportStatic) {
bindToElementViaStaticImport(qualifierClass, staticName, importList);
RefactoringUtil.bindToElementViaStaticImport(qualifierClass, staticName, importList);
}
else {
PsiManagerEx manager = getManager();
@@ -118,34 +115,6 @@ public class PsiReferenceExpressionImpl extends ExpressionPsiElement implements
return this;
}
public void bindToElementViaStaticImport(final PsiClass qualifierClass, final String staticName, final PsiImportList importList)
throws IncorrectOperationException {
final String qualifiedName = qualifierClass.getQualifiedName();
final List<PsiJavaCodeReferenceElement> refs = getImportsFromClass(importList, qualifiedName);
if (refs.size() < CodeStyleSettingsManager.getSettings(getProject()).NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND) {
importList.add(JavaPsiFacade.getInstance(getProject()).getElementFactory().createImportStaticStatement(qualifierClass, staticName));
} else {
for (PsiJavaCodeReferenceElement ref : refs) {
final PsiImportStaticStatement importStatement = PsiTreeUtil.getParentOfType(ref, PsiImportStaticStatement.class);
if (importStatement != null) {
importStatement.delete();
}
}
importList.add(JavaPsiFacade.getInstance(getProject()).getElementFactory().createImportStaticStatement(qualifierClass, "*"));
}
}
private static List<PsiJavaCodeReferenceElement> getImportsFromClass(@NotNull PsiImportList importList, String className){
final List<PsiJavaCodeReferenceElement> array = new ArrayList<PsiJavaCodeReferenceElement>();
for (PsiImportStaticStatement staticStatement : importList.getImportStaticStatements()) {
final PsiClass psiClass = staticStatement.resolveTargetClass();
if (psiClass != null && Comparing.strEqual(psiClass.getQualifiedName(), className)) {
array.add(staticStatement.getImportReference());
}
}
return array;
}
public void setQualifierExpression(@Nullable PsiExpression newQualifier) throws IncorrectOperationException {
final PsiExpression oldQualifier = getQualifierExpression();
if (newQualifier == null) {
@@ -36,6 +36,7 @@ import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.controlFlow.ControlFlowUtil;
@@ -62,6 +63,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.psi.JavaTokenType.*;
public class RefactoringUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.util.RefactoringUtil");
public static final int EXPR_COPY_SAFE = 0;
@@ -882,6 +885,34 @@ public class RefactoringUtil {
}
}
public static void bindToElementViaStaticImport(final PsiClass qualifierClass, final String staticName, final PsiImportList importList)
throws IncorrectOperationException {
final String qualifiedName = qualifierClass.getQualifiedName();
final List<PsiJavaCodeReferenceElement> refs = getImportsFromClass(importList, qualifiedName);
if (refs.size() < CodeStyleSettingsManager.getSettings(qualifierClass.getProject()).NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND) {
importList.add(JavaPsiFacade.getInstance(qualifierClass.getProject()).getElementFactory().createImportStaticStatement(qualifierClass, staticName));
} else {
for (PsiJavaCodeReferenceElement ref : refs) {
final PsiImportStaticStatement importStatement = PsiTreeUtil.getParentOfType(ref, PsiImportStaticStatement.class);
if (importStatement != null) {
importStatement.delete();
}
}
importList.add(JavaPsiFacade.getInstance(qualifierClass.getProject()).getElementFactory().createImportStaticStatement(qualifierClass, "*"));
}
}
public static List<PsiJavaCodeReferenceElement> getImportsFromClass(@NotNull PsiImportList importList, String className){
final List<PsiJavaCodeReferenceElement> array = new ArrayList<PsiJavaCodeReferenceElement>();
for (PsiImportStaticStatement staticStatement : importList.getImportStaticStatements()) {
final PsiClass psiClass = staticStatement.resolveTargetClass();
if (psiClass != null && Comparing.strEqual(psiClass.getQualifiedName(), className)) {
array.add(staticStatement.getImportReference());
}
}
return array;
}
public static interface ImplicitConstructorUsageVisitor {
void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor);
@@ -0,0 +1,26 @@
// "Replace Implements with Static Import" "true"
import static In.FOO;
interface In {
int FOO = 0;
}
class II {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class II1 {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + In.FOO);
}
}
@@ -0,0 +1,29 @@
// "Replace Implements with Static Import" "true"
import static In.FOO;
interface In {
int FOO = 0;
}
class II {
public static void main(String[] args) {
System.out.println(FOO);
}
}
/**
* {@link In.FOO}
*/
class II1 {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + In.FOO);
}
}
@@ -0,0 +1,29 @@
// "Replace Implements with Static Import" "true"
import static In.FOO;
interface In {
int FOO = 0;
}
class II {
public static void main(String[] args) {
System.out.println(FOO);
}
}
/**
* {@link I#FOO}
*/
class II1 {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + In.FOO);
}
}
@@ -1,7 +1,7 @@
// "Replace Implements with Static Import" "true"
import static I.BAZZ;
import static I.FOO;
import static I1.BAZZ;
public class X {
void bar() {
@@ -0,0 +1,18 @@
// "Replace Implements with Static Import" "true"
import static I1.BAZZ;
public class X implements I {
void bar() {
System.out.println(FOO);
System.out.println(BAZZ);
}
}
interface I {
String FOO = "foo";
}
interface I1 {
String BAZZ = "bazz";
}
@@ -0,0 +1,19 @@
// "Replace Implements with Static Import" "true"
import static I1.BAZZ;
import static II.FOO;
public class X {
void bar() {
System.out.println(FOO);
System.out.println(BAZZ);
}
}
interface II extends I1{
String FOO = "foo";
}
interface I1 {
String BAZZ = "bazz";
}
@@ -0,0 +1,20 @@
// "Replace Implements with Static Import" "true"
import static In.FOO;
interface In {
int FOO = 0;
}
class II {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class II1 {
int FOO = 9;
public static void main(String[] args) {
System.out.println(In.FOO);
}
}
@@ -0,0 +1,23 @@
// "Replace Implements with Static Import" "true"
interface I<caret>n {
int FOO = 0;
}
class II implements In {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class II1 implements In {
public static void main(String[] args) {
System.out.println(II1.FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + II.FOO);
}
}
@@ -0,0 +1,26 @@
// "Replace Implements with Static Import" "true"
interface I<caret>n {
int FOO = 0;
}
class II implements In {
public static void main(String[] args) {
System.out.println(FOO);
}
}
/**
* {@link In.FOO}
*/
class II1 implements In {
public static void main(String[] args) {
System.out.println(II1.FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + II.FOO);
}
}
@@ -0,0 +1,27 @@
// "Replace Implements with Static Import" "true"
interface I<caret>n {
int FOO = 0;
}
class II implements In {
public static void main(String[] args) {
System.out.println(FOO);
}
}
/**
* {@link I#FOO}
*/
class II1 implements In {
public static void main(String[] args) {
System.out.println(II1.FOO);
}
}
class Uc {
static final String FOO = "";
void g() {
System.out.println("" + II.FOO);
}
}
@@ -0,0 +1,15 @@
// "Replace Implements with Static Import" "true"
public class X implements I {
void bar() {
System.out.println(FOO);
System.out.println(BAZZ);
}
}
interface I extends I1{
String FOO = "foo";
}
interface I<caret>1 {
String BAZZ = "bazz";
}
@@ -0,0 +1,15 @@
// "Replace Implements with Static Import" "true"
public class X implements II {
void bar() {
System.out.println(FOO);
System.out.println(BAZZ);
}
}
interface I<caret>I extends I1{
String FOO = "foo";
}
interface I1 {
String BAZZ = "bazz";
}
@@ -0,0 +1,17 @@
// "Replace Implements with Static Import" "true"
interface I<caret>n {
int FOO = 0;
}
class II implements In {
public static void main(String[] args) {
System.out.println(FOO);
}
}
class II1 implements In {
int FOO = 9;
public static void main(String[] args) {
System.out.println(In.FOO);
}
}
@@ -60,7 +60,10 @@ public class ConfigurationContext {
final ConfigurationContext context = new ConfigurationContext(dataContext);
final DataManager dataManager = DataManager.getInstance();
ConfigurationContext sharedContext = dataManager.loadFromDataContext(dataContext, SHARED_CONTEXT);
if (sharedContext == null || !Comparing.equal(sharedContext.getLocation().getPsiElement(), context.getLocation().getPsiElement())) {
if (sharedContext == null ||
sharedContext.getLocation() == null ||
context.getLocation() == null ||
!Comparing.equal(sharedContext.getLocation().getPsiElement(), context.getLocation().getPsiElement())) {
sharedContext = context;
dataManager.saveInDataContext(dataContext, SHARED_CONTEXT, sharedContext);
}
@@ -753,7 +753,7 @@ public class DocumentationManager {
}
@NotNull
private static DocumentationProvider getProviderFromElement(@Nullable PsiElement element, @Nullable PsiElement originalElement) {
public static DocumentationProvider getProviderFromElement(@Nullable PsiElement element, @Nullable PsiElement originalElement) {
if (element != null && !element.isValid()) {
element = null;
}
@@ -149,13 +149,23 @@ public final class IntentionActionMetaData {
return urls.isEmpty() ? null : urls.toArray(new TextDescriptor[urls.size()]);
}
@Nullable
private static URL getIntentionDescriptionDirURL(ClassLoader aClassLoader, String intentionFolderName) {
final URL pageURL = aClassLoader.getResource(INTENTION_DESCRIPTION_FOLDER + "/" + intentionFolderName);
final URL pageURL = aClassLoader.getResource(INTENTION_DESCRIPTION_FOLDER + "/" + intentionFolderName+"/"+ DESCRIPTION_FILE_NAME);
if (LOG.isDebugEnabled()) {
LOG.debug("Path:"+"intentionDescriptions/" + intentionFolderName);
LOG.debug("URL:"+pageURL);
}
return pageURL;
if (pageURL != null) {
try {
final String url = pageURL.toExternalForm();
return new URL(url.substring(0, url.lastIndexOf('/')));
}
catch (MalformedURLException e) {
LOG.error(e);
}
}
return null;
}
private URL getDirURL() {
@@ -223,8 +223,8 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
}
@Nullable
private static String generateInfo(PsiElement element) {
final DocumentationProvider documentationProvider = DocumentationManager.getProviderFromElement(element);
private static String generateInfo(PsiElement element, PsiElement atPointer) {
final DocumentationProvider documentationProvider = DocumentationManager.getProviderFromElement(element, atPointer);
String info = documentationProvider.getQuickNavigateInfo(element);
if (info != null) {
@@ -305,7 +305,7 @@ public class CtrlMouseHandler extends AbstractProjectComponent {
@Nullable
public String getInfo() {
try {
return generateInfo(myTargetElement);
return generateInfo(myTargetElement, myElementAtPointer);
}
catch (IndexNotReadyException e) {
showDumbModeNotification(myTargetElement.getProject());
@@ -45,7 +45,7 @@ import java.util.Comparator;
import java.util.List;
public abstract class BaseRunConfigurationAction extends ActionGroup {
private static final Logger LOG = Logger.getInstance("#" + BaseRunConfigurationAction.class.getName());
protected static final Logger LOG = Logger.getInstance("#" + BaseRunConfigurationAction.class.getName());
protected BaseRunConfigurationAction(final String text, final String description, final Icon icon) {
super(text, description, icon);
@@ -175,12 +175,15 @@ public abstract class BaseRunConfigurationAction extends ActionGroup {
public void update(final AnActionEvent event){
final ConfigurationContext context = ConfigurationContext.getFromContext(event.getDataContext());
final Presentation presentation = event.getPresentation();
RunnerAndConfigurationSettings configuration;
try {
configuration = context.getConfiguration();
}
catch (IndexNotReadyException e) {
configuration = null;
final RunnerAndConfigurationSettings existing = context.findExisting();
RunnerAndConfigurationSettings configuration = existing;
if (configuration == null) {
try {
configuration = context.getConfiguration();
}
catch (IndexNotReadyException e) {
configuration = null;
}
}
if (configuration == null){
presentation.setEnabled(false);
@@ -189,13 +192,13 @@ public abstract class BaseRunConfigurationAction extends ActionGroup {
else{
presentation.setEnabled(true);
presentation.setVisible(true);
final String name = suggestRunActionName((LocatableConfiguration)configuration.getConfiguration());
final List<RuntimeConfigurationProducer> producers = getEnabledProducers(context);
if (!producers.isEmpty()) {
//todo[nik,anna] it's dirty fix. Otherwise wrong configuration will be returned from context.getConfiguration()
if (existing == null && !producers.isEmpty()) {
//todo[nik,anna] it's dirty fix. Otherwise wrong configuration will be returned from context.getConfiguration()
context.getConfiguration(producers.get(0));
}
updatePresentation(presentation, context.findExisting() != null || producers.size() <= 1 ? " " + name : "", context);
final String name = suggestRunActionName((LocatableConfiguration)configuration.getConfiguration());
updatePresentation(presentation, existing != null || producers.size() <= 1 ? " " + name : "", context);
}
}
@@ -16,6 +16,7 @@
package com.intellij.psi.impl;
import com.intellij.ide.IconProvider;
import com.intellij.lang.Language;
import com.intellij.openapi.project.Project;
import com.intellij.pom.*;
import com.intellij.psi.PsiElement;
@@ -164,6 +165,14 @@ public class PomTargetPsiElementImpl extends RenameableFakePsiElement implements
return null;
}
@NotNull
public Language getLanguage() {
if (myTarget instanceof PsiTarget) {
return ((PsiTarget)myTarget).getNavigationElement().getLanguage();
}
return Language.ANY;
}
@NotNull
@Override
public Project getProject() {
@@ -26,6 +26,9 @@ import org.jetbrains.annotations.NonNls;
* single logical <code>(line; column)</code> pair matches soft wrap-introduced virtual space, i.e. different visual positions
* correspond to the same logical position. It's convenient to store exact visual location details within the logical
* position in order to relief further {@code 'logical position' -> 'visual position'} mapping.
* <p/>
* <b>Note:</b> two objects of this class are considered equal if their logical line and column are equal. I.e. all logical positions
* for soft wrap-introduced virtual space and the first document symbol after soft wrap are considered to be equal.
*
* @see Editor#offsetToLogicalPosition(int)
* @see Editor#logicalPositionToOffset(LogicalPosition)
@@ -134,18 +137,11 @@ public class LogicalPosition implements Comparable<LogicalPosition> {
if (!(o instanceof LogicalPosition)) return false;
final LogicalPosition logicalPosition = (LogicalPosition) o;
return column == logicalPosition.column && line == logicalPosition.line && softWrapLines == logicalPosition.softWrapLines
&& linesFromActiveSoftWrap == logicalPosition.linesFromActiveSoftWrap
&& softWrapColumnDiff == logicalPosition.softWrapColumnDiff && foldedLines == logicalPosition.foldedLines
&& foldingColumnDiff == logicalPosition.foldingColumnDiff;
return column == logicalPosition.column && line == logicalPosition.line;
}
public int hashCode() {
int result = 29 * line + column;
result = result * 29 + softWrapLines;
result = 29 * result + softWrapColumnDiff;
result = 29 * result + foldedLines;
return 29 * result + foldingColumnDiff;
return 29 * line + column;
}
@NonNls
@@ -0,0 +1,47 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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 com.intellij.openapi.fileChooser;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
/**
* @author Konstantin Bulenkov
*/
public class FileTypeDescriptor extends FileChooserDescriptor {
private final ArrayList<String> ext;
public FileTypeDescriptor(String title, @NotNull String... extensions) {
super(true, false, false, true, false, false);
assert extensions.length > 0 : "There should be at least one extension";
ext = new ArrayList<String>(Arrays.asList(extensions));
setTitle(title);
}
@Override
public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
final String ex = file.getExtension();
return file.isDirectory() || (ex != null && ext.contains(ex.toLowerCase()));
}
@Override
public boolean isFileSelectable(VirtualFile file) {
return !file.isDirectory() && isFileVisible(file, true);
}
}
@@ -233,10 +233,13 @@ public class EditorActionUtil {
}
else if (logLineToUse == logCaretLine) {
int line = currentVisCaret.line;
int column = 0;
int column;
if (currentVisCaret.column == 0) {
column = findSmartIndentColumn(editor, currentVisCaret.line);
}
else {
column = findFirstNonSpaceColumnOnTheLine(editor, currentVisCaret.line);
}
caretModel.moveToVisualPosition(new VisualPosition(line, column));
}
else {
@@ -279,7 +279,7 @@ public class SoftWrapModelImpl implements SoftWrapModelEx {
@NotNull
public LogicalPosition adjustLogicalPosition(@NotNull LogicalPosition defaultLogical, @NotNull VisualPosition visual) {
if (myActive > 0 || !isSoftWrappingEnabled() || myWraps.isEmpty()) {
if (myActive > 0 || !isSoftWrappingEnabled() || myWraps.isEmpty() || myEditor.getDocument().getTextLength() <= 0) {
return defaultLogical;
}
@@ -21,8 +21,6 @@ import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ui.AbstractTableCellEditor;
import com.intellij.util.ui.CellEditorComponentWithBrowseButton;
import javax.swing.*;
import java.awt.*;
@@ -45,12 +43,7 @@ public class LocalPathCellEditor extends AbstractTableCellEditor {
public Component getTableCellEditorComponent(final JTable table, Object value, boolean isSelected, final int row, int column) {
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
FileChooserDescriptor d = new FileChooserDescriptor(false, true, false, true, false, false);
if (myTitle != null) {
d.setTitle(myTitle);
}
d.setShowFileSystemRoots(true);
final FileChooserDescriptor d = getFileChooserDescriptor();
VirtualFile initialFile = LocalFileSystem.getInstance().findFileByPath((String)getCellEditorValue());
VirtualFile[] files = FileChooser.chooseFiles(table, d, initialFile);
if (files.length == 1 && files[0] != null) {
@@ -66,4 +59,13 @@ public class LocalPathCellEditor extends AbstractTableCellEditor {
myComponent.getChildComponent().setText((String)value);
return myComponent;
}
public FileChooserDescriptor getFileChooserDescriptor() {
FileChooserDescriptor d = new FileChooserDescriptor(false, true, false, true, false, false);
if (myTitle != null) {
d.setTitle(myTitle);
}
d.setShowFileSystemRoots(true);
return d;
}
}
@@ -111,21 +111,6 @@ public class IdeaSpecificSettings {
replaceModuleRelatedRoots(model.getProject(), modifiableModel, libElement, JavadocOrderRootType.getInstance(), RELATIVE_MODULE_JAVADOC);
modifiableModel.commit();
}
else {
libraryByName = EclipseClasspathReader.findLibraryByName(model.getProject(), libName);
if (libraryByName != null) {
appendLibraryScope(model, libElement, libraryByName);
}
final Library[] libraries = model.getModuleLibraryTable().getLibraries();
for (Library library : libraries) {
final Library.ModifiableModel modifiableModel = library.getModifiableModel();
replaceCollapsedByEclipseSourceRoots(libElement, modifiableModel);
replaceModuleRelatedRoots(model.getProject(), modifiableModel, libElement, OrderRootType.SOURCES, RELATIVE_MODULE_SRC);
replaceModuleRelatedRoots(model.getProject(), modifiableModel, libElement, OrderRootType.CLASSES, RELATIVE_MODULE_CLS);
replaceModuleRelatedRoots(model.getProject(), modifiableModel, libElement, JavadocOrderRootType.getInstance(), RELATIVE_MODULE_JAVADOC);
modifiableModel.commit();
}
}
}
}
+1
View File
@@ -25,6 +25,7 @@
<depends optional="true" config-file="groovy-copyright.xml">com.intellij.copyright</depends>
<depends optional="true" config-file="intellilang-groovy-support.xml">org.intellij.intelliLang</depends>
<depends optional="true">AntSupport</depends>
<extensionPoints>
<extensionPoint name="libraryManager" interface="org.jetbrains.plugins.groovy.config.AbstractGroovyLibraryManager"/>
@@ -22,7 +22,6 @@ import com.intellij.openapi.util.UserDataHolderEx;
import com.intellij.patterns.compiler.PatternCompilerImpl;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.intellij.plugins.intelliLang.inject.InjectorUtils;
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.jetbrains.annotations.NotNull;
@@ -41,8 +40,7 @@ public class PatternEditorContextMembersProvider extends NonCodeMembersContribut
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
ResolveState state) {
final PsiFile file = place.getContainingFile().getOriginalFile();
final BaseInjection injection = file.getUserData(BaseInjection.INJECTION_KEY);
if (injection == null) return;
@@ -2,7 +2,6 @@ package org.jetbrains.plugins.groovy.annotator.intentions.dynamic;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -15,10 +14,9 @@ public class DynamicMembersContributor extends NonCodeMembersContributor {
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
ResolveState state) {
final DynamicManager manager = DynamicManager.getInstance(place.getProject());
for (String qName : ResolveUtil.getAllSuperTypes(qualifierType, place, ctx).keySet()) {
for (String qName : ResolveUtil.getAllSuperTypes(qualifierType, place).keySet()) {
for (PsiMethod method : manager.getMethods(qName)) {
if (!ResolveUtil.processElement(processor, method)) return;
}
@@ -9,6 +9,8 @@ import com.intellij.psi.scope.PsiScopeProcessor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrBuilderMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -17,7 +19,7 @@ import java.util.Collections;
/**
* @author peter
*/
class AntBuilderMethod extends LightMethodBuilder {
class AntBuilderMethod extends LightMethodBuilder implements GrBuilderMethod {
private final PsiFile myPlace;
@Nullable private final Class myAntClass;
@@ -26,7 +28,7 @@ class AntBuilderMethod extends LightMethodBuilder {
myPlace = place;
myAntClass = antClass;
setModifiers(PsiModifier.PUBLIC);
addParameter("args", CommonClassNames.JAVA_UTIL_MAP);
addParameter("args", new GrMapType(place.getResolveScope()));
setBaseIcon(GantIcons.ANT_TASK);
addParameter(new GrLightParameter("body", closureType, this).setOptional(true));
}
@@ -47,10 +49,11 @@ class AntBuilderMethod extends LightMethodBuilder {
final AntIntrospector introspector = AntDomExtender.getIntrospector(myAntClass);
if (introspector != null) {
final NameHint hint = processor.getHint(NameHint.KEY);
final PsiType closureType = getParameterList().getParameters()[1].getType();
for (String name : Collections.list(introspector.getNestedElements())) {
if (hint == null || hint.getName(ResolveState.initial()).equals(name)) {
final AntBuilderMethod method = new AntBuilderMethod(myPlace, name, getParameterList().getParameters()[1].getType(), null);
final AntBuilderMethod method = new AntBuilderMethod(myPlace, name, closureType, introspector.getElementType(name));
if (!ResolveUtil.processElement(processor, method)) {
return false;
}
@@ -59,4 +62,9 @@ class AntBuilderMethod extends LightMethodBuilder {
}
return true;
}
@Override
public boolean hasObligatoryNamedArguments() {
return false;
}
}
@@ -20,7 +20,6 @@ import com.intellij.psi.impl.light.LightMethodBuilder;
import com.intellij.psi.impl.light.LightVariableBuilder;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
@@ -38,9 +37,8 @@ public class GantMemberContributor extends NonCodeMembersContributor {
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
if (ResolveUtil.isInheritor(qualifierType, "groovy.util.AntBuilder", place, ctx)) {
ResolveState state) {
if (ResolveUtil.isInheritor(qualifierType, "groovy.util.AntBuilder", place)) {
processAntTasks(processor, place);
return;
}
@@ -0,0 +1,10 @@
package org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members;
/**
* @author peter
*/
public interface GrBuilderMethod {
boolean hasObligatoryNamedArguments();
}
@@ -2,7 +2,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -15,10 +14,9 @@ public class GdkMembersContributor extends NonCodeMembersContributor {
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
ResolveState state) {
final GroovyPsiManager manager = GroovyPsiManager.getInstance(place.getProject());
for (String qName : ResolveUtil.getAllSuperTypes(qualifierType, place, ctx).keySet()) {
for (String qName : ResolveUtil.getAllSuperTypes(qualifierType, place).keySet()) {
for (PsiMethod defaultMethod : manager.getDefaultMethods(qName)) {
if (!ResolveUtil.processElement(processor, defaultMethod)) return;
}
@@ -42,6 +42,10 @@ public class GrMapType extends GrLiteralClassType {
private final String myJavaClassName;
public GrMapType(GlobalSearchScope scope) {
this(JavaPsiFacade.getInstance(scope.getProject()), scope, Collections.<String, PsiType>emptyMap(), Collections.<Pair<PsiType, PsiType>>emptyList(), LanguageLevel.JDK_1_5);
}
public GrMapType(JavaPsiFacade facade,
GlobalSearchScope scope,
Map<String, PsiType> stringEntries,
@@ -144,7 +148,7 @@ public class GrMapType extends GrLiteralClassType {
}
public boolean isAssignableFrom(@NotNull PsiType type) {
return false;
return type instanceof GrMapType || myFacade.getElementFactory().createTypeFromText(getJavaClassName(), null).isAssignableFrom(type);
}
}
@@ -106,7 +106,7 @@ public class GrConstructorInvocationImpl extends GroovyPsiElementImpl implements
for (NonCodeMembersProcessor membersProcessor : NonCodeMembersProcessor.EP_NAME.getExtensions()) {
if (!membersProcessor.processNonCodeMembers(thisType, processor, this, true)) break;
}
NonCodeMembersContributor.processDynamicElements(thisType, processor, this, ResolveState.initial());
NonCodeMembersContributor.runContributors(thisType, processor, this, ResolveState.initial());
return processor.getCandidates();
}
@@ -138,7 +138,7 @@ public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgum
if (field != null) return field;
final PropertyResolverProcessor processor = new PropertyResolverProcessor(propName, this);
ResolveUtil
.processNonCodeMethods(JavaPsiFacade.getElementFactory(getProject()).createType(clazz), processor, getProject(), this, false);
.processNonCodeMethods(JavaPsiFacade.getElementFactory(getProject()).createType(clazz), processor, this, false);
final GroovyResolveResult[] candidates = processor.getCandidates();
if (candidates.length == 0) return null;
return candidates[0].getElement();
@@ -87,7 +87,7 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock
// Process non-code in closures
PsiType clType = JavaPsiFacade.getInstance(getProject()).getElementFactory().createType(closureClass, PsiSubstitutor.EMPTY);
if (!ResolveUtil.processNonCodeMethods(clType, processor, getProject(), place, true)) return false;
if (!ResolveUtil.processNonCodeMethods(clType, processor, place, true)) return false;
}
return true;
@@ -284,7 +284,7 @@ public class CompleteReferenceExpression {
javaLangClass.processDeclarations(processor, ResolveState.initial(), null, refExpr);
PsiType javaLangClassType =
JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(javaLangClass, substitutor);
ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr.getProject(), refExpr, true);
ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr, true);
}
}
}
@@ -352,6 +352,6 @@ public class CompleteReferenceExpression {
return;
}
ResolveUtil.processNonCodeMethods(qualifierType, processor, project, refExpr, true);
ResolveUtil.processNonCodeMethods(qualifierType, processor, refExpr, true);
}
}
@@ -624,7 +624,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
}
if (!javaLangClass.processDeclarations(processor, state, null, refExpr)) return;
PsiType javaLangClassType = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(javaLangClass, substitutor);
ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr.getProject(), refExpr, false);
ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr, false);
}
}
}
@@ -653,7 +653,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
return;
}
ResolveUtil.processNonCodeMethods(qualifierType, processor, project, refExpr, false);
ResolveUtil.processNonCodeMethods(qualifierType, processor, refExpr, false);
}
}
@@ -134,7 +134,7 @@ public class TypesUtil {
}
}
ResolveUtil.processNonCodeMethods(thisType, processor, place.getProject(), place, false);
ResolveUtil.processNonCodeMethods(thisType, processor, place, false);
return processor.getCandidates();
}
return GroovyResolveResult.EMPTY_ARRAY;
@@ -58,14 +58,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrM
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrPropertySelection;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrEnumConstant;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.JavaIdentifier;
@@ -136,7 +134,19 @@ public class PsiUtil {
return InheritanceUtil.isInheritor(argumentTypes[0], CommonClassNames.JAVA_UTIL_MAP);
}
LOG.assertTrue(signature != null);
return GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, place);
if (GrClosureSignatureUtil.isSignatureApplicable(signature, argumentTypes, place)) {
return true;
}
if (method instanceof GrBuilderMethod &&
!((GrBuilderMethod)method).hasObligatoryNamedArguments()) {
final PsiParameter[] parameters = method.getParameterList().getParameters();
if (parameters.length > 0 && parameters[0].getType() instanceof GrMapType &&
(argumentTypes.length == 0 || !(argumentTypes[0] instanceof GrMapType))) {
return GrClosureSignatureUtil.isSignatureApplicable(signature.curry(1), argumentTypes, place);
}
}
return false;
}
public static boolean isApplicable(@Nullable PsiType[] argumentTypes, GrClosureType type, GroovyPsiElement context) {
@@ -147,7 +157,7 @@ public class PsiUtil {
}
public static PsiClassType createMapType(PsiManager manager, GlobalSearchScope scope) {
return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createTypeByFQClassName(CommonClassNames.JAVA_UTIL_MAP, scope);
return new GrMapType(scope);
}
@Nullable
@@ -631,7 +641,7 @@ public class PsiUtil {
qClass.processDeclarations(processor, ResolveState.initial().put(PsiSubstitutor.KEY, PsiSubstitutor.EMPTY), null, expr);
}
ResolveUtil.processNonCodeMethods(qualifierType, processor, expr.getProject(), expr, false);
ResolveUtil.processNonCodeMethods(qualifierType, processor, expr, false);
final GroovyResolveResult[] candidates = processor.getCandidates();
PsiType type = null;
if (candidates.length == 1) {
@@ -828,7 +838,7 @@ public class PsiUtil {
for (NonCodeMembersProcessor membersProcessor : NonCodeMembersProcessor.EP_NAME.getExtensions()) {
if (!membersProcessor.processNonCodeMembers(thisType, processor, place, true)) break;
}
NonCodeMembersContributor.processDynamicElements(thisType, processor, place, ResolveState.initial());
NonCodeMembersContributor.runContributors(thisType, processor, place, ResolveState.initial());
constructorResults.addAll(Arrays.asList(processor.getCandidates()));
if (!toBreak) break;
}
@@ -23,7 +23,6 @@ import com.intellij.psi.PsiType;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.DelegatingScopeProcessor;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
/**
@@ -32,13 +31,15 @@ import org.jetbrains.annotations.NotNull;
public abstract class NonCodeMembersContributor {
private static final ExtensionPointName<NonCodeMembersContributor> EP_NAME = ExtensionPointName.create("org.intellij.groovy.membersContributor");
public abstract void processDynamicElements(@NotNull PsiType qualifierType, PsiScopeProcessor processor, PsiElement place, ResolveState state, ProcessingContext ctx);
public abstract void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state);
public static boolean processDynamicElements(@NotNull final PsiType qualifierType,
public static boolean runContributors(@NotNull final PsiType qualifierType,
PsiScopeProcessor processor,
final PsiElement place,
final ResolveState state) {
final ProcessingContext ctx = new ProcessingContext();
final Ref<Boolean> result = Ref.create(true);
final PsiScopeProcessor wrapper = new DelegatingScopeProcessor(processor) {
@Override
@@ -52,7 +53,7 @@ public abstract class NonCodeMembersContributor {
}
};
for (final NonCodeMembersContributor contributor : EP_NAME.getExtensions()) {
contributor.processDynamicElements(qualifierType, wrapper, place, state, ctx);
contributor.processDynamicElements(qualifierType, wrapper, place, state);
if (!result.get()) {
return false;
}
@@ -17,6 +17,7 @@
package org.jetbrains.plugins.groovy.lang.resolve;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
@@ -24,11 +25,11 @@ import com.intellij.psi.scope.JavaScopeProcessorEvent;
import com.intellij.psi.scope.NameHint;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ProcessingContext;
import com.intellij.psi.util.*;
import com.intellij.util.containers.ConcurrentFactoryMap;
import com.intellij.util.containers.ConcurrentHashMap;
import com.intellij.util.containers.FactoryMap;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.dsl.GroovyDslFileIndex;
@@ -60,7 +61,19 @@ import java.util.*;
*/
@SuppressWarnings({"StringBufferReplaceableByString"})
public class ResolveUtil {
public static final PsiScopeProcessor.Event DECLARATION_SCOPE_PASSED = new PsiScopeProcessor.Event() {
public static final PsiScopeProcessor.Event DECLARATION_SCOPE_PASSED = new PsiScopeProcessor.Event() {};
private static final Key<CachedValue<FactoryMap<PsiType, Map<String, PsiType>>>> SUPER_TYPES = Key.create("SUPER_TYPES");
private static final TObjectHashingStrategy<PsiType> RAW_TYPE_HASHING_STRATEGY = new TObjectHashingStrategy<PsiType>() {
@Override
public int computeHashCode(PsiType object) {
return rawCanonicalText(object).hashCode();
}
@Override
public boolean equals(PsiType o1, PsiType o2) {
return rawCanonicalText(o1).equals(rawCanonicalText(o2));
}
};
private ResolveUtil() {
@@ -77,12 +90,12 @@ public class ResolveUtil {
if (!run.processDeclarations(processor, ResolveState.initial(), lastParent, place)) return false;
if (processNonCodeMethods) {
if (run instanceof GrTypeDefinition) {
processNonCodeMethods(factory.createType(((GrTypeDefinition)run)), processor, project, place, false);
processNonCodeMethods(factory.createType(((GrTypeDefinition)run)), processor, place, false);
}
else if ((run instanceof GroovyFileBase) && ((GroovyFileBase)run).isScript()) {
final PsiClass psiClass = ((GroovyFileBase)run).getScriptClass();
if (psiClass != null) {
processNonCodeMethods(factory.createType(psiClass), processor, project, place, false);
processNonCodeMethods(factory.createType(psiClass), processor, place, false);
}
}
}
@@ -121,16 +134,9 @@ public class ResolveUtil {
public static boolean processNonCodeMethods(PsiType type,
PsiScopeProcessor processor,
Project project,
PsiElement place,
boolean forCompletion) {
String qName = rawCanonicalText(type);
if (qName == null) {
return true;
}
if (!NonCodeMembersContributor.processDynamicElements(type, processor, place, ResolveState.initial())) {
if (!NonCodeMembersContributor.runContributors(type, processor, place, ResolveState.initial())) {
return false;
}
@@ -141,8 +147,7 @@ public class ResolveUtil {
}
}
final HashMap<String, PsiType> visited = getSuperTypes(type, project);
for (PsiType psiType : visited.values()) {
for (PsiType psiType : getAllSuperTypes(type, place).values()) {
for (NonCodeMembersProcessor membersProcessor : NonCodeMembersProcessor.EP_NAME.getExtensions()) {
if (!membersProcessor.processNonCodeMembers(psiType, processor, place, forCompletion)) return false;
}
@@ -152,51 +157,59 @@ public class ResolveUtil {
private static HashMap<String, PsiType> getSuperTypes(PsiType type, Project project) {
final HashMap<String, PsiType> visited = new HashMap<String, PsiType>();
collectSuperTypes(type, visited, project);
collectSuperTypes(type, visited);
if (type instanceof PsiArrayType) {
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
collectSuperTypes(factory.createTypeFromText(CommonClassNames.JAVA_LANG_COMPARABLE, null), visited, project);
collectSuperTypes(factory.createTypeFromText(CommonClassNames.JAVA_IO_SERIALIZABLE, null), visited, project);
collectSuperTypes(factory.createTypeFromText(CommonClassNames.JAVA_LANG_COMPARABLE, null), visited);
collectSuperTypes(factory.createTypeFromText(CommonClassNames.JAVA_IO_SERIALIZABLE, null), visited);
}
return visited;
}
private static void collectSuperTypes(PsiType type, Map<String, PsiType> visited, Project project) {
private static void collectSuperTypes(PsiType type, Map<String, PsiType> visited) {
String qName = rawCanonicalText(type);
if (qName == null || visited.put(qName, type) != null) {
if (visited.put(qName, type) != null) {
return;
}
for (PsiType superType : type.getSuperTypes()) {
collectSuperTypes(TypeConversionUtil.erasure(superType), visited, project);
collectSuperTypes(TypeConversionUtil.erasure(superType), visited);
}
}
private static final Key<FactoryMap<PsiType, Map<String, PsiType>>> SUPER_TYPES = Key.create("SUPER_TYPES");
public static Map<String, PsiType> getAllSuperTypes(PsiType base, final PsiElement place, ProcessingContext ctx) {
FactoryMap<PsiType, Map<String, PsiType>> classes = ctx.get(SUPER_TYPES);
if (classes == null) {
ctx.put(SUPER_TYPES, classes = new FactoryMap<PsiType, Map<String, PsiType>>() {
@Override
protected Map<String, PsiType> create(PsiType key) {
return getSuperTypes(key, place.getProject());
}
});
}
return classes.get(base);
public static Map<String, PsiType> getAllSuperTypes(PsiType base, final PsiElement place) {
final Project project = place.getProject();
return CachedValuesManager.getManager(project).getCachedValue(project, SUPER_TYPES, new CachedValueProvider<FactoryMap<PsiType, Map<String, PsiType>>>() {
@Override
public Result<FactoryMap<PsiType, Map<String, PsiType>>> compute() {
final FactoryMap<PsiType, Map<String, PsiType>> map = new ConcurrentFactoryMap<PsiType, Map<String, PsiType>>() {
@Override
protected Map<PsiType, Map<String, PsiType>> createMap() {
return new ConcurrentHashMap<PsiType, Map<String, PsiType>>(RAW_TYPE_HASHING_STRATEGY);
}
@Override
protected Map<String, PsiType> create(PsiType key) {
return getSuperTypes(key, project);
}
};
return Result.create(map, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project));
}
}, false).get(base);
}
public static boolean isInheritor(PsiType type, @NotNull String baseClass, PsiElement place, ProcessingContext ctx) {
return getAllSuperTypes(type, place, ctx).keySet().contains(baseClass);
public static boolean isInheritor(PsiType type, @NotNull String baseClass, PsiElement place) {
return getAllSuperTypes(type, place).keySet().contains(baseClass);
}
@Nullable
private static String rawCanonicalText(PsiType type) {
@NotNull
private static String rawCanonicalText(@NotNull PsiType type) {
final String result = type.getCanonicalText();
if (result == null) return null;
if (result == null) return "";
final int i = result.indexOf('<');
if (i > 0) return result.substring(0, i);
return result;
@@ -446,7 +459,7 @@ public class ResolveUtil {
}
}
else if (parent instanceof GrApplicationStatement) {
final GrExpression funExpr = ((GrApplicationStatement) parent).getFunExpression();
final GrExpression funExpr = ((GrApplicationStatement) parent).getInvokedExpression();
if (funExpr instanceof GrReferenceExpression) {
variants = ((GrReferenceExpression) funExpr).getSameNameVariants();
}
@@ -459,7 +472,7 @@ public class ResolveUtil {
public static GroovyResolveResult[] getConstructorResolveResult(PsiMethod[] constructors, PsiElement place) {
GroovyResolveResult[] variants = new GroovyResolveResult[constructors.length];
for (int i = 0; i < constructors.length; i++) {
final boolean isAccessible = com.intellij.psi.util.PsiUtil.isAccessible(constructors[i], place, null);
final boolean isAccessible = PsiUtil.isAccessible(constructors[i], place, null);
variants[i] = new GroovyResolveResultImpl(constructors[i], isAccessible);
}
return variants;
@@ -19,7 +19,6 @@ package org.jetbrains.plugins.groovy.lang.resolve.noncode;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightMethodBuilder;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.annotator.inspections.GroovyImmutableAnnotationInspection;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
@@ -34,8 +33,7 @@ public class ImmutableAnnotationProcessor extends NonCodeMembersContributor {
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
ResolveState state) {
if (!(qualifierType instanceof PsiClassType)) return;
PsiClass psiClass = ((PsiClassType)qualifierType).resolve();
@@ -64,7 +64,11 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC
getProject().getComponent(GroovyCompilerLoader.class).projectOpened();
CompilerManagerImpl.testSetup();
CompilerProjectExtension.getInstance(getProject()).setCompilerOutputUrl(myMainOutput.findOrCreateDir("out").getUrl());
new WriteCommandAction(getProject()) {
protected void run(Result result) throws Throwable {
CompilerProjectExtension.getInstance(getProject()).setCompilerOutputUrl(myMainOutput.findOrCreateDir("out").getUrl());
}
}.execute();
addGroovyLibrary(myModule, getName().contains("1_7"));
@@ -1,4 +1,4 @@
package org.jetbrains.plugins.groovy.gant.completion;
package org.jetbrains.plugins.groovy.gant;
import com.intellij.openapi.module.Module
@@ -1,4 +1,4 @@
package org.jetbrains.plugins.groovy.gant.completion;
package org.jetbrains.plugins.groovy.gant;
import com.intellij.openapi.util.io.FileUtil
@@ -10,7 +10,7 @@ import org.jetbrains.plugins.groovy.util.TestUtils
/**
* @author peter
*/
public class StandaloneGantCompletionTest extends LightCodeInsightFixtureTestCase {
public class StandaloneGantTest extends LightCodeInsightFixtureTestCase {
@Override
protected String getBasePath() {
@@ -47,6 +47,29 @@ target(aaa: "") {
checkVariants "ant.patt<caret>t", "patternset"
}
public void testOptionalArgumentsHighlighting() throws Exception {
myFixture.configureByText "a.gant", """
ant.java(classname: "com.intellij.util.io.zip.ReorderJarsMain", fork: "true") {
arg(value: "aaa")
classpath {
pathelement(location: "sss")
}
}
"""
myFixture.checkHighlighting(true, false, false)
}
public void testPathElement() throws Exception {
checkVariants """
ant.java(classname: "com.intellij.util.io.zip.ReorderJarsMain", fork: "true") {
arg(value: "aaa")
classpath {
pathele<caret>ment(location: "sss")
}
}
""", "pathelement"
}
static final def GANT_JARS = ["gant.jar", "ant.jar", "ant-junit.jar", "ant-launcher.jar", "commons.jar"]
}
+1
View File
@@ -269,6 +269,7 @@
<action id="ScanSourceCommentsAction" internal="true" class="com.intellij.tools.ScanSourceCommentsAction" text="Dump all comments in the project"/>
<action internal="true" id="CompilerTest" class="com.intellij.compiler.impl.javaCompiler.api.CompilerPerfTestAction" text="Test Rebuild Performance"/>
<action internal="true" id="GenerateDomModel" class="com.intellij.util.dom.generator.GenerateDomModelAction" text="Generate Dom Model"/>
<add-to-group group-id="Internal" anchor="last"/>
</group>
+1
View File
@@ -18,6 +18,7 @@
<orderEntry type="module" module-name="lang-api" />
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="module" module-name="xml-openapi" />
<orderEntry type="library" name="DTDParser" level="project" />
</component>
<component name="copyright">
<Base>
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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 com.intellij.util.dom.generator;
/**
* @author Konstantin Bulenkov
*/
public class DGNamespace {
public final String name;
public boolean skip = false;
public String superClass = null;
public String enums = null;
public DGNamespace(String name) {
this.name = name;
}
}
@@ -0,0 +1,338 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import com.wutka.dtd.*;
import org.apache.xerces.xni.parser.XMLEntityResolver;
import java.io.File;
import java.util.*;
/**
* @author Gregory.Shrago
*/
public class DTDModelLoader implements ModelLoader {
private ModelDesc model;
public void loadModel(ModelDesc model, Collection<File> schemas, XMLEntityResolver resolver) throws Exception {
this.model = model;
for (File dtdFile : schemas) {
String fileName = dtdFile.getPath();
if (dtdFile.isDirectory() || !fileName.endsWith(".dtd") || fileName.endsWith("datatypes.dtd")) {
Util.log("skipping " + fileName);
continue;
}
Util.log("loading " + fileName+"..");
String ns = fileName.substring(fileName.lastIndexOf(File.separatorChar) + 1);
//loadDTDByXerces(ns, dtdFile, resolver);
loadDTDByWutka(ns, dtdFile);
}
}
private NamespaceDesc ensureNamespaceExists(String ns) {
if (!model.nsdMap.containsKey(ns)) {
Util.log("Adding default ns desc for: " + ns);
NamespaceDesc nsd = new NamespaceDesc(ns, model.nsdMap.get(""));
model.nsdMap.put(ns, nsd);
}
return model.nsdMap.get(ns);
}
private void loadDTDByWutka(String ns, File dtdFile) throws Exception {
DTDParser parser = new DTDParser(dtdFile, false);
// Parse the DTD and ask the parser to guess the root element
DTD dtd = parser.parse(true);
checkDTDRootElement(dtd);
processDTD(ns, dtd, model.jtMap, model.nsdMap);
}
private void processDTD(String namespace, DTD dtd, Map<String, TypeDesc> jtMap, Map<String, NamespaceDesc> nsdMap) {
final NamespaceDesc nsd = ensureNamespaceExists(namespace);
if (nsd.skip) return;
final ArrayList<String> resultQNames = new ArrayList<String>();
final DTDElement[] elements = new DTDElement[dtd.elements.size()];
int ptr = 1;
final HashSet<DTDElement> visitedElements = new HashSet<DTDElement>();
elements[0] = dtd.rootElement;
while (--ptr > -1) {
final DTDElement el = elements[ptr];
visitedElements.add(el);
final String typeName = model.toJavaTypeName(el.name, namespace);
final String typeQName = model.toJavaQualifiedTypeName(namespace, typeName, false);
if (resultQNames.contains(typeQName)) {
continue;
} else {
resultQNames.add(typeQName);
}
final TypeDesc td = new TypeDesc(el.name, namespace, typeName, TypeDesc.TypeEnum.CLASS);
boolean duplicates = false;
if ((el.content instanceof DTDAny) || (el.content instanceof DTDMixed)) {
FieldDesc fd = new FieldDesc(FieldDesc.SIMPLE, "value", "String", null, "null", false);
fd.realIndex = td.fdMap.size();
td.fdMap.put(fd.name, fd);
}
for (Object o : el.attributes.keySet()) {
String attrName = (String) o;
DTDAttribute attr = (DTDAttribute) el.attributes.get(attrName);
if (attr.decl == DTDDecl.FIXED || "ID".equals(attr.type)) {
continue;
}
boolean required = attr.decl == DTDDecl.REQUIRED;
FieldDesc fd1 = new FieldDesc(FieldDesc.ATTR, Util.toJavaFieldName(attrName), "String", null, "\"\"", required);
fd1.tagName = attrName;
fd1.documentation = "Attribute " + attrName + "";
fd1.realIndex = td.fdMap.size();
duplicates = Util.addToNameMap(td.fdMap, fd1, false) || duplicates;
}
final ArrayList<List<DTDItem>> choiceList = new ArrayList<List<DTDItem>>();
final LinkedList<Entry> plist = new LinkedList<Entry>();
if (el.content instanceof DTDContainer) {
//if ((el.content instanceof DTDChoice) || (el.content instanceof DTDSequence)) {
plist.add(new Entry(el.content, false, true));
}
while (!plist.isEmpty()) {
final Entry pentry = plist.removeFirst();
final DTDItem p = pentry.p;
if (p instanceof DTDName) {
final DTDName n = (DTDName) p;
final DTDElement nel = (DTDElement) dtd.elements.get(n.value);
final String pName = n.value;
final FieldDesc fd1 = new FieldDesc(FieldDesc.STR, Util.toJavaFieldName(pName), pName, null, "null", pentry.required && (n.cardinal == DTDCardinal.ONEMANY || n.cardinal == DTDCardinal.NONE));
fd1.tagName = pName;
if (nel != null) {
fd1.documentation = parseDTDItemDocumentation(dtd, nel, "Type " + nel.name + " documentation");
}
if (nel == null) {
fd1.type = model.toJavaTypeName(fd1.tagName, namespace);
} else if (nel.content instanceof DTDEmpty || nel.content instanceof DTDAny) {
boolean hasAttrFields = false;
boolean hasTextContents = nel.content instanceof DTDAny;
for (Object o : nel.attributes.values()) {
DTDAttribute attr = (DTDAttribute) o;
if (attr.decl != DTDDecl.FIXED && !"ID".equals(attr.type)) {
hasAttrFields = true;
break;
}
}
if (hasAttrFields || hasTextContents) {
fd1.clType = FieldDesc.OBJ;
fd1.type = model.toJavaTypeName(fd1.tagName, namespace);
fd1.contentQualifiedName = model.toJavaQualifiedTypeName(namespace, fd1.name, false);
fd1.def = "null";
// next type
if (!visitedElements.contains(nel)) {
elements[ptr++] = nel;
}
} else if (hasTextContents) {
fd1.clType = FieldDesc.STR;
fd1.type = "String";
fd1.def = "null";
} else {
fd1.clType = FieldDesc.BOOL;
fd1.type = "boolean";
fd1.def = "false";
}
} else if (nel.content instanceof DTDContainer) {
boolean hasAttrFields = false;
boolean hasTextField = false;
if ((nel.content instanceof DTDMixed) && ((DTDMixed) nel.content).getItemsVec().size() == 1) {
hasTextField = true;
for (Object o : nel.attributes.values()) {
final DTDAttribute attr = (DTDAttribute) o;
if (attr.decl != DTDDecl.FIXED && !"ID".equals(attr.type)) {
hasAttrFields = true;
break;
}
}
}
if (hasTextField && !hasAttrFields) {
fd1.clType = FieldDesc.STR;
fd1.type = "String";
fd1.def = "null";
} else {
fd1.clType = FieldDesc.OBJ;
fd1.type = model.toJavaTypeName(fd1.tagName, namespace);
fd1.contentQualifiedName = model.toJavaQualifiedTypeName(namespace, fd1.tagName, false);
// next type
if (!visitedElements.contains(nel)) {
elements[ptr++] = nel;
}
}
} else {
fd1.type = "ERROR:Name";
}
if ((pentry.many || n.cardinal.type >= 2) && fd1.clType != FieldDesc.BOOL) {
fd1.elementType = fd1.type;
fd1.elementName = fd1.name;
fd1.type = "List<" + fd1.elementType + ">";
fd1.name = Util.pluralize(fd1.name);
fd1.def = "new ArrayList(0)";
fd1.clType = -fd1.clType;
fd1.comment = "array of " + fd1.elementType;
}
fd1.realIndex = td.fdMap.size();
duplicates = Util.addToNameMap(td.fdMap, fd1, false) || duplicates;
} else if (p instanceof DTDContainer) {
final DTDContainer cont = (DTDContainer) p;
final boolean isChoice = cont instanceof DTDChoice;
// 0 - NONE, 1 - OPT, 2 - ZEROMANY, 3 - ONEMANY
final boolean required = !isChoice && pentry.required && p.cardinal != DTDCardinal.ZEROMANY && p.cardinal != DTDCardinal.OPTIONAL;
final boolean many = p.cardinal == DTDCardinal.ONEMANY || p.cardinal == DTDCardinal.ZEROMANY;
List<DTDItem> l = cont.getItemsVec();
if (!many && isChoice) {
choiceList.add(l);
}
for (DTDItem aL : l) {
plist.add(new Entry(aL, many, required));
}
} else {
Util.logerr("unknown item " + p);
}
}
td.duplicates = duplicates;
td.documentation = parseDTDItemDocumentation(dtd, el, "Type " + el.name + " documentation");
jtMap.put(model.toJavaQualifiedTypeName(namespace, td.name, false), td);
int i = 0;
for (FieldDesc fd : td.fdMap.values()) {
fd.idx = i++;
}
for (List<DTDItem> l : choiceList) {
ArrayList<DTDItem> clist = new ArrayList<DTDItem>();
LinkedList<DTDItem> elist = new LinkedList<DTDItem>();
for (i = 0; i < l.size(); i++) {
elist.add(l.get(i));
}
while (!elist.isEmpty()) {
DTDItem p = elist.removeFirst();
if (p instanceof DTDContainer) {
List<DTDItem> l2 = ((DTDContainer) p).getItemsVec();
for (DTDItem aL2 : l2) {
elist.addFirst(aL2);
}
} else if (p instanceof DTDName) {
clist.add(p);
}
}
boolean choiceOpt = true;
FieldDesc[] choice = new FieldDesc[clist.size()];
for (i = 0; i < choice.length; i++) {
DTDName p = (DTDName) clist.get(i);
String s = Util.toJavaFieldName(p.value);
FieldDesc fd = td.fdMap.get(s);
if (fd == null) {
fd = td.fdMap.get(Util.pluralize(s));
if (fd == null) {
Util.logerr("uknown choice element: " + s);
continue;
}
}
choice[i] = fd;
choice[i].choice = choice;
if (fd.required) choiceOpt = false;
}
for (i = 0; i < choice.length; i++) {
choice[i].choiceOpt = choiceOpt;
}
}
}
List<DTDEntity> entList = dtd.getItemsByType(DTDEntity.class);
for (DTDEntity entity : entList) {
String value = entity.value;
if (!value.startsWith("(") || !value.endsWith(")")) {
continue;
}
String typeName = model.toJavaTypeName(entity.name, namespace);
TypeDesc td = new TypeDesc(entity.name, namespace, typeName, TypeDesc.TypeEnum.ENUM);
StringTokenizer st = new StringTokenizer(value, "(|)");
while (st.hasMoreTokens()) {
final String s = st.nextToken();
td.fdMap.put(s, new FieldDesc(Util.computeEnumConstantName(s, td.name), s));
}
td.documentation = parseDTDItemDocumentation(dtd, entity, "Type " + entity.name + " documentation");
jtMap.put(model.toJavaQualifiedTypeName(namespace, td.name, true), td);
}
}
private static String parseDTDItemDocumentation(DTD dtd, DTDOutput obj, String title) {
int elementIndex = dtd.items.indexOf(obj);
if (elementIndex < 1) return null;
Object prev = dtd.items.get(elementIndex - 1);
if (!(prev instanceof DTDComment)) return null;
DTDComment comment = (DTDComment) prev;
return title + "\n" + "<pre>\n" + comment.getText() + "\n</pre>";
}
static class Entry {
boolean required;
boolean many;
DTDItem p;
Entry(DTDItem p, boolean many, boolean required) {
this.required = required;
this.many = many;
this.p = p;
}
Entry parent;
DTDItem it;
Vector choice;
int num;
Entry(Entry parent, DTDItem it, Vector choice, int num) {
this.parent = parent;
this.it = it;
this.choice = choice;
this.num = num;
}
}
private static void checkDTDRootElement(DTD dtd) throws Exception {
if (dtd.rootElement == null) {
StringBuffer sb = new StringBuffer("Empty root: possible elements: ");
HashMap map = new HashMap(dtd.elements);
for (Object o : dtd.elements.values()) {
DTDElement el = (DTDElement) o;
if (el.content instanceof DTDContainer) {
for (Object obj : ((DTDContainer) el.content).getItemsVec()) {
if (obj instanceof DTDName) {
map.remove(((DTDName) obj).value);
}
}
}
}
if (dtd.rootElement != null) return;
sb.append(map.size()).append(map.keySet());
throw new Exception(sb.toString());
}
}
}
@@ -0,0 +1,65 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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 com.intellij.util.dom.generator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import javax.swing.*;
import java.io.File;
/**
* @author Konstantin Bulenkov
*/
public class DomGenDialog extends DialogWrapper{
final DomGenPanel panel;
final JComponent comp;
protected DomGenDialog(Project project) {
super(project);
panel = new DomGenPanel(project);
comp = panel.getComponent();
init();
getOKAction().putValue(Action.NAME, "Generate");
}
@Override
protected JComponent createCenterPanel() {
return comp;
}
@Override
protected void doOKAction() {
final String location = panel.getLocation();
ModelLoader loader = location.toLowerCase().endsWith(".xsd") ? new XSDModelLoader() : new DTDModelLoader();
final ModelGen modelGen = new ModelGen(loader);
final NamespaceDesc desc = panel.getNamespaceDescriptor();
modelGen.setConfig(desc.name, location, desc);
try {
final File output = new File(panel.getOutputDir());
modelGen.perform(output, new File(location).getParentFile());
} catch (Exception e) {
e.printStackTrace(System.err);
}
super.doOKAction();
}
@Override
protected String getDimensionServiceKey() {
return getClass().getName();
}
}
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.util.dom.generator.DomGenPanel">
<grid id="27dc6" binding="mainPanel" layout-manager="GridLayoutManager" row-count="6" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="437" height="199"/>
</constraints>
<properties/>
<border type="none" title="Dom Generator Config"/>
<children>
<component id="29b47" class="javax.swing.JLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Namespace:"/>
</properties>
</component>
<hspacer id="1b788">
<constraints>
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
<vspacer id="e8ccd">
<constraints>
<grid row="5" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<component id="833b2" class="javax.swing.JTextField" binding="myNamespace">
<constraints>
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="327" height="22"/>
</grid>
</constraints>
<properties/>
</component>
<component id="7940e" class="javax.swing.JLabel">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Schema File:"/>
</properties>
</component>
<component id="7fb9d" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="mySchemaLocation" custom-create="true">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="327" height="22"/>
</grid>
</constraints>
<properties/>
</component>
<component id="f5680" class="javax.swing.JLabel">
<constraints>
<grid row="3" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Super Class:"/>
</properties>
</component>
<component id="20f66" class="javax.swing.JTextField" binding="mySuperClass">
<constraints>
<grid row="3" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="327" height="22"/>
</grid>
</constraints>
<properties>
<text value="com.intellij.util.xml.DomElement"/>
</properties>
</component>
<component id="4a359" class="javax.swing.JLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Package:"/>
</properties>
</component>
<component id="afd05" class="javax.swing.JTextField" binding="myPackage">
<constraints>
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="327" height="22"/>
</grid>
</constraints>
<properties>
<text value="com.intellij.myFramework.model"/>
</properties>
</component>
<component id="d62dc" class="javax.swing.JLabel">
<constraints>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Output Dir:"/>
</properties>
</component>
<component id="6a48b" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myOutputDir" custom-create="true">
<constraints>
<grid row="4" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="327" height="22"/>
</grid>
</constraints>
<properties/>
</component>
</children>
</grid>
</form>
@@ -0,0 +1,64 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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 com.intellij.util.dom.generator;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileChooser.FileTypeDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import javax.swing.*;
/**
* @author Konstantin Bulenkov
*/
public class DomGenPanel {
private JPanel mainPanel;
private JTextField myNamespace;
private JTextField mySuperClass;
private TextFieldWithBrowseButton mySchemaLocation;
private JTextField myPackage;
private TextFieldWithBrowseButton myOutputDir;
private final Project myProject;
public DomGenPanel(Project project) {
myProject = project;
}
private void createUIComponents() {
mySchemaLocation = new TextFieldWithBrowseButton();
final String title = "Choose XSD or DTD schema";
mySchemaLocation.addBrowseFolderListener(title, "", myProject, new FileTypeDescriptor(title, "xsd", "dtd"));
myOutputDir = new TextFieldWithBrowseButton();
myOutputDir.addBrowseFolderListener("Select Output For Generated Files", "", myProject, FileChooserDescriptorFactory.getDirectoryChooserDescriptor("Output For Generated Files"));
}
public JComponent getComponent() {
return mainPanel;
}
public NamespaceDesc getNamespaceDescriptor() {
return new NamespaceDesc(myNamespace.getText().trim(), myPackage.getText().trim(), mySuperClass.getText().trim(), "", null, null, null, null);
}
public String getLocation() {
return mySchemaLocation.getText();
}
public String getOutputDir() {
return myOutputDir.getText();
}
}
@@ -0,0 +1,34 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import java.io.File;
public interface Emitter {
public static final String JDOC_OPEN = "/**";
public static final String JDOC_CONT = " * ";
public static final String JDOC_CLOSE = " */";
void emit(FileManager fileManager, ModelDesc model, File outputRoot);
}
@@ -0,0 +1,75 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
public class FieldDesc implements Comparable<FieldDesc> {
final static int STR = 1;
final static int BOOL = 2;
final static int OBJ = 3;
final static int ATTR = 4;
final static int DOUBLE = 5;
final static int SIMPLE = 6;
public FieldDesc(String name, String def) {
this.name = name;
this.def = def;
}
public FieldDesc(int clType, String name, String type, String elementType, String def, boolean required) {
this.clType = clType;
this.name = name;
this.type = type;
this.elementType = elementType;
this.def = def;
this.required = required;
}
int clType = STR;
String name;
String type;
String elementType;
String def;
boolean required;
int idx;
String tagName;
String elementName;
String comment;
FieldDesc[] choice;
boolean choiceOpt;
String documentation;
String simpleTypesString;
int duplicateIndex = -1;
int realIndex;
String contentQualifiedName;
public int compareTo(FieldDesc o) {
return name.compareTo(o.name);
}
public String toString() {
return "Field: " + name + ";" + type + ";" + elementName + ";" + elementType;
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import java.io.File;
public interface FileManager {
public File releaseOutputFile(File outFile);
public File getOutputFile(File target);
}
@@ -0,0 +1,34 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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 com.intellij.util.dom.generator;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
/**
* @author Konstantin Bulenkov
*/
public class GenerateDomModelAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
final Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
if (project != null) {
new DomGenDialog(project).show();
}
}
}
@@ -0,0 +1,766 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import java.util.*;
import java.io.File;
import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
* @author Gregory.Shrago
*/
public class JetBrainsEmitter implements Emitter {
static final boolean NOT_COMPARE_MODE = true; // compare mode: skip package decl & all comments/javadoc
static final boolean JB_OFF = false;
static final boolean REPLACE_TYPES_WITH_INTERFACES = true;
public void emit(FileManager fileManager, ModelDesc model, File outputRoot) {
final NamespaceDesc nsdDef = model.nsdMap.get("");
final Set<String> simpleTypes = new TreeSet<String>();
for (TypeDesc td : model.jtMap.values()) {
generateClass(fileManager, td, model, outputRoot, simpleTypes);
}
// for (Iterator it = nsdMap.values().iterator(); it.hasNext(); ) {
// NamespaceDesc nsd = (NamespaceDesc) it.next();
// generateSuper(nsd, outputRoot);
// generateHelper(nsd, jtMap, outputRoot);
// }
generateSuper(fileManager, nsdDef, model, outputRoot);
generateHelper(fileManager, nsdDef, model, outputRoot);
Util.log("SimpleTypes log:");
for (String s : simpleTypes) {
Util.log(" " + s);
}
}
public void generateClass(FileManager fileManager, TypeDesc td, ModelDesc model, File outDir, Set<String> simpleTypes) {
final Map<String, TypeDesc> jtMap = model.jtMap;
final Map<String, NamespaceDesc> nsdMap = model.nsdMap;
final NamespaceDesc nsd = nsdMap.get(nsdMap.containsKey(td.xsNamespace) ? td.xsNamespace : "");
final String typeName = td.name;
final String typeQName = model.getNSDPrefix(td) + typeName;
final String pkgName = typeQName.lastIndexOf('.') > -1 ? typeQName.substring(0, typeQName.lastIndexOf('.')) : "";
final File outFile = fileManager.getOutputFile(new File(outDir, toJavaFileName(typeQName)));
PrintWriter out = null;
try {
TreeSet<String> externalClasses = new TreeSet<String>();
if (td.type != TypeDesc.TypeEnum.ENUM) {
if (nsd.imports != null) {
StringTokenizer st = new StringTokenizer(nsd.imports, ";");
while (st.hasMoreTokens()) {
externalClasses.add(st.nextToken());
}
}
if (!model.getNSDPrefix("", nsd.superClass, false).equals(model.getNSDPrefix(td))) {
externalClasses.add(model.getNSDPrefix("", nsd.superClass, false) + nsd.superClass.substring(nsd.superClass.lastIndexOf(".") + 1));
}
if (td.supers != null) {
for (TypeDesc tds : td.supers) {
String pkg1 = model.getNSDPrefix(tds);
String pkg2 = model.getNSDPrefix(td);
if (!pkg1.equals(pkg2)) {
externalClasses.add(model.getNSDPrefix(tds) + tds.name);
}
}
}
for (FieldDesc fd : td.fdMap.values()) {
if (fd.simpleTypesString != null && fd.simpleTypesString.indexOf(":fully-qualified-classType;") != -1) {
externalClasses.add("com.intellij.psi.PsiClass");
}
if (fd.contentQualifiedName != null && fd.contentQualifiedName.indexOf('.') > 0) {
String pkgNameFD = fd.contentQualifiedName.substring(0, fd.contentQualifiedName.lastIndexOf('.'));
if (!pkgNameFD.equals(pkgName)) {
externalClasses.add(fd.contentQualifiedName);
}
}
if (fd.clType < 0) {
externalClasses.add("java.util.List");
}
externalClasses.add("org.jetbrains.annotations.NotNull");
if (fd.required) {
externalClasses.add("com.intellij.util.xml.Required");
}
if (fd.duplicateIndex >= 0 || fd.clType == FieldDesc.BOOL) {
externalClasses.add("com.intellij.util.xml.SubTag");
}
if (fd.clType == FieldDesc.ATTR) {
externalClasses.add("com.intellij.util.xml.GenericAttributeValue");
} else if (Math.abs(fd.clType) != FieldDesc.SIMPLE) {
if (Math.abs(fd.clType) == FieldDesc.OBJ) {
final TypeDesc ftd = jtMap.get(fd.contentQualifiedName);
if (ftd != null && ftd.type == TypeDesc.TypeEnum.ENUM) {
externalClasses.add("com.intellij.util.xml.GenericDomValue");
}
} else {
externalClasses.add("com.intellij.util.xml.GenericDomValue");
}
}
}
}
Util.log("Generating type: " + typeName + "..");
out = new PrintWriter(new FileWriter(outFile));
if (NOT_COMPARE_MODE) {
out.println("// Generated on " + new Date());
out.println("// DTD/Schema : " + nsd.name);
}
out.println("");
if (NOT_COMPARE_MODE && pkgName != null && pkgName.length() > 0) {
out.println("package " + pkgName + ";");
}
out.println();
if (td.type != TypeDesc.TypeEnum.ENUM) {
boolean javaLang = false;
boolean external = false;
for (String s : externalClasses) {
if (s.startsWith("java.")) {
javaLang = true;
continue;
}
external = true;
out.println("import " + s + ";");
}
if (javaLang) {
if (external) out.println();
for (String s : externalClasses) {
if (!s.startsWith("java.")) continue;
out.println("import " + s + ";");
}
}
out.println();
}
if (td.type == TypeDesc.TypeEnum.ENUM) {
boolean text = false;
for (Map.Entry<String, FieldDesc> e : td.fdMap.entrySet()) {
if (!e.getKey().equals(e.getValue().name)) {
text = true;
break;
}
}
if (NOT_COMPARE_MODE) {
out.println(JDOC_OPEN);
out.println(JDOC_CONT + td.xsNamespace + ":" + td.xsName + " enumeration.");
printDocumentation(out, td.documentation, JDOC_CONT);
out.println(JDOC_CLOSE);
}
out.print("public enum " + typeName + (text ? (JB_OFF ? "" : " implements com.intellij.util.xml.NamedEnum") : ""));
out.print(" {");
boolean first = true;
for (Map.Entry<String, FieldDesc> e : td.fdMap.entrySet()) {
String val = e.getKey();
FieldDesc id = e.getValue();
if (first) {
first = false;
out.println("");
} else {
out.println(",");
}
if (text) {
out.print("\t" + id.name + " (\"" + val + "\")");
} else {
out.print("\t" + id.name);
}
}
if (text) {
out.println(";");
out.println();
out.println("\tprivate final String value;");
out.println("\tprivate " + typeName + "(String value) { this.value = value; }");
out.println("\tpublic String getValue() { return value; }");
}
out.println();
out.println("}");
return;
}
if (NOT_COMPARE_MODE) {
out.println(JDOC_OPEN);
if (td.type == TypeDesc.TypeEnum.GROUP_INTERFACE) {
out.println(JDOC_CONT + td.xsNamespace + ":" + td.xsName + " model group interface.");
} else {
out.println(JDOC_CONT + td.xsNamespace + ":" + td.xsName + " interface.");
}
printDocumentation(out, td.documentation, JDOC_CONT);
out.println(JDOC_CLOSE);
}
out.print("public interface " + typeName);
if (nsd.superClass != null || (td.supers != null && td.supers.length > 1)) {
boolean comma = false;
if (td.type != TypeDesc.TypeEnum.GROUP_INTERFACE) {
if (nsd.superClass != null) {
out.print(" extends " + nsd.superClass.substring(nsd.superClass.lastIndexOf(".") + 1));
comma = true;
}
}
if (td.supers != null && td.supers.length > 0) {
if (!comma) out.print(" extends ");
for (TypeDesc aSuper : td.supers) {
if (comma) out.print(", ");
else comma = true;
out.print(aSuper.name);
}
}
}
out.println(" {");
FieldDesc[] fields = td.fdMap.values().toArray(new FieldDesc[td.fdMap.size()]);
if (fields.length == 0) {
Util.logwarn("no fields in: " + td.xsName);
}
Arrays.sort(fields, new Comparator<FieldDesc>() {
public int compare(FieldDesc o1, FieldDesc o2) {
return o1.realIndex - o2.realIndex;
}
});
/*
// fields
out.println("");
out.println("\t// fields");
for (int i = 0; i < fields.length; i++) {
out.print("\t// ");
out.print(fields[i].tagName);
out.print(", required:" + fields[i].required);
out.print(", cltype:" + fields[i].clType);
out.println("");
String[] doc = parseAnnotationString(fields[i].documentation);
for (int dc=0; dc<doc.length; dc++) {
out.println("\t// "+doc[dc]);
}
if (fields[i].comment != null) {
out.print("\t// ");
out.print(fields[i].comment);
out.println("");
}
out.print("\tprivate ");
out.print(fields[i].type);
out.print(" ");
out.print(fields[i].name);
out.print(" = ");
out.print(fields[i].def);
out.print(";");
out.println("");
out.println("");
}
*/
// constructors
// set/get methods
// static gets
/*
out.println("\t// standard getters");
out.println("\t" + JDOC_OPEN);
out.println("\t" + JDOC_CONT + "Returns \"" + defTagName + "\"");
out.println("\t" + JDOC_CLOSE);
out.println("\tpublic String get_tag_name() { return _tag_name; }");
out.println("\t" + JDOC_OPEN);
out.println("\t" + JDOC_CONT + "Returns child node tag names");
out.println("\t" + JDOC_CLOSE);
out.println("\tpublic String[] get_tag_names() { return (String[])_tag_names.clone(); }");
out.println("\t" + JDOC_OPEN);
out.println("\t" + JDOC_CONT + "Returns child node field names");
out.println("\t" + JDOC_CLOSE);
out.println("\tpublic String[] get_field_names() { return (String[])_field_names.clone(); }");
out.println("");
out.println("\t// getters/setters methods");
*/
out.println("");
for (FieldDesc field : fields) {
String tagName = field.tagName;
String type = field.type;
String elementType = field.elementType;
String name = field.name;
String paramName = toJavaIdName(field.clType > 0 ? name : field.elementName);
String javaDocTagName = field.clType < 0 ? tagName + " children" : tagName != null ? tagName + " child" : "simple content";
boolean isAttr = field.clType == FieldDesc.ATTR;
boolean isList = field.clType < 0;
if (name.equals("class")) { // getClass method prohibited
name = "clazz";
}
boolean nameChanged = field.tagName != null && !name.equals(isList ? Util.pluralize(Util.toJavaFieldName(field.tagName)) : Util.toJavaFieldName(field.tagName));
// annotations
// types replacement
String newType = field.clType < 0 ? elementType : type;
String converterString = null;
if (field.simpleTypesString != null) {
if (field.simpleTypesString.indexOf(":fully-qualified-classType;") != -1) { // localType, remoteType, etc.
newType = "PsiClass";
//converterString = (JB_OFF ? "//" : "")+"\t@Convert (PsiClassReferenceConverter.class)";
} else if (field.simpleTypesString.indexOf(":ejb-linkType;") != -1) {
} else if (field.simpleTypesString.indexOf(":ejb-ref-nameType;") != -1) { // jndi-nameType
} else if (field.simpleTypesString.indexOf(":pathType;") != -1) {
} else if (field.simpleTypesString.indexOf(":java-identifierType;") != -1) {
//out.println((JB_OFF ? "//" : "") +"\t@Convert (JavaIdentifierConverter.class)");
} else if (field.simpleTypesString.indexOf(":QName;") != -1) {
// ???
} else if (field.simpleTypesString.indexOf(":integer;") != -1) { // BigDecimal
newType = REPLACE_TYPES_WITH_INTERFACES ? "Integer" : "int";
} else if (field.simpleTypesString.indexOf(":int;") != -1) {
newType = REPLACE_TYPES_WITH_INTERFACES ? "Integer" : "int";
} else if (field.simpleTypesString.indexOf(":byte;") != -1) {
newType = REPLACE_TYPES_WITH_INTERFACES ? "Byte" : "byte";
} else if (field.simpleTypesString.indexOf(":short;") != -1) {
newType = REPLACE_TYPES_WITH_INTERFACES ? "Short" : "short";
} else if (field.simpleTypesString.indexOf(":long;") != -1) {
newType = REPLACE_TYPES_WITH_INTERFACES ? "Long" : "long";
} else if (field.simpleTypesString.indexOf(":float;") != -1) {
newType = REPLACE_TYPES_WITH_INTERFACES ? "Float" : "float";
} else if (field.simpleTypesString.indexOf(":double;") != -1) {
newType = REPLACE_TYPES_WITH_INTERFACES ? "Double" : "double";
} else if (field.simpleTypesString.indexOf(":boolean;") != -1) { // true-falseType
newType = REPLACE_TYPES_WITH_INTERFACES ? "Boolean" : "boolean";
}
for (int idx = 0; idx != -1;) {
simpleTypes.add(field.simpleTypesString.substring(idx));
idx = field.simpleTypesString.indexOf(';', idx) + 1;
if (idx == 0) break;
}
}
if (REPLACE_TYPES_WITH_INTERFACES) {
switch (Math.abs(field.clType)) {
case FieldDesc.ATTR:
newType = "GenericAttributeValue<" + newType + ">";
break;
case FieldDesc.BOOL:
newType = "GenericDomValue<Boolean>";
break;
case FieldDesc.SIMPLE:
break;
case FieldDesc.STR:
newType = "GenericDomValue<" + newType + ">";
break;
case FieldDesc.OBJ: {
TypeDesc ftd = jtMap.get(field.contentQualifiedName);
if (ftd != null && ftd.type == TypeDesc.TypeEnum.ENUM) {
newType = "GenericDomValue<" + ftd.name + ">";
}
break;
}
}
}
if (newType != null && isList) {
elementType = newType;
} else if (newType != null) {
type = newType;
}
if (isList) {
type = "List<" + elementType + ">";
}
StringBuffer sbAnnotations = new StringBuffer();
if (field.clType == FieldDesc.SIMPLE) {
// sbAnnotations.append((JB_OFF ? "//" : "") +"\t@TagValue");
} else if (isAttr && nameChanged) {
sbAnnotations.append((JB_OFF ? "//" : "") + "\t@com.intellij.util.xml.Attribute (\"").append(tagName).append("\")");
} else if (isList) {
// sbAnnotations.append((JB_OFF ? "//" : "") +"\t@SubTagList (\"" + tagName + "\")");
if (nameChanged) {
sbAnnotations.append((JB_OFF ? "//" : "") + "\t@com.intellij.util.xml.SubTag (\"").append(tagName).append("\")");
}
} else {
if (field.duplicateIndex >= 0) {
sbAnnotations.append((JB_OFF ? "//" : "") + "\t@SubTag (value = \"").append(tagName).append("\", index = ").append(field.duplicateIndex - 1).append(")");
} else if (field.clType == FieldDesc.BOOL) {
sbAnnotations.append((JB_OFF ? "//" : "") + "\t@SubTag (value = \"").append(tagName).append("\", indicator = true)");
} else if (!name.equals(field.name)) {
sbAnnotations.append((JB_OFF ? "//" : "") + "\t@com.intellij.util.xml.SubTag (\"").append(tagName).append("\")");
}
}
if (converterString != null) {
sbAnnotations.append("\n").append(converterString);
}
if (NOT_COMPARE_MODE && td.type != TypeDesc.TypeEnum.GROUP_INTERFACE) {
out.println("\t" + JDOC_OPEN);
final String text;
if (isList) {
text = "the list of " + javaDocTagName;
} else {
text = "the value of the " + javaDocTagName;
}
out.println("\t" + JDOC_CONT + "Returns " + text + ".");
printDocumentation(out, field.documentation, "\t" + JDOC_CONT);
out.println("\t" + JDOC_CONT + "@return " + text + ".");
out.println("\t" + JDOC_CLOSE);
}
out.println((JB_OFF ? "//" : "") + "\t@NotNull");
if (td.type != TypeDesc.TypeEnum.GROUP_INTERFACE) {
if (sbAnnotations.length() > 0) out.println(sbAnnotations);
if (field.required) {
out.println((JB_OFF ? "//" : "") + "\t@Required");
}
}
out.print("\t");
//out.print("public ");
out.print(type);
out.print(" ");
out.print("get");
out.print(Util.capitalize(name));
out.println("();");
final boolean genAddRemoveInsteadOfSet = true;
if (!genAddRemoveInsteadOfSet || field.clType > 0) {
if (field.clType == FieldDesc.SIMPLE) {
if (NOT_COMPARE_MODE && td.type != TypeDesc.TypeEnum.GROUP_INTERFACE) {
out.println("\t" + JDOC_OPEN);
if (field.clType < 0) {
out.println("\t" + JDOC_CONT + "Sets the list of " + javaDocTagName + ".");
} else {
out.println("\t" + JDOC_CONT + "Sets the value of the " + javaDocTagName + ".");
}
out.println("\t" + JDOC_CONT + "@param " + paramName + " the new value to set");
out.println("\t" + JDOC_CLOSE);
if (sbAnnotations.length() > 0) out.println(sbAnnotations);
}
out.print("\t");
//out.print("public ");
out.print("void set");
out.print(Util.capitalize(name));
out.print("(");
if (field.required) {
out.print((JB_OFF ? "" : "@NotNull "));
}
out.print(type);
out.print(" ");
out.print(paramName);
out.println(");");
}
} else {
if (NOT_COMPARE_MODE && td.type != TypeDesc.TypeEnum.GROUP_INTERFACE) {
out.println("\t" + JDOC_OPEN);
out.println("\t" + JDOC_CONT + "Adds new child to the list of " + javaDocTagName + ".");
out.println("\t" + JDOC_CONT + "@return created child");
out.println("\t" + JDOC_CLOSE);
if (sbAnnotations.length() > 0) out.println(sbAnnotations);
}
out.print("\t");
//out.print("public ");
out.print(elementType + " add");
out.print(Util.capitalize(field.elementName));
out.println("();");
/*
if (!td.isGroupInterface) {
out.println("\t" + JDOC_OPEN);
out.println("\t" + JDOC_CONT + "Adds new child to the list of " + javaDocTagName + ".");
out.println("\t" + JDOC_CONT + "@param " + paramName + " the new child to add");
out.println("\t" + JDOC_CLOSE);
if (sbAnnotations.length() > 0) out.println(sbAnnotations);
}
out.print("\tpublic void add");
out.print(capitalize(fields[i].elementName));
out.print("(");
out.print(fields[i].elementType);
out.print(" ");
out.print(paramName);
out.println(");");
if (!td.isGroupInterface) {
out.println("\t" + JDOC_OPEN);
out.println("\t" + JDOC_CONT + "Removes the child from the list of " + javaDocTagName + ".");
out.println("\t" + JDOC_CONT + "@param " + paramName + " the new child to remove");
out.println("\t" + JDOC_CLOSE);
if (sbAnnotations.length() > 0) out.println(sbAnnotations);
}
out.print("\tpublic ");
out.print("void remove");
out.print(capitalize(fields[i].elementName));
out.print("(");
out.print(fields[i].elementType);
out.print(" ");
out.print(paramName);
out.println(");");
*/
}
out.println("");
out.println("");
}
out.println("}");
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
out.close();
} catch (Exception ex) {
}
fileManager.releaseOutputFile(outFile);
}
}
private void generateSuper(FileManager fileManager, NamespaceDesc nsd, ModelDesc model, File outDir) {
if (nsd.superClass == null || nsd.superClass.length() == 0) return;
final String typeName = nsd.superClass.substring(nsd.superClass.lastIndexOf(".") + 1);
final String typeQName = model.toJavaQualifiedTypeName("", nsd.superClass, false);
String pkgName = typeQName.substring(0, typeQName.lastIndexOf('.'));
File outFile = new File(outDir, toJavaFileName(typeQName));
outFile = fileManager.getOutputFile(outFile);
PrintWriter out = null;
try {
Util.log("Generating type: " + typeName + "..");
out = new PrintWriter(new FileWriter(outFile));
out.println("// Generated on " + new Date());
out.println("// DTD/Schema : " + nsd.name);
out.println("");
if (pkgName != null) {
out.println("package " + pkgName + ";");
}
out.println("");
out.println("");
out.println(JDOC_OPEN);
out.println(JDOC_CONT + nsd.name + " base interface.");
out.println(JDOC_CLOSE);
out.print("public interface " + typeName + " ");
out.println("{");
out.println("}");
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (Exception ex) {
}
fileManager.releaseOutputFile(outFile);
}
}
private void generateHelper(FileManager fileManager, NamespaceDesc nsd, ModelDesc model, File outDir) {
final Map<String, TypeDesc> jtMap = model.jtMap;
final Map<String, NamespaceDesc > nsdMap = model.nsdMap;
if (nsd.helperClass == null || nsd.helperClass.length() == 0) return;
ArrayList<TypeDesc> jtList = new ArrayList<TypeDesc>();
for (TypeDesc td : jtMap.values()) {
if (td.type != TypeDesc.TypeEnum.CLASS) continue;
// if (!nsd.name.equals(td.xsNamespace)) {
// continue;
// }
jtList.add(td);
}
if (jtList.size() == 0) return;
String typeName = nsd.helperClass.substring(nsd.helperClass.lastIndexOf(".") + 1);
final String typeQName = model.toJavaQualifiedTypeName("", nsd.helperClass, false);
String pkgName = typeQName.substring(0, typeQName.lastIndexOf('.'));
File outFile = new File(outDir, toJavaFileName(typeQName));
outFile = fileManager.getOutputFile(outFile);
PrintWriter out = null;
try {
Util.log("Generating type: " + typeName + "..");
out = new PrintWriter(new FileWriter(outFile));
out.println("// Generated on " + new Date());
out.println("// DTD/Schema : " + nsd.name);
out.println("");
if (pkgName != null) {
out.println("package " + pkgName + ";");
}
out.println("");
out.println("");
out.println(JDOC_OPEN);
out.println(JDOC_CONT + nsd.name + " helper class.");
out.println(JDOC_CLOSE);
out.print("public class " + typeName + " ");
out.println("{");
out.println("");
// child index method
// class Holder implements Comparable {
// String str;
// int index;
//
// public Holder(String str, int index) {
// this.str = str;
// this.index = index;
// }
//
// public int compareTo(Object o) {
// return str.compareTo(o==null?null:((Holder)o).str);
// }
// };
// ArrayList holders = new ArrayList();
// for (Iterator it = jtList.iterator(); it.hasNext();) {
// TypeDesc td = (TypeDesc) it.next();
// NamespaceDesc tdnsd = (NamespaceDesc) nsdMap.get(td.xsNamespace);
// String qname = toJavaQualifiedTypeName(tdnsd, td.name);
// ArrayList fields = new ArrayList(td.fdMap.values());
// Collections.sort(fields, new Comparator() {
// public int compare(Object o1, Object o2) {
// return ((FieldDesc) o1).realIndex - ((FieldDesc) o2).realIndex;
// }
// });
// for (Iterator it2 = fields.iterator(); it2.hasNext();) {
// FieldDesc fd = (FieldDesc) it2.next();
// Holder h = new Holder(qname+":"+fd.tagName, fd.realIndex);
// holders.add(h);
// }
// }
// Collections.sort(holders);
// out.println("\tprivate static String[] parentChildTags = new String[] {");
// int idx = 0;
// for (Iterator it = holders.iterator(); it.hasNext(); idx++) {
// Holder holder = (Holder) it.next();
// if (idx % 4 == 0) out.print("\n\t\t");
// out.print("\""+holder.str+"\"");
// if (idx < holders.size()-1) out.print(",");
// }
// out.println("\n\t};");
// out.println("\tprivate static int[] parentChildIndices = new int[] {");
// idx = 0;
// for (Iterator it = holders.iterator(); it.hasNext(); idx++) {
// Holder holder = (Holder) it.next();
// if (idx % 24 == 0) out.print("\n\t\t");
// out.print(holder.index);
// if (idx < holders.size()-1) out.print(",");
// }
// out.println("\n\t};");
// out.println();
// out.println("\tpublic static int getChildIndex(String parentTag, String childTag) {");
// out.println("\t\tint idx = java.util.Arrays.binarySearch(parentChildTags, parentTag+\":\"+childTag);");
// out.println("\t\treturn idx < 0? -1: parentChildIndices[idx];");
// out.println("\t}");
out.println("\tprivate interface GetName { String getName(Object o); }");
out.println("\tprivate static java.util.HashMap<Class, GetName> nameMap = new java.util.HashMap();");
out.println("\tstatic {");
for (TypeDesc td : jtList) {
ArrayList<FieldDesc> fields = new ArrayList<FieldDesc>(td.fdMap.values());
Collections.sort(fields, new Comparator<FieldDesc>() {
public int compare(FieldDesc o1, FieldDesc o2) {
return o1.realIndex - o2.realIndex;
}
});
int guessPriority = 0;
FieldDesc guessedField = null;
for (FieldDesc fd : fields) {
if (fd.clType == FieldDesc.STR || fd.clType == FieldDesc.SIMPLE || fd.clType == FieldDesc.ATTR) {
if (fd.name.equals("name") && guessPriority < 10) {
guessPriority = 10;
guessedField = fd;
} else if (fd.name.endsWith("Name")) {
if ((fd.name.endsWith(Util.decapitalize(td.name + "Name")) || fd.realIndex < 2) && guessPriority < 10) {
guessPriority = 10;
guessedField = fd;
} else if (fd.name.endsWith(Util.decapitalize("DisplayName")) && guessPriority < 5) {
guessPriority = 5;
guessedField = fd;
} else if (guessPriority < 3) {
guessPriority = 3;
guessedField = fd;
}
} else if (fd.name.equals("value") && guessPriority < 1) {
guessPriority = 1;
guessedField = fd;
}
} else
if ((fd.clType == -FieldDesc.OBJ || fd.clType == -FieldDesc.STR) && fd.name.endsWith("displayNames") && guessPriority < 5) {
guessPriority = 5;
guessedField = fd;
}
}
out.println();
String qname = model.getNSDPrefix(td) + td.name;
String tdNameString = "\"" + toPresentationName(td.name) + "\"";
out.println("\t\tnameMap.put(" + qname + ".class, new GetName() {");
out.println("\t\t\tpublic String getName(Object o) {");
if (guessedField != null) {
out.println("\t\t\t\t" + qname + " my = (" + qname + ") o;");
String getter = "my.get" + Util.capitalize(guessedField.name) + "()";
if (guessedField.clType > 0) {
out.println("\t\t\t\tString s = o==null? null:" + getter +
(guessedField.clType == FieldDesc.STR || guessedField.clType == FieldDesc.ATTR ? ".getValue();" : ";"));
out.println("\t\t\t\treturn s==null?" + tdNameString + ":s;");
} else {
out.println("\t\t\t\treturn (o!=null && " + getter + "!=null && " + getter + ".size()>0)?");
out.println("\t\t\t\t\tgetPresentationName(" + getter + ".get(0), null):" + tdNameString + ";");
}
} else {
out.println("\t\t\t\treturn " + tdNameString + ";");
}
out.println("\t\t\t}");
out.println("\t\t});");
}
out.println("\t}");
out.println("\tpublic static String getPresentationName(Object o, String def) {");
out.println("\t\tGetName g = o!=null? nameMap.get(o.getClass().getInterfaces()[0]):null;");
out.println("\t\treturn g != null?g.getName(o):def;");
out.println("\t}");
out.println("}");
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
out.close();
} catch (Exception ex) {
}
fileManager.releaseOutputFile(outFile);
}
}
public static void printDocumentation(PrintWriter out, String str, String prefix) {
if (str == null) return;
StringTokenizer st = new StringTokenizer(str, "\n\r");
while (st.hasMoreTokens()) {
String line = prefix + st.nextToken();
out.println(line);
}
}
public static String toPresentationName(String typeName) {
StringBuffer sb = new StringBuffer(typeName.length() + 10);
boolean prevUp = true;
for (int i = 0; i < typeName.length(); i++) {
char c = typeName.charAt(i);
if (Character.isUpperCase(c) && !prevUp) {
sb.append(' ');
}
sb.append(c);
prevUp = Character.isUpperCase(c);
}
return sb.toString();
}
private static String toJavaFileName(String typeName) {
return typeName.replace('.', File.separatorChar) + ".java";
}
public static String toJavaIdName(String javaFieldName) {
if (Util.RESERVED_NAMES_MAP.containsKey(javaFieldName)) {
javaFieldName += "_";
}
return javaFieldName;
}
}
@@ -0,0 +1,60 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import java.io.File;
/**
* @author Gregory.Shrago
*/
public class Main {
public static void main(String argv[]) throws Exception {
if (argv.length != 4) {
System.out.println("Usage: Main <XSD or DTD> <input folder> <output folder> <config xml>");
}
String mode = argv[0];
final ModelLoader loader;
if (mode.equalsIgnoreCase("xsd")) {
loader = new XSDModelLoader();
}
else if (mode.equalsIgnoreCase("dtd")) {
loader = new DTDModelLoader();
}
else {
System.out.println("'"+mode+"' format not supported");
System.exit(-1);
return;
}
final File modelRoot = new File(argv[1]);
final File outputRoot = new File(argv[2]);
final File configXml = new File(argv[3]);
outputRoot.mkdirs();
final ModelGen modelGen = new ModelGen(loader);
modelGen.loadConfig(configXml);
modelGen.perform(outputRoot, modelRoot);
}
}
@@ -0,0 +1,245 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet;
/**
* @author Gregory.Shrago
*/
public class MergingFileManager implements FileManager {
public File getOutputFile(File target) {
File outFile = target;
if (!outFile.getParentFile().exists() && !outFile.getParentFile().mkdirs()) {
Util.logerr("parent mkdirs failed: " + outFile);
return null;
}
for (int i = 0; outFile.exists(); i++) {
outFile = new File(target.getParentFile(), target.getName() + ".tmp." + i);
}
return outFile;
}
public File releaseOutputFile(File outFile) {
int idx = outFile.getName().indexOf(".tmp.");
File target = outFile;
if (idx > -1) {
target = new File(outFile.getParentFile(), outFile.getName().substring(0, idx));
String[] curLines = loadFile(outFile);
String[] prevLines = loadFile(target);
String[] mergedLines = mergeLines(curLines, prevLines);
if (mergedLines != prevLines) {
if (mergedLines == curLines) {
if (target.exists() && !target.delete()) {
Util.logerr("file replace failed: " + target);
outFile.delete();
} else {
outFile.renameTo(target);
Util.logwarn("file replaced: " + target);
}
} else {
outFile.delete();
if (target.exists() && !target.delete()) {
Util.logerr("file replace failed: " + target);
} else {
writeFile(target, mergedLines);
Util.logwarn("file merged: " + target);
}
}
} else {
outFile.delete();
}
}
return target;
}
private static String[] mergeLines(String[] curLines, String[] prevLines) {
if (prevLines.length == 0) return curLines;
ArrayList<String> merged = new ArrayList<String>();
int curIdx = 0, prevIdx = 0;
String cur, prev;
boolean classScope = false;
boolean importMerged = false;
for (int i = 0; i < Math.max(curLines.length, prevLines.length); i++) {
cur = curIdx < curLines.length ? curLines[curIdx] : "";
prev = prevIdx < prevLines.length ? prevLines[prevIdx] : "";
if (classScope) {
merged.addAll(Arrays.asList(curLines).subList(curIdx, curLines.length));
break;
} else if (prev.trim().startsWith("import ") || cur.trim().startsWith("import ")) {
if (importMerged) continue;
importMerged = true;
int[] indices = new int[]{curIdx, prevIdx};
mergeImports(merged, curLines, prevLines, indices);
curIdx = indices[0];
prevIdx = indices[1];
} else if (cur.equals(prev)) {
if (cur.trim().startsWith("public interface ")
|| cur.trim().startsWith("public enum ")) classScope = true;
merged.add(cur);
curIdx++;
prevIdx++;
} else if (prev.trim().startsWith("@")) {
merged.add(prev);
prevIdx++;
} else if (cur.trim().startsWith("@")) {
merged.add(cur);
curIdx++;
} else if (cur.trim().startsWith("package ") && prev.trim().startsWith("package ")) {
merged.add(prev);
curIdx++;
prevIdx++;
} else if (cur.trim().startsWith("public interface ") && prev.trim().startsWith("public interface ")) {
classScope = true;
prevIdx = addAllStringsUpTo(merged, prevLines, prevIdx, "{");
curIdx = addAllStringsUpTo(null, curLines, curIdx, "{");
} else if (cur.trim().startsWith("* ")) {
curIdx = addAllStringsUpTo(merged, curLines, curIdx, "*/");
if (prev.trim().startsWith("* ") || prev.trim().endsWith("*/")) {
prevIdx = addAllStringsUpTo(null, prevLines, prevIdx, "*/");
}
} else {
merged.add(cur);
curIdx++;
prevIdx++;
}
}
String[] mergedLines = merged.toArray(new String[merged.size()]);
if (compareLines(mergedLines, prevLines, 2) == 0) {
return prevLines;
} else if (compareLines(mergedLines, curLines, 2) == 0) {
return curLines;
} else {
return mergedLines;
}
}
private static void mergeImports(ArrayList<String> merged, String[] curLines, String[] prevLines, int[] indices) {
TreeSet<String> externalClasses = new TreeSet<String>();
for (int i = 0; i < curLines.length; i++) {
String line = curLines[i].trim();
if (line.startsWith("import ") && line.endsWith(";")) {
indices[0] = i + 1;
final String name = line.substring("import ".length(), line.length() - 1).trim();
if (name.endsWith("*")) continue;
externalClasses.add(name);
}
}
for (int i = 0; i < prevLines.length; i++) {
String line = prevLines[i].trim();
if (line.startsWith("import ") && line.endsWith(";")) {
indices[1] = i + 1;
final String name = line.substring("import ".length(), line.length() - 1).trim();
if (name.endsWith("*")) continue;
externalClasses.add(name);
}
}
boolean javaLang = false;
for (String s : externalClasses) {
if (s.startsWith("java.")) {
javaLang = true;
continue;
}
merged.add("import " + s + ";");
}
if (javaLang) {
merged.add("");
for (String s : externalClasses) {
if (!s.startsWith("java.")) continue;
merged.add("import " + s + ";");
}
}
}
private static int addAllStringsUpTo(ArrayList<String> merged, String[] lines, int startIdx, String upTo) {
String str;
do {
str = startIdx < lines.length ? lines[startIdx] : upTo;
if (merged != null) merged.add(str);
startIdx++;
} while (!str.trim().endsWith(upTo) && startIdx < lines.length);
return startIdx;
}
private static int compareLines(String[] mergedLines, String[] curLines, int start) {
if (mergedLines.length < curLines.length) return -1;
if (mergedLines.length > curLines.length) return 1;
for (int i = start; i < mergedLines.length; i++) {
final int comp = mergedLines[i].compareTo(curLines[i]);
if (comp != 0) return comp;
}
return 0;
}
private static void writeFile(File target, String[] mergedLines) {
PrintWriter out = null;
try {
int lineCount = mergedLines.length;
while (lineCount > 0 && mergedLines[lineCount - 1].length() == 0) lineCount--;
out = new PrintWriter(new FileWriter(target));
for (int i = 0; i < lineCount; i++) {
String mergedLine = mergedLines[i];
out.println(mergedLine);
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (Exception e) {
}
}
}
}
private static String[] loadFile(File f1) {
if (!f1.exists()) return new String[0];
ArrayList<String> list = new ArrayList<String>();
BufferedReader in = null;
try {
in = new BufferedReader(new FileReader(f1));
String str;
while ((str = in.readLine()) != null) {
list.add(str);
}
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
return list.toArray(new String[list.size()]);
}
}
@@ -0,0 +1,170 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import org.apache.xerces.xs.XSObject;
import javax.xml.namespace.QName;
import java.io.PrintWriter;
import java.util.*;
/**
* @author Gregory.Shrago
*/
public class ModelDesc {
final Map<String, String> name2replaceMap = new HashMap<String, String>();
final Map<QName, String> qname2FileMap = new HashMap<QName, String>();
final Map<String, NamespaceDesc> nsdMap = new HashMap<String, NamespaceDesc>();
final Map<String, TypeDesc> jtMap = new TreeMap<String, TypeDesc>();
public String getNSDPrefix(TypeDesc td) {
return getNSDPrefix(td.xsNamespace, td.name, td.type == TypeDesc.TypeEnum.ENUM);
}
public String getNSDPrefix(String namespace, String name, boolean isEnum) {
final int lastIdx = name.lastIndexOf(".");
if (lastIdx > -1) return name.substring(0, lastIdx + 1);
final NamespaceDesc nsd = getNSD(namespace);
if (isEnum && nsd.enumPkg != null) {
return nsd.enumPkg + ".";
}
if (nsd.pkgNames != null) {
final QName qname = new QName(namespace, name);
final String files = qname2FileMap.get(qname);
if (files != null) {
for (int i = 0; i < nsd.pkgNames.length; i += 2) {
String file = nsd.pkgNames[i];
String pkg = nsd.pkgNames[i + 1];
if (files.contains(":" + file + ":")) {
return pkg + ".";
}
}
}
}
return nsd.pkgName != null && nsd.pkgName.length() > 0 ? nsd.pkgName + "." : "";
}
public NamespaceDesc getNSD(String namespace) {
NamespaceDesc nsd = nsdMap.get(namespace);
if (nsd == null) {
nsd = nsdMap.get("");
}
return nsd;
}
public String toJavaTypeName(String tname, String ns) {
final int lastIndex = tname.lastIndexOf('.');
String xmlName = lastIndex>-1? tname.substring(lastIndex+1): tname;
NamespaceDesc nsd = getNSD(ns);
if (!ns.endsWith(".dtd")) {
if (xmlName.endsWith(Util.ANONYMOUS_ELEM_TYPE_SUFFIX)) xmlName = xmlName.substring(0, xmlName.length() - Util.ANONYMOUS_ELEM_TYPE_SUFFIX.length());
else if (xmlName.endsWith(Util.ANONYMOUS_ATTR_TYPE_SUFFIX)) xmlName = xmlName.substring(0, xmlName.length() - Util.ANONYMOUS_ATTR_TYPE_SUFFIX.length());
else if (xmlName.endsWith(Util.TYPE_SUFFIX)) xmlName = xmlName.substring(0, xmlName.length() - Util.TYPE_SUFFIX.length());
}
String rc = Util.capitalize(Util.toJavaName(xmlName));
if (nsd.prefix != null && nsd.prefix.length()>0 && !rc.startsWith(nsd.prefix)) {
rc = nsd.prefix + rc;
}
if (Util.RESERVED_NAMES_MAP.containsKey(rc)) {
rc = Util.RESERVED_NAMES_MAP.get(rc);
}
if (name2replaceMap.containsKey(rc)) {
rc = Util.expandProperties(name2replaceMap.get(rc), nsd.props);
}
return rc;
}
public String toJavaQualifiedTypeName(XSObject xs, Map<String, NamespaceDesc> nsdMap, boolean isEnum) {
String typeName = toJavaTypeName(xs.getName(), xs.getNamespace());
return getNSDPrefix(xs.getNamespace(), xs.getName(), isEnum) + typeName;
}
public String toJavaQualifiedTypeName(String namespace, String xmlname, boolean isEnum) {
return getNSDPrefix(namespace, xmlname, isEnum) + toJavaTypeName(xmlname, namespace);
}
void dump(final PrintWriter out) {
// out.println("-- qname2FileMap ---");
// out.println(qname2FileMap);
out.println("-- nsdMap ---");
for (Map.Entry<String, NamespaceDesc> entry : nsdMap.entrySet()) {
out.println("namespace key: "+entry.getKey());
dumpNamespace(entry.getValue(), out);
}
out.println("-- jtMap ---");
for (Map.Entry<String, TypeDesc> entry : jtMap.entrySet()) {
out.println("type key: "+entry.getKey());
dumpTypeDesc(entry.getValue(), out);
}
}
private void dumpTypeDesc(TypeDesc td, PrintWriter out) {
final ArrayList<String> superList;
if (td.supers !=null) {
superList = new ArrayList<String>();
for (TypeDesc aSuper : td.supers) {
superList.add(getNSDPrefix(aSuper)+aSuper.name);
}
} else superList = null;
out.println(" name " + td.name);
out.println(" type " + td.type);
out.println(" xsName " + td.xsName);
out.println(" xsNS " + td.xsNamespace);
out.println(" dups " + td.duplicates);
out.println(" supers " + (superList!=null?superList:"null"));
out.println(" doc " + (td.documentation != null ? td.documentation.length() : "null"));
for (Map.Entry<String, FieldDesc> entry : td.fdMap.entrySet()) {
out.println(" field key: " + entry.getKey());
dumpFieldDesc(td, entry.getValue(), out);
}
}
private void dumpFieldDesc(TypeDesc td, FieldDesc fd, PrintWriter out) {
out.println(" name " + fd.name);
if (td.type == TypeDesc.TypeEnum.ENUM) return;
out.println(" clType " + fd.clType);
out.println(" required " + fd.required);
out.println(" index " + fd.idx+"/"+fd.realIndex);
out.println(" choiceOpt " + fd.choiceOpt);
out.println(" choice " + (fd.choice!=null?fd.choice.length:"null"));
out.println(" content " + fd.contentQualifiedName);
out.println(" dupIdx " + fd.duplicateIndex);
out.println(" elName " + fd.elementName);
out.println(" elType " + fd.elementType);
out.println(" def " + fd.def);
out.println(" doc " + (fd.documentation != null? fd.documentation.length(): "null"));
}
private void dumpNamespace(NamespaceDesc value, PrintWriter out) {
if (value.skip) return;
out.println(" name "+value.name);
out.println(" prefix "+value.prefix);
out.println(" pkgName "+value.pkgName);
out.println(" pkgNames "+(value.pkgNames != null?Arrays.asList(value.pkgNames):"null"));
out.println(" enumPkg "+value.enumPkg);
out.println(" super "+value.superClass);
}
}
@@ -0,0 +1,176 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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 com.intellij.util.dom.generator;
import org.jdom.Element;
import org.jdom.Document;
import org.jdom.input.SAXBuilder;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.apache.xerces.xni.parser.XMLEntityResolver;
import org.apache.xerces.xni.parser.XMLInputSource;
import org.apache.xerces.xni.XMLResourceIdentifier;
import org.apache.xerces.xni.XNIException;
import java.util.*;
import java.io.File;
import java.io.IOException;
import java.io.CharArrayReader;
/**
* @author Gregory.Shrago
*/
public class ModelGen {
private final ModelDesc model = new ModelDesc();
private final Map<String, String> schemaLocationMap = new HashMap<String, String>();
private final ModelLoader loader;
private final Emitter emitter;
private final FileManager fileManager;
public ModelGen(ModelLoader loader) {
this(loader, new JetBrainsEmitter(), new MergingFileManager());
}
public ModelGen(ModelLoader loader, Emitter emitter, FileManager fileManager) {
this.loader = loader;
this.emitter = emitter;
this.fileManager = fileManager;
}
public ModelDesc getModel() {
return model;
}
public static Element loadXml(File configXml) throws Exception {
SAXBuilder saxBuilder = new SAXBuilder();
saxBuilder.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId,
String systemId)
throws SAXException, IOException {
return new InputSource(new CharArrayReader(new char[0]));
}
});
final Document document = saxBuilder.build(configXml);
return document.getRootElement();
}
public void loadConfig(File configXml) throws Exception {
loadConfig(loadXml(configXml));
}
public void setConfig(String schema, String location, NamespaceDesc desc) {
schemaLocationMap.put(schema, location);
model.nsdMap.put("http://www.w3.org/2001/XMLSchema", new NamespaceDesc("http://www.w3.org/2001/XMLSchema"));
model.nsdMap.put("http://www.w3.org/2001/XMLSchema-instance", new NamespaceDesc("http://www.w3.org/2001/XMLSchema-instance"));
model.nsdMap.put("", new NamespaceDesc("", "", "com.intellij.util.xml.DomElement", "", null, null, null, null));
model.nsdMap.put(desc.name, desc);
}
public void loadConfig(Element element) {
final Element namespaceEl = element.getChild("namespaces");
for (Element e : (List<Element>) namespaceEl.getChildren("schemaLocation")) {
final String name = e.getAttributeValue("name");
final String file = e.getAttributeValue("file");
schemaLocationMap.put(name, file);
}
for (Element e : (List<Element>) namespaceEl.getChildren("reserved-name")) {
final String name = e.getAttributeValue("name");
final String replacement = e.getAttributeValue("replace-with");
model.name2replaceMap.put(name, replacement);
}
NamespaceDesc def = new NamespaceDesc("", "generated", "java.lang.Object", "", null, null, null, null);
for (Element nsElement : (List<Element>) namespaceEl.getChildren("namespace")) {
final String name = nsElement.getAttributeValue("name");
final NamespaceDesc nsDesc = new NamespaceDesc(name, def);
final String skip = nsElement.getAttributeValue("skip");
final String prefix = nsElement.getAttributeValue("prefix");
final String superC = nsElement.getAttributeValue("super");
final String imports = nsElement.getAttributeValue("imports");
final String packageS = nsElement.getAttributeValue("package");
final String packageEnumS = nsElement.getAttributeValue("enums");
final String interfaces = nsElement.getAttributeValue("interfaces");
final ArrayList<String> list = new ArrayList<String>();
for (Element pkgElement : (List<Element>) nsElement.getChildren("package")) {
final String pkgName = pkgElement.getAttributeValue("name");
final String fileName = pkgElement.getAttributeValue("file");
list.add(fileName);
list.add(pkgName);
}
for (Element pkgElement : (List<Element>) nsElement.getChildren("property")) {
final String propertyName = pkgElement.getAttributeValue("name");
final String propertyValue = pkgElement.getAttributeValue("value");
nsDesc.props.put(propertyName, propertyValue);
}
if (skip != null) nsDesc.skip = skip.equalsIgnoreCase("true");
if (prefix != null) nsDesc.prefix = prefix;
if (superC != null) nsDesc.superClass = superC;
if (imports != null) nsDesc.imports = imports;
if (packageS != null) nsDesc.pkgName = packageS;
if (packageEnumS != null) nsDesc.enumPkg = packageEnumS;
if (interfaces != null) nsDesc.intfs = interfaces;
if (!list.isEmpty()) nsDesc.pkgNames = list.toArray(new String[list.size()]);
if (name.length() == 0) def = nsDesc;
model.nsdMap.put(name, nsDesc);
}
}
public void perform(final File outputRoot, final File... modelRoots) throws Exception {
loadModel(modelRoots);
emitter.emit(fileManager, model, outputRoot);
Util.log("Done.");
}
public void loadModel(final File... modelRoots) throws Exception {
XMLEntityResolver resolver = new XMLEntityResolver() {
public XMLInputSource resolveEntity(XMLResourceIdentifier xmlResourceIdentifier) throws XNIException, IOException {
String esid = xmlResourceIdentifier.getExpandedSystemId();
if (esid == null) {
final String location = schemaLocationMap.get(xmlResourceIdentifier.getNamespace());
if (location != null) {
esid = location;
} else {
return null;
}
}
// Util.log("resolving "+esid);
File f = null;
for (File root : modelRoots) {
if (root == null) continue;
final String fileName = esid.substring(esid.lastIndexOf('/') + 1);
f = new File(root, fileName);
}
if (f == null || !f.exists()) {
Util.logerr("unable to resolve: " + esid);
return null;
}
esid = f.getPath();
return new XMLInputSource(null, esid, null);
}
};
ArrayList<File> files = new ArrayList<File>();
for (File root : modelRoots) {
files.addAll(Arrays.asList(root.listFiles()));
}
loader.loadModel(model, files, resolver);
Util.log(model.jtMap.size() + " java types loaded");
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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 com.intellij.util.dom.generator;
import org.apache.xerces.xni.parser.XMLEntityResolver;
import java.io.File;
import java.util.Collection;
public interface ModelLoader {
void loadModel(ModelDesc model, Collection<File> files, XMLEntityResolver resolver) throws Exception;
}
@@ -0,0 +1,81 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import java.util.Map;
import java.util.HashMap;
public class NamespaceDesc {
public NamespaceDesc(String name,
String pkgName,
String superClass,
String prefix,
String factoryClass,
String helperClass,
String imports,
String intfs) {
this.name = name;
this.pkgName = pkgName;
this.superClass = superClass;
this.prefix = prefix;
this.factoryClass = factoryClass;
this.helperClass = helperClass;
this.imports = imports;
this.intfs = intfs;
}
public NamespaceDesc(String name) {
this(name, "generated", "java.lang.Object", "", null, null, null, null);
skip = true;
}
public NamespaceDesc(String name, NamespaceDesc def) {
this.name = name;
this.pkgName = def.pkgName;
this.superClass = def.superClass;
this.prefix = def.prefix;
this.factoryClass = def.factoryClass;
this.helperClass = def.helperClass;
this.imports = def.imports;
this.intfs = def.intfs;
}
final Map<String, String> props = new HashMap<String, String>();
final String name;
String pkgName;
String superClass;
String prefix;
String factoryClass;
String helperClass;
String imports;
String intfs;
boolean skip;
String[] pkgNames;
String enumPkg;
public String toString() {
return "NS:"+name+" "+(skip?"skip":"")+pkgName;
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import java.util.Map;
import java.util.TreeMap;
public class TypeDesc {
public enum TypeEnum {
CLASS, ENUM, GROUP_INTERFACE
}
public TypeDesc(String xsName, String xsNamespace, String name, TypeEnum type) {
this.xsName = xsName;
this.xsNamespace = xsNamespace;
this.name = name;
this.type = type;
}
TypeEnum type;
final String xsName;
final String xsNamespace;
final String name;
final Map<String, FieldDesc> fdMap = new TreeMap<String, FieldDesc>();
boolean duplicates;
String documentation;
TypeDesc[] supers;
public String toString() {
return (type == TypeEnum.ENUM ? "enum" : "type") + ": " + name + ";" + xsName + ";";
}
}
@@ -0,0 +1,222 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import org.apache.xerces.xs.XSObject;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
public class Util {
public static final String ANONYMOUS_ELEM_TYPE_SUFFIX = "ElemType";
public static final String ANONYMOUS_ATTR_TYPE_SUFFIX = "AttrType";
public static final String TYPE_SUFFIX = "Type";
//
// Constants
//
public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema";
// reserved names map
public static final String[] RESERVED_NAMES_TABLE = {
"abstract", "default", "if", "private", "this",
"boolean", "do", "implements", "protected", "throw",
"break", "double", "import", "public", "throws",
"byte", "else", "instanceof", "return", "transient",
"case", "extends", "int", "short", "try",
"catch", "final", "interface", "static", "void",
"char", "finally", "long", "strictfp", "volatile",
"class", "float", "native", "super", "while",
"const", "for", "new", "switch",
"continue", "goto", "package", "synchronized"
};
public static final HashMap<String, String> RESERVED_NAMES_MAP;
static {
RESERVED_NAMES_MAP = new HashMap<String, String>();
for (String aRESERVED_NAMES_TABLE : RESERVED_NAMES_TABLE) {
// RESERVED_NAMES_MAP.put(RESERVED_NAMES_TABLE[i], RESERVED_NAMES_TABLE[i]+"_");
// as far as there is no actual field but setters/getters:
RESERVED_NAMES_MAP.put(aRESERVED_NAMES_TABLE, aRESERVED_NAMES_TABLE);
}
//RESERVED_NAMES_MAP.put("class", "clazz");
}
static void log(String str) {
System.out.println(str);
}
static void logwarn(String str) {
System.out.println("[warn] " + str);
}
static void logerr(String str) {
System.out.println("[error] " + str);
}
public static String pluralize(String suggestion) {
// return suggestion+"List";
final String VOWELS = "aeiouy";
if (suggestion.endsWith("s") || suggestion.endsWith("x") ||
suggestion.endsWith("ch")) {
suggestion += "es";
} else {
int len = suggestion.length();
if (suggestion.endsWith("y") && len > 1 && VOWELS.indexOf(suggestion.charAt(len - 2)) < 0) {
suggestion = suggestion.substring(0, len - 1) + "ies";
} else {
suggestion += "s";
}
}
return suggestion;
}
public static String toJavaFieldName(String xmlName) {
String rc = toJavaName(xmlName);
if (RESERVED_NAMES_MAP.containsKey(rc)) {
rc = RESERVED_NAMES_MAP.get(rc);
}
return rc;
}
public static String computeEnumConstantName(String val, String typeName) {
String id = val;
for (int i = 1; i < id.length(); i++) {
if (Character.isUpperCase(id.charAt(i))
&& Character.isLowerCase(id.charAt(i - 1))) {
id = id.substring(0, i) + "_" + id.substring(i);
i++;
}
}
id = id.toUpperCase();
id = id.replace('.', '_').replace('-', '_');
if (id.length() < 2 || !Character.isJavaIdentifierStart(id.charAt(0))) {
id = typeName + "_" + id;
}
return id;
}
public static String capitalize(String str) {
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
}
public static String decapitalize(String str) {
return Character.toLowerCase(str.charAt(0)) + str.substring(1);
}
public static String toJavaName(String xmlName) {
xmlName = xmlName.substring(xmlName.lastIndexOf(':') + 1);
StringTokenizer st = new StringTokenizer(xmlName, "-");
StringBuffer sb = new StringBuffer(st.nextToken());
while (st.hasMoreTokens()) {
sb.append(capitalize(st.nextToken()));
}
return sb.toString();
}
public static String toDefXmlTagName(XSObject xs) {
String xmlName = xs.getName();
if (xmlName.endsWith(TYPE_SUFFIX)) xmlName = xmlName.substring(0, xmlName.length() - 4);
return xmlName;
}
public static String toDefXmlTagName(String tname) {
String xmlName = tname;
if (xmlName.endsWith(TYPE_SUFFIX)) xmlName = xmlName.substring(0, xmlName.length() - TYPE_SUFFIX.length());
return xmlName;
}
public static boolean addToNameMap(Map<String, FieldDesc> fdMap, FieldDesc fd1, boolean merge) {
boolean duplicates = false;
FieldDesc fd2;
if ((fd2 = fdMap.remove(fd1.name)) != null) {
if (fd2.clType == FieldDesc.ATTR) {
// attr <-> field
fd2.name = fd1.name + "Attr";
fdMap.put(fd2.name, fd2);
} else if (merge) {
fdMap.put(fd2.name, fd2);
return false;
} else {
duplicates = true;
fd2.name = fd1.name + "1";
fd2.duplicateIndex = 1;
fdMap.put(fd2.name, fd2);
fd1.name = fd1.name + "2";
fd1.duplicateIndex = 2;
}
} else if ((fd2 = fdMap.get(fd1.name + "1")) != null) {
int id = 2;
while (fdMap.containsKey(fd1.name + id)) id++;
fd1.name = fd1.name + id;
fd1.duplicateIndex = id;
}
fdMap.put(fd1.name, fd1);
return duplicates;
}
public static String expandProperties(final String str, final Map<String, String> map) {
if (str.indexOf("${") == -1) return str;
int state = 0;
final StringBuilder result = new StringBuilder();
final StringBuilder variable = new StringBuilder();
for (int i=0; i<str.length(); i++) {
final char ch = str.charAt(i);
switch (state) {
case 0:
if (ch == '$') state = 1;
else result.append(ch);
break;
case 1:
if (ch == '{') {
state = 2;
variable.setLength(0);
}
else {
state = 0;
result.append('$').append(ch);
}
break;
case 2:
if (ch == '}') {
final String value = map.get(variable.toString());
result.append(value == null? variable : value);
state = 0;
}
else {
variable.append(ch);
}
break;
}
}
return result.toString();
}
}
@@ -0,0 +1,674 @@
/*
* Copyright 2000-2010 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* XSD/DTD Model generator tool
*
* By Gregory Shrago
* 2002 - 2006
*/
package com.intellij.util.dom.generator;
import org.apache.xerces.xs.*;
import org.apache.xerces.impl.xs.XSComplexTypeDecl;
import org.apache.xerces.impl.xs.XSParticleDecl;
import org.apache.xerces.impl.xs.XSAttributeGroupDecl;
import org.apache.xerces.impl.xs.XSElementDecl;
import org.apache.xerces.impl.xs.util.XSObjectListImpl;
import org.apache.xerces.impl.dv.XSSimpleType;
import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl;
import org.apache.xerces.xni.parser.XMLEntityResolver;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMErrorHandler;
import org.w3c.dom.DOMError;
import org.w3c.dom.TypeInfo;
import javax.xml.namespace.QName;
import java.io.File;
import java.util.*;
/**
* @author Gregory.Shrago
*/
public class XSDModelLoader implements ModelLoader {
private static final boolean TEXT_ELEMENTS_ARE_COMPLEX = false;
private ModelDesc model;
public void loadModel(ModelDesc model, Collection<File> files, XMLEntityResolver resolver) throws Exception {
this.model = model;
processSchemas(files, resolver);
}
public static boolean checkComplexType(XSTypeDefinition td) {
if (td.getTypeCategory() != XSTypeDefinition.COMPLEX_TYPE) return false;
XSComplexTypeDefinition ctd = (XSComplexTypeDefinition) td;
if (ctd.getContentType() == XSComplexTypeDefinition.CONTENTTYPE_ELEMENT) {
return true;
}
if ((td instanceof XSComplexTypeDecl) && ((XSComplexTypeDecl) td).getAbstract()) return true;
if (TEXT_ELEMENTS_ARE_COMPLEX) return true;
if (ctd.getAttributeUses() != null) {
for (int i = 0; i < ctd.getAttributeUses().getLength(); i++) {
XSSimpleTypeDefinition xsstd = ((XSAttributeUse) ctd.getAttributeUses().item(i)).getAttrDeclaration().getTypeDefinition();
if ("ID".equals(xsstd.getName())) continue;
return true;
}
}
return false;
}
public static boolean checkEnumType(XSTypeDefinition td) {
final XSSimpleTypeDefinition st;
if (td.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
XSComplexTypeDefinition ctd = (XSComplexTypeDefinition) td;
if (ctd.getContentType() != XSComplexTypeDefinition.CONTENTTYPE_SIMPLE) return false;
if (ctd.getAttributeUses() != null) {
for (int i = 0; i < ctd.getAttributeUses().getLength(); i++) {
XSSimpleTypeDefinition xsstd = ((XSAttributeUse) ctd.getAttributeUses().item(i)).getAttrDeclaration().getTypeDefinition();
if ("ID".equals(xsstd.getName())) continue;
return false;
}
}
st = ctd.getSimpleType();
} else if (td.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
st = (XSSimpleTypeDefinition) td;
} else {
return false;
}
return st.getLexicalEnumeration() != null && st.getLexicalEnumeration().getLength() != 0;
}
private static boolean checkBooleanType(XSTypeDefinition td) {
if (td.getTypeCategory() != XSTypeDefinition.SIMPLE_TYPE) return false;
final XSSimpleTypeDefinition st = ((XSSimpleTypeDefinition) td);
final XSObjectList facets = st.getFacets();
for (int i = 0; i < facets.getLength(); i++) {
final XSFacet facet = (XSFacet) facets.item(i);
if (facet.getFacetKind() == XSSimpleTypeDefinition.FACET_LENGTH) {
if ("0".equals(facet.getLexicalFacetValue())) {
return true;
}
}
}
return false;
}
private XSModel loadSchema(File schemaFile, XMLEntityResolver resolver) throws Exception {
// get DOM Implementation using DOM Registry
System.setProperty(
DOMImplementationRegistry.PROPERTY,
"org.apache.xerces.dom.DOMXSImplementationSourceImpl");
DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
XSImplementation impl = (XSImplementation) registry.getDOMImplementation("XS-Loader");
XSLoader schemaLoader = impl.createXSLoader(null);
DOMConfiguration config = schemaLoader.getConfig();
// create Error Handler
DOMErrorHandler errorHandler = new DOMErrorHandler() {
public boolean handleError(DOMError domError) {
Util.log("DOMError: " + domError.getMessage());
Object relatedException = domError.getRelatedException();
if (relatedException != null) {
Util.log("DOMError: " + relatedException);
if (relatedException instanceof Throwable) {
((Throwable) relatedException).printStackTrace(System.out);
}
}
return false;
}
};
// set error handler
config.setParameter("error-handler", errorHandler);
// set validation feature
config.setParameter("validate", Boolean.TRUE);
// parse document
config.setParameter("error-handler", errorHandler);
config.setParameter("http://apache.org/xml/properties/internal/entity-resolver", resolver);
XSModel model = schemaLoader.loadURI(schemaFile.getAbsolutePath());
if (model == null) return null;
XSNamedMap components = model.getComponents(XSConstants.ELEMENT_DECLARATION);
for (int i = 0; i < components.getLength(); i++) {
XSObject obj = components.item(i);
QName qname = new QName(obj.getNamespace(), obj.getName());
String file = this.model.qname2FileMap.get(qname);
this.model.qname2FileMap.put(qname, (file == null ? "" : file + ";") + schemaFile.getName());
}
components = model.getComponents(XSConstants.TYPE_DEFINITION);
for (int i = 0; i < components.getLength(); i++) {
XSObject obj = components.item(i);
QName qname = new QName(obj.getNamespace(), obj.getName());
String file = this.model.qname2FileMap.get(qname);
this.model.qname2FileMap.put(qname, (file == null ? "" : file) + ":" + schemaFile.getName() + ":");
}
return model;
}
public void processSchemas(Collection<File> schemas, XMLEntityResolver resolver) throws Exception {
Map<String, NamespaceDesc> nsdMap = model.nsdMap;
Map<String, TypeDesc> jtMap = model.jtMap;
final NamespaceDesc nsdDef = nsdMap.get("");
final ArrayList<XSModel> models = new ArrayList<XSModel>();
final HashMap<String, XSTypeDefinition> types = new HashMap<String, XSTypeDefinition>();
for (File schemaFile : schemas) {
String fileName = schemaFile.getPath();
if (schemaFile.isDirectory() || !fileName.endsWith(".xsd")) {
Util.log("skipping " + fileName);
continue;
}
Util.log("loading " + fileName + "..");
final XSModel model = loadSchema(schemaFile, resolver);
if (model == null) continue;
final StringList namespaceList = model.getNamespaces();
for (int i = 0; i < namespaceList.getLength(); i++) {
String ns = namespaceList.item(i);
if (!nsdMap.containsKey(ns)) {
Util.log("Adding default namespace desc for: " + ns);
NamespaceDesc nsd = new NamespaceDesc(ns, nsdDef);
nsdMap.put(ns, nsd);
}
}
models.add(model);
final XSNamedMap typeDefMap = model.getComponents(XSConstants.TYPE_DEFINITION);
for (int i = 0; i < typeDefMap.getLength(); i++) {
XSTypeDefinition o = (XSTypeDefinition) typeDefMap.item(i);
NamespaceDesc nsd = nsdMap.get(o.getNamespace());
if (nsd != null && nsd.skip) continue;
final String key = o.getName() + "," + o.getNamespace();
types.put(key, o);
}
final XSNamedMap elementDeclMap = model.getComponents(XSConstants.ELEMENT_DECLARATION);
for (int i = 0; i < elementDeclMap.getLength(); i++) {
XSElementDeclaration o = (XSElementDeclaration) elementDeclMap.item(i);
if (o.getTypeDefinition().getAnonymous() && (o.getTypeDefinition() instanceof XSComplexTypeDefinition)) {
//types.put(o.getName() + "," + o.getNamespace(), o);
XSComplexTypeDefinition ctd = makeTypeFromAnonymous(o);
NamespaceDesc nsd = nsdMap.get(o.getNamespace());
if (nsd != null && nsd.skip) continue;
final String key = ctd.getName() + "," + ctd.getNamespace();
types.put(key, ctd);
}
}
}
Util.log(types.size() + " elements loaded, processing..");
ArrayList<XSTypeDefinition> toProcess = new ArrayList<XSTypeDefinition>(types.values());
ArrayList<XSComplexTypeDefinition> toAdd = new ArrayList<XSComplexTypeDefinition>();
for (ListIterator<XSTypeDefinition> it = toProcess.listIterator(); it.hasNext();) {
XSTypeDefinition td = it.next();
Util.log("processing " + td.getName() + "," + td.getNamespace() + "..");
if (checkComplexType(td)) {
processType((XSComplexTypeDefinition) td, models, jtMap, nsdMap, toAdd);
} else if (checkEnumType(td)) {
processEnumType(td, jtMap, nsdMap);
}
if (toAdd.size() != 0) {
for (XSComplexTypeDefinition o : toAdd) {
final String key = o.getName() + "," + o.getNamespace();
if (!types.containsKey(key)) {
Util.log(" adding " + o.getName() + "," + o.getNamespace());
types.put(key, o);
it.add(o);
it.previous();
} else {
Util.logwarn(key + " already exists");
}
}
toAdd.clear();
}
}
}
private XSComplexTypeDefinition makeTypeFromAnonymous(XSObject o) {
final XSComplexTypeDecl ctd = new XSComplexTypeDecl();
if (o instanceof XSElementDeclaration && ((XSElementDeclaration) o).getTypeDefinition() instanceof XSComplexTypeDecl) {
final XSComplexTypeDecl ctd1 = (XSComplexTypeDecl) ((XSElementDeclaration) o).getTypeDefinition();
final XSObjectListImpl annotations = ctd1.getAnnotations() instanceof XSObjectListImpl ? (XSObjectListImpl) ctd1.getAnnotations() : new XSObjectListImpl();
ctd.setValues(o.getName(), ctd1.getNamespace(), ctd1.getBaseType(), ctd1.getDerivationMethod(),
ctd1.getFinal(), ctd1.getProhibitedSubstitutions(), ctd1.getContentType(),
ctd1.getAbstract(), ctd1.getAttrGrp(), (XSSimpleType) ctd1.getSimpleType(),
(XSParticleDecl) ctd1.getParticle(), annotations);
ctd.setName(o.getName() + Util.ANONYMOUS_ELEM_TYPE_SUFFIX);
} else if (o instanceof XSAttributeDeclaration) {
final XSSimpleTypeDecl ctd1 = (XSSimpleTypeDecl) ((XSAttributeDeclaration) o).getTypeDefinition();
final XSObjectListImpl annotations = ctd1.getAnnotations() instanceof XSObjectListImpl ? (XSObjectListImpl) ctd1.getAnnotations() : new XSObjectListImpl();
ctd.setValues(o.getName(), ctd1.getNamespace(), ctd1.getBaseType(), XSConstants.DERIVATION_RESTRICTION,
ctd1.getFinal(), (short) 0, XSComplexTypeDefinition.CONTENTTYPE_SIMPLE,
false, new XSAttributeGroupDecl(), ctd1,
null, annotations);
ctd.setName(o.getName() + Util.ANONYMOUS_ATTR_TYPE_SUFFIX);
}
model.qname2FileMap.put(new QName(ctd.getNamespace(), ctd.getName()), model.qname2FileMap.get(new QName(o.getNamespace(), o.getName())));
return ctd;
}
public void processEnumType(XSTypeDefinition def, Map<String, TypeDesc> jtMap, Map<String, NamespaceDesc> nsdMap) throws Exception {
boolean complexType = def instanceof XSComplexTypeDefinition;
if (!nsdMap.containsKey(def.getNamespace())) {
Util.log("Namespace desc not found for: " + def);
}
final String typeName = toJavaTypeName(def, nsdMap);
final TypeDesc td = new TypeDesc(def.getName(), def.getNamespace(), typeName, TypeDesc.TypeEnum.ENUM);
final XSComplexTypeDefinition ct = complexType ? (XSComplexTypeDefinition) def : null;
final XSSimpleTypeDefinition st = (XSSimpleTypeDefinition) (complexType ? ((XSComplexTypeDefinition) def).getSimpleType() : def);
for (int i = 0; i < st.getLexicalEnumeration().getLength(); i++) {
final String s = st.getLexicalEnumeration().item(i);
td.fdMap.put(s, new FieldDesc(Util.computeEnumConstantName(s, td.name), s));
}
final XSObjectList anns = complexType ? ct.getAnnotations() : st.getAnnotations();
td.documentation = parseAnnotationString("Enumeration " + def.getNamespace() + ":" + def.getName() + " documentation", anns != null && anns.getLength() > 0 ? ((XSAnnotation) anns.item(0)).getAnnotationString() : null);
jtMap.put(model.toJavaQualifiedTypeName(def, nsdMap, true), td);
}
public void processType(XSComplexTypeDefinition def, List<XSModel> models, Map<String, TypeDesc> jtMap, Map<String, NamespaceDesc> nsdMap, ArrayList<XSComplexTypeDefinition> toAdd) throws Exception {
if (!nsdMap.containsKey(def.getNamespace())) {
Util.log("Namespace desc not found for: " + def);
}
String typeName = toJavaTypeName(def, nsdMap);
TypeDesc td = jtMap.get(model.toJavaQualifiedTypeName(def, nsdMap, false));
if (td != null) {
if (td.fdMap.size() == 0) {
// Util.log("Reusing forward decl: "+typeName);
} else {
Util.logerr("merging: type names collision: " + typeName);
}
} else {
td = new TypeDesc(def.getName(), def.getNamespace(), typeName, TypeDesc.TypeEnum.CLASS);
}
XSObjectList anns = def.getAnnotations();
td.documentation = parseAnnotationString("Type " + def.getNamespace() + ":" + def.getName() + " documentation",
anns != null && anns.getLength() > 0 ? ((XSAnnotation) anns.item(0)).getAnnotationString() : null);
TypeDesc tdBase = null;
if (checkComplexType(def.getBaseType())) {
XSComplexTypeDefinition base = (XSComplexTypeDefinition) def.getBaseType();
String typeNameBase = toJavaTypeName(base, nsdMap);
if ((tdBase = jtMap.get(model.toJavaQualifiedTypeName(base, nsdMap, false))) == null) {
// logwarn("forward decl: "+et);
tdBase = new TypeDesc(base.getName(), base.getNamespace(), typeNameBase, TypeDesc.TypeEnum.CLASS);
jtMap.put(model.toJavaQualifiedTypeName(base, nsdMap, false), tdBase);
}
}
if (def.getSimpleType() != null || def.getContentType() == XSComplexTypeDefinition.CONTENTTYPE_MIXED) {
FieldDesc fd = new FieldDesc(FieldDesc.SIMPLE, "value", "String", null, "null", true);
fd.realIndex = td.fdMap.size();
td.fdMap.put(fd.name, fd);
}
XSObjectList attrs = def.getAttributeUses();
for (int i = 0; i < attrs.getLength(); i++) {
XSAttributeUse au = (XSAttributeUse) attrs.item(i);
XSAttributeDeclaration ad = au.getAttrDeclaration();
XSSimpleTypeDefinition atd = ad.getTypeDefinition();
XSAnnotation ann = ad.getAnnotation();
String documentation = parseAnnotationString("Attribute " + ad.getNamespace() + ":" + ad.getName() + " documentation", ann != null ? ann.getAnnotationString() : null);
// skip "ID" and "FIXED"
if ("ID".equals(atd.getName())) continue;
// "language", "dewey-versionType", "boolean"
if (ad.getConstraintType() == XSConstants.VC_FIXED) continue;
FieldDesc fd1 = new FieldDesc(FieldDesc.ATTR, Util.toJavaFieldName(ad.getName()), "String", null, "null", au.getRequired());
fd1.tagName = ad.getName();
fd1.documentation = documentation;
fd1.realIndex = td.fdMap.size();
td.duplicates = Util.addToNameMap(td.fdMap, fd1, false) || td.duplicates;
if (checkEnumType(ad.getTypeDefinition())) {
XSTypeDefinition etRoot = ad.getTypeDefinition();
if (etRoot.getAnonymous()) {
etRoot = makeTypeFromAnonymous(ad);
if (toAdd != null) toAdd.add((XSComplexTypeDefinition) etRoot);
}
fd1.type = toJavaTypeName(etRoot, nsdMap);
fd1.contentQualifiedName = model.toJavaQualifiedTypeName(etRoot, nsdMap, true);
// forward decl
if (jtMap.get(fd1.contentQualifiedName) == null) {
// logwarn("forward decl: "+et);
TypeDesc ftd = new TypeDesc(etRoot.getName(), etRoot.getNamespace(), fd1.type, TypeDesc.TypeEnum.ENUM);
jtMap.put(fd1.contentQualifiedName, ftd);
// // anonymous (simple type) enum
// if (ad.getTypeDefinition().getAnonymous()) {
// processEnumType(ad.getTypeDefinition(), jtMap, nsdMap);
// }
}
} else {
fd1.simpleTypesString = getSimpleTypesString(ad.getTypeDefinition());
}
}
LinkedList<PEntry> plist = new LinkedList<PEntry>();
if (def.getParticle() != null) {
plist.add(new PEntry(def.getParticle(), false));
}
processParticles(def, plist, nsdMap, jtMap, td, models, toAdd, tdBase);
jtMap.put(model.toJavaQualifiedTypeName(def, nsdMap, false), td);
if (td.fdMap.size() == 1 && def.getSimpleType() != null) {
// calc type hierarchy for simple content
FieldDesc fd = td.fdMap.get("value");
fd.simpleTypesString = getSimpleTypesString(def);
}
}
private static String getSimpleTypesString(XSTypeDefinition et) {
StringBuffer typesHierarchy = new StringBuffer();
while (et != null && !"anySimpleType".equals(et.getName()) && !"anyType".equals(et.getName())) {
typesHierarchy.append(et.getNamespace().substring(et.getNamespace().lastIndexOf("/") + 1)).append(":").append(et.getName()).append(";");
if (et instanceof XSSimpleType) {
XSSimpleType simpleType = (XSSimpleType) et;
if (simpleType.getVariety() == XSSimpleTypeDefinition.VARIETY_LIST
|| simpleType.getVariety() == XSSimpleTypeDefinition.VARIETY_UNION) {
XSObjectList list = simpleType.getMemberTypes();
if (list.getLength() > 0) {
typesHierarchy.append("{");
for (int i = 0; i < list.getLength(); i++) {
typesHierarchy.append(getSimpleTypesString((XSTypeDefinition) list.item(i)));
}
typesHierarchy.append("}");
}
}
}
et = et.getBaseType();
}
return typesHierarchy.toString();
}
private TypeDesc processGroup(XSModelGroup modelGroup, List<XSModel> models, Map<String, TypeDesc> jtMap, Map<String, NamespaceDesc> nsdMap) {
XSModelGroupDefinition def = null;
for (XSModel xsModel : models) {
XSNamedMap map = xsModel.getComponents(XSConstants.MODEL_GROUP_DEFINITION);
for (int i = 0; i < map.getLength(); i++) {
XSModelGroupDefinition mg = (XSModelGroupDefinition) map.item(i);
final XSModelGroup xsModelGroup = mg.getModelGroup();
if (xsModelGroup == modelGroup || xsModelGroup.toString().equals(modelGroup.toString())) {
def = mg;
break;
}
}
}
if (def == null) return null;
if (!nsdMap.containsKey(def.getNamespace())) {
Util.log("Namespace desc not found for: " + def);
}
String typeName = toJavaTypeName(def, nsdMap);
final String typeQName = model.toJavaQualifiedTypeName(def, nsdMap, false);
TypeDesc td = jtMap.get(typeQName);
if (td != null) {
if (td.type == TypeDesc.TypeEnum.GROUP_INTERFACE) {
return td;
} else {
Util.logerr("type-group conflict: " + typeName);
return null;
}
} else {
td = new TypeDesc(def.getName(), def.getNamespace(), typeName, TypeDesc.TypeEnum.GROUP_INTERFACE);
}
XSAnnotation ann = def.getAnnotation();
td.documentation = parseAnnotationString("Type " + def.getNamespace() + ":" + def.getName() + " documentation",
ann == null ? null : ann.getAnnotationString());
td.type = TypeDesc.TypeEnum.GROUP_INTERFACE;
LinkedList<PEntry> plist = new LinkedList<PEntry>();
for (int i = 0; i < def.getModelGroup().getParticles().getLength(); i++) {
XSParticle p = (XSParticle) def.getModelGroup().getParticles().item(i);
plist.add(new PEntry(p, false));
}
processParticles(def, plist, nsdMap, jtMap, td, models, null, null);
jtMap.put(typeQName, td);
return td;
}
private void processParticles(XSObject def, LinkedList<PEntry> plist, Map<String, NamespaceDesc> nsdMap, Map<String, TypeDesc> jtMap, TypeDesc td, List<XSModel> models, ArrayList<XSComplexTypeDefinition> toAdd, TypeDesc baseClass) {
final boolean globalMerge = jtMap.containsKey(model.toJavaQualifiedTypeName(def, nsdMap, td.type == TypeDesc.TypeEnum.ENUM));
final HashMap<XSParticle, String> globalChoice = new HashMap<XSParticle, String>();
final ArrayList<XSObjectList> choiceList = new ArrayList<XSObjectList>();
final ArrayList<TypeDesc> supers = new ArrayList<TypeDesc>();
if (baseClass != null) {
supers.add(baseClass);
}
while (!plist.isEmpty()) {
final PEntry pentry = plist.removeFirst();
final XSParticle p = pentry.p;
if (p.getTerm() instanceof XSElementDecl) {
final XSElementDecl el = (XSElementDecl) p.getTerm();
if (el.getConstraintType() == XSConstants.VC_FIXED) continue;
XSTypeDefinition etRoot = el.getTypeDefinition();
XSTypeDefinition et = etRoot;
XSAnnotation ann = el.getAnnotation();
String documentation = parseAnnotationString("Element " + el.getNamespace() + ":" + el.getName() + " documentation", ann != null ? ann.getAnnotationString() : null);
final FieldDesc fd1 = new FieldDesc(FieldDesc.STR, Util.toJavaFieldName(el.getName()), et.getName(), null, "null", !pentry.many && p.getMinOccurs() > 0);
fd1.documentation = documentation;
fd1.tagName = el.getName();
while (et.getBaseType() != null && !"anySimpleType".equals(et.getBaseType().getName()) && !"anyType".equals(et.getBaseType().getName())) {
et = et.getBaseType();
}
if (checkEnumType(etRoot)) {
if (etRoot.getAnonymous()) {
etRoot = makeTypeFromAnonymous(el);
if (toAdd != null) toAdd.add((XSComplexTypeDefinition) etRoot);
}
fd1.type = toJavaTypeName(etRoot, nsdMap);
fd1.clType = FieldDesc.OBJ;
fd1.contentQualifiedName = model.toJavaQualifiedTypeName(etRoot, nsdMap, true);
// forward decl
if (!jtMap.containsKey(fd1.contentQualifiedName)) {
// logwarn("forward decl: "+et);
TypeDesc ftd = new TypeDesc(etRoot.getName(), etRoot.getNamespace(), fd1.type, TypeDesc.TypeEnum.ENUM);
jtMap.put(fd1.contentQualifiedName, ftd);
}
} else if (checkComplexType(etRoot)) {
if (etRoot.getAnonymous()) {
etRoot = makeTypeFromAnonymous(el);
if (toAdd != null) toAdd.add((XSComplexTypeDefinition) etRoot);
}
fd1.type = toJavaTypeName(etRoot, nsdMap);
fd1.clType = FieldDesc.OBJ;
fd1.contentQualifiedName = model.toJavaQualifiedTypeName(etRoot, nsdMap, false);
// forward decl
if (jtMap.get(fd1.contentQualifiedName) == null) {
//logwarn("forward decl: "+etRoot);
jtMap.put(fd1.contentQualifiedName, new TypeDesc(etRoot.getName(), etRoot.getNamespace(), fd1.type, TypeDesc.TypeEnum.CLASS));
}
} else if (checkBooleanType(etRoot)) {
fd1.type = "boolean";
fd1.clType = FieldDesc.BOOL;
} else {
if (etRoot instanceof XSComplexTypeDefinition) {
final XSComplexTypeDefinition ct = (XSComplexTypeDefinition) etRoot;
// XXX xerces2.7.1 wierd annotation inheritance bug fix
//ann = (XSAnnotation) (ct.getAnnotations()!=null && ct.getAnnotations().getLength()>0?ct.getAnnotations().item(0):null);
ann = (XSAnnotation) (ct.getAnnotations() != null && ct.getAnnotations().getLength() > 0 ? ct.getAnnotations().item(ct.getAnnotations().getLength() - 1) : null);
documentation = parseAnnotationString("Type " + ct.getNamespace() + ":" + ct.getName() + " documentation", ann != null ? ann.getAnnotationString() : null);
if (documentation != null) {
fd1.documentation = fd1.documentation != null ? fd1.documentation + "\n" + documentation : documentation;
}
}
fd1.simpleTypesString = getSimpleTypesString(etRoot);
// "fully-qualified-classType", "jndi-nameType", "transaction-typeType"
// "java-identifierType", "pathType"
fd1.type = et.getName();
if (fd1.type == null) {
fd1.type = "String";
fd1.def = "null";
fd1.clType = FieldDesc.STR;
// fd1.type = "boolean";
// fd1.def = "false";
// fd1.clType = FieldDesc.BOOL;
} else if (fd1.type.equals("string") || fd1.type.equals("anyURI")) {
fd1.type = "String";
} else if (fd1.type.equals("boolean")) {
fd1.type = "String";
} else if (fd1.type.equals("emptyType")) {
fd1.type = "boolean";
fd1.def = "false";
fd1.clType = FieldDesc.BOOL;
} else if (fd1.type.equals("decimal")) {
fd1.type = "String";
fd1.def = "\"0.0\"";
} else if (fd1.type.equals("QName")) {
fd1.type = "String";
} else if (fd1.type.equals("extensibleType")) {
fd1.type = "Object";
} else {
if ("anySimpleType".equals(et.getBaseType().getName())
|| "anyType".equals(et.getBaseType().getName())) {
fd1.type = "String";
fd1.def = "null";
fd1.clType = FieldDesc.STR;
} else {
fd1.type = "boolean";
fd1.def = "false";
fd1.clType = FieldDesc.BOOL;
}
Util.logwarn("using '" + fd1.type + "' for unknown base type: " + et.getName() + " for " + el);
}
}
if ((pentry.many || p.getMaxOccursUnbounded() || p.getMaxOccurs() > 1) && fd1.clType != FieldDesc.BOOL) {
fd1.elementType = fd1.type;
fd1.elementName = fd1.name;
fd1.type = "List<" + fd1.elementType + ">";
fd1.name = Util.pluralize(fd1.name);
fd1.def = "new ArrayList(0)";
fd1.clType = -fd1.clType;
fd1.comment = "array of " + fd1.elementType;
}
fd1.realIndex = td.fdMap.size();
boolean merge = globalMerge || globalChoice.containsKey(p) && globalChoice.values().contains(fd1.name);
td.duplicates = Util.addToNameMap(td.fdMap, fd1, merge) || td.duplicates;
globalChoice.put(p, fd1.name);
} else if (p.getTerm() instanceof XSModelGroup) {
boolean addToGlobalChoice = false;
boolean many = p.getMaxOccursUnbounded() || p.getMaxOccurs() > 1;
XSObjectList l = ((XSModelGroup) p.getTerm()).getParticles();
if (!many) {
if (((XSModelGroup) p.getTerm()).getCompositor() == XSModelGroup.COMPOSITOR_CHOICE) {
addToGlobalChoice = true;
choiceList.add(l);
} else {
// generate group interface???
XSModelGroup groupDef = (XSModelGroup) p.getTerm();
TypeDesc gtd = processGroup(groupDef, models, jtMap, nsdMap);
if (gtd != null) supers.add(gtd);
}
}
if (globalChoice.containsKey(p)) {
addToGlobalChoice = true;
}
for (int i = 0; i < l.getLength(); i++) {
final PEntry o = new PEntry((XSParticle) l.item(i), many);
plist.add(o);
if (addToGlobalChoice && !globalChoice.containsKey(o.p)) {
globalChoice.put(o.p, null);
}
}
}
}
int i = 0;
for (Iterator<FieldDesc> it = td.fdMap.values().iterator(); it.hasNext(); i++) {
FieldDesc fd = it.next();
fd.idx = i;
}
for (XSObjectList l : choiceList) {
final ArrayList<XSParticle> clist = new ArrayList<XSParticle>();
final LinkedList<XSParticle> elist = new LinkedList<XSParticle>();
for (i = 0; i < l.getLength(); i++) {
elist.add((XSParticle) l.item(i));
}
while (!elist.isEmpty()) {
final XSParticle p = elist.removeFirst();
if (p.getTerm() instanceof XSModelGroup) {
XSObjectList l2 = ((XSModelGroup) p.getTerm()).getParticles();
for (int i2 = 0; i2 < l2.getLength(); i2++) {
elist.addFirst((XSParticle) l2.item(i2));
}
} else if (p.getTerm() instanceof XSElementDecl) {
clist.add(p);
}
}
boolean choiceOpt = true;
FieldDesc[] choice = new FieldDesc[clist.size()];
for (i = 0; i < choice.length; i++) {
XSParticle p = clist.get(i);
XSElementDecl el = (XSElementDecl) p.getTerm();
String s = Util.toJavaFieldName(el.getName());
if (p.getMaxOccursUnbounded() || p.getMaxOccurs() > 1) {
s = Util.pluralize(s);
}
FieldDesc fd = td.fdMap.get(s);
if (fd == null) {
fd = td.fdMap.get(Util.pluralize(s));
if (fd == null) {
Util.logerr("uknown choice element: " + s);
}
}
choice[i] = fd;
choice[i].choice = choice;
if (fd.required) choiceOpt = false;
}
for (i = 0; i < choice.length; i++) {
choice[i].choiceOpt = choiceOpt;
}
}
td.supers = supers.toArray(new TypeDesc[supers.size()]);
}
public static String parseAnnotationString(String title, String str) {
if (str == null) return null;
int idx = str.indexOf(":documentation");
if (idx == -1) idx = str.indexOf("<documentation");
if (idx == -1) return null;
idx = str.indexOf(">", idx + 1);
if (idx == -1) return null;
int idx2 = str.indexOf(":documentation", idx + 1);
if (idx2 == -1) idx2 = str.indexOf("</documentation", idx + 1);
idx2 = str.lastIndexOf("<", idx2 + 1);
str = str.substring(idx + 1, idx2).trim();
idx = str.indexOf("<![CDATA[");
if (idx > -1) {
idx = str.indexOf("[", idx + 3);
idx2 = str.indexOf("]]>", idx + 1);
str = str.substring(idx + 1, idx2);
}
return "<pre>\n<h3>" + title + "</h3>\n" + str + "\n</pre>";
}
public String toJavaTypeName(XSObject xs, Map<String, NamespaceDesc> nsdMap) {
String name = xs.getName();
if (name == null) {
if (xs instanceof TypeInfo) {
name = ((TypeInfo) xs).getTypeName();
if (name != null && name.startsWith("#")) {
name = name.substring(1);
}
}
}
return model.toJavaTypeName(name, xs.getNamespace());
}
public static class PEntry {
public PEntry(XSParticle p, boolean many) {
this.p = p;
this.many = many;
}
XSParticle p;
boolean many;
}
}
@@ -21,6 +21,25 @@ public abstract class DomChildDescriptionImpl extends AbstractDomChildDescriptio
myTagName = tagName;
}
public String getName() {
return myTagName.getLocalName();
}
public boolean isValid() {
return true;
}
public void navigate(boolean requestFocus) {
}
public boolean canNavigate() {
return false;
}
public boolean canNavigateToSource() {
return false;
}
@NotNull
public String getXmlElementName() {
return myTagName.getLocalName();
@@ -17,9 +17,9 @@ package com.intellij.xml.impl.dom;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.references.PomService;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.FakePsiElement;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlFile;
@@ -204,11 +204,7 @@ public class DomElementXmlDescriptor implements XmlElementDescriptor {
if (declaration != null) return declaration.getXmlElement();
return new FakePsiElement() {
public PsiElement getParent() {
return DomUtil.getFile(mySomeElement);
}
};
return PomService.convertToPsi(myManager.getProject(), myChildrenDescription);
}
@NonNls
@@ -255,6 +251,25 @@ public class DomElementXmlDescriptor implements XmlElementDescriptor {
myDomElement = domElement;
}
public String getName() {
return getXmlElementName();
}
public boolean isValid() {
return true;
}
public void navigate(boolean requestFocus) {
}
public boolean canNavigate() {
return false;
}
public boolean canNavigateToSource() {
return false;
}
@NotNull
public XmlName getXmlName() {
throw new UnsupportedOperationException("Method getXmlName not implemented in " + getClass());
@@ -304,4 +319,5 @@ public class DomElementXmlDescriptor implements XmlElementDescriptor {
throw new UnsupportedOperationException("Method getAnnotation not implemented in " + getClass());
}
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.util.xml.reflect;
import com.intellij.pom.PomNamedTarget;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomNameStrategy;
import com.intellij.util.xml.XmlName;
@@ -23,7 +24,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @author peter
*/
public interface DomChildrenDescription extends AbstractDomChildrenDescription {
public interface DomChildrenDescription extends AbstractDomChildrenDescription, PomNamedTarget {
@NotNull
XmlName getXmlName();