You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2015/07/30 21:48:54 UTC
[55/80] zest-java git commit: Stage 2 of the namespace change. Bulk
of documentation fixed.
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/inspections/ConcernsAnnotationDeclaredCorrectlyInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/inspections/ConcernsAnnotationDeclaredCorrectlyInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/inspections/ConcernsAnnotationDeclaredCorrectlyInspection.java
new file mode 100644
index 0000000..fc598d5
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/inspections/ConcernsAnnotationDeclaredCorrectlyInspection.java
@@ -0,0 +1,173 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.concerns.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiAnnotationMemberValue;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiJavaCodeReferenceElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractInspection;
+import org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.psi.search.GlobalSearchScopeUtil.determineSearchScope;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.*;
+
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class ConcernsAnnotationDeclaredCorrectlyInspection extends AbstractInspection
+{
+ @NotNull
+ protected final String resourceBundlePrefixId()
+ {
+ return "concerns.annotation.declared.correctly";
+ }
+
+ @NotNull
+ public final String getShortName()
+ {
+ return "ConcernsAnnotationDeclaredCorrectlyInspection";
+ }
+
+ @Override
+ public final ProblemDescriptor[] checkClass( @NotNull PsiClass psiClass,
+ @NotNull InspectionManager manager,
+ boolean isOnTheFly )
+ {
+ // If class does not have @Concerns, ignore
+ PsiAnnotation concernsAnnotation = getConcernsAnnotation( psiClass );
+ if( concernsAnnotation == null )
+ {
+ return null;
+ }
+
+ // If @Concerns declared in class, suggest remove @Concerns annotation
+ if( !psiClass.isInterface() )
+ {
+ String message = message( "concerns.annotation.declared.correctly.error.annotation.declared.in.class" );
+ RemoveConcernsAnnotationFix fix = new RemoveConcernsAnnotationFix( concernsAnnotation );
+ ProblemDescriptor problemDescriptor = manager.createProblemDescriptor( concernsAnnotation, message, fix,
+ GENERIC_ERROR_OR_WARNING );
+ return new ProblemDescriptor[]{ problemDescriptor };
+ }
+
+ // If @Concerns annotation is empty, ignore
+ List<PsiAnnotationMemberValue> concernsAnnotationValue = getConcernsAnnotationValue( concernsAnnotation );
+ if( concernsAnnotationValue.isEmpty() )
+ {
+ return null;
+ }
+
+ // If ConcernOfClass is not resolved, ignore
+ Project project = psiClass.getProject();
+ GlobalSearchScope searchScope = determineSearchScope( psiClass );
+ PsiClass concernOfClass = getConcernOfClass( project, searchScope );
+ if( concernOfClass == null )
+ {
+ return null;
+ }
+
+ List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
+ for( PsiAnnotationMemberValue concernClassAnnotationValue : concernsAnnotationValue )
+ {
+ PsiJavaCodeReferenceElement concernClassReference = getConcernClassReference( concernClassAnnotationValue );
+
+ // If it's not a class reference, ignore
+ if( concernClassReference == null )
+ {
+ continue;
+ }
+
+ // If class reference can't be resolved, ignore
+ PsiClass concernClass = (PsiClass) concernClassReference.resolve();
+ if( concernClass == null )
+ {
+ continue;
+ }
+
+ // If concern class does not inherit concern class, suggest remove that reference.
+ if( !concernClass.isInheritor( concernOfClass, true ) )
+ {
+ String message = Qi4jResourceBundle.message(
+ "concerns.annotation.declared.correctly.error.concern.class.does.not.extend.ConcernOf",
+ concernClass.getQualifiedName()
+ );
+
+ RemoveInvalidConcernClassReferenceFix fix = new RemoveInvalidConcernClassReferenceFix(
+ concernClassAnnotationValue, concernClassReference
+ );
+ ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+ concernClassAnnotationValue, message, fix, GENERIC_ERROR_OR_WARNING );
+ problems.add( problemDescriptor );
+ }
+ else
+ {
+ // TODO: Test whether it is a generic concern
+ // TODO: Test whether it is a specific concern
+ }
+ }
+
+ return problems.toArray( new ProblemDescriptor[problems.size()] );
+ }
+
+ private static class RemoveConcernsAnnotationFix extends AbstractFix
+ {
+ private final PsiAnnotation annotationToRemove;
+
+ private RemoveConcernsAnnotationFix( @NotNull PsiAnnotation annotationToRemove )
+ {
+ super( message( "concerns.annotation.declared.correctly.fix.remove.annotation" ) );
+ this.annotationToRemove = annotationToRemove;
+ }
+
+ public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+ {
+ annotationToRemove.delete();
+ }
+ }
+
+ private static class RemoveInvalidConcernClassReferenceFix extends AbstractFix
+ {
+ private final PsiAnnotationMemberValue concernClassAnnotationValue;
+
+ public RemoveInvalidConcernClassReferenceFix( @NotNull PsiAnnotationMemberValue annotationValueToRemove,
+ @NotNull PsiJavaCodeReferenceElement concernClassReference )
+ {
+ super( message( "concerns.annotation.declared.correctly.fix.remove.concern.class.reference",
+ concernClassReference.getQualifiedName() ) );
+ this.concernClassAnnotationValue = annotationValueToRemove;
+ }
+
+ public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+ {
+ concernClassAnnotationValue.delete();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/intentions/add/AddConcernOnType.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/intentions/add/AddConcernOnType.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/intentions/add/AddConcernOnType.java
new file mode 100644
index 0000000..9a06c04
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/concerns/intentions/add/AddConcernOnType.java
@@ -0,0 +1,138 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.concerns.intentions.add;
+
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.Processor;
+import com.intellij.util.Query;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.common.intentions.AbstractIntention;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.intellij.psi.search.searches.ClassInheritorsSearch.search;
+import static java.util.Collections.emptyList;
+import static org.apache.zest.ide.plugin.idea.common.psi.search.GlobalSearchScopeUtil.determineSearchScope;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.addOrReplaceConcernAnnotation;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.getConcernOfClass;
+
+/**
+ * JAVADOC: This is disabled in Qi4jApplicationComponent.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class AddConcernOnType
+ extends AbstractIntention
+{
+ protected boolean isIntentionValidFor( PsiElement element )
+ {
+ if( !( element instanceof PsiClass ) )
+ {
+ return false;
+ }
+
+ // If it's not interface, ignore it
+ PsiClass psiClass = (PsiClass) element;
+ if( !psiClass.isInterface() )
+ {
+ return false;
+ }
+
+ // Is @Concerns accesible within module
+ GlobalSearchScope searchScope = determineSearchScope( psiClass );
+ PsiClass concernOfClass = getConcernOfClass( psiClass.getProject(), searchScope );
+ return concernOfClass != null;
+ }
+
+ protected final String resourceBundlePrefixId()
+ {
+ return "add.concern";
+ }
+
+ @Override
+ public boolean isAvailable( @NotNull Project project, Editor editor, @Nullable PsiElement element )
+ {
+ while( element != null )
+ {
+ if( element instanceof PsiFile ||
+ element instanceof PsiMethod )
+ {
+ break;
+ }
+
+ if( isIntentionValidFor( element ) )
+ {
+ return true;
+ }
+
+ element = element.getParent();
+ }
+
+ return false;
+ }
+
+ @SuppressWarnings( "unchecked" )
+ protected void processIntention( @NotNull Project project, @NotNull Editor editor, @NotNull PsiElement element )
+ {
+ PsiClass psiClass = (PsiClass) element;
+ List<PsiClass> concernCandidates = findConcernsCandidates( psiClass );
+ if( concernCandidates.size() == 1 )
+ {
+ PsiClass concernCandidate = concernCandidates.get( 0 );
+ addOrReplaceConcernAnnotation( psiClass, concernCandidate );
+ }
+ }
+
+ private static List<PsiClass> findConcernsCandidates( final @NotNull PsiClass classToCheck )
+ {
+ GlobalSearchScope searchScope = determineSearchScope( classToCheck );
+ PsiClass concernOfClass = getConcernOfClass( classToCheck.getProject(), searchScope );
+ if( concernOfClass == null )
+ {
+ return emptyList();
+ }
+
+ Query<PsiClass> psiClassQuery = search( concernOfClass, searchScope, true, false );
+ final List<PsiClass> concernCandidates = new ArrayList<PsiClass>();
+ psiClassQuery.forEach( new Processor<PsiClass>()
+ {
+ public boolean process( PsiClass psiClass )
+ {
+ // TODO: Ideally search for all "extends" as well
+ boolean isInheritor = psiClass.isInheritor( classToCheck, true );
+ if( isInheritor )
+ {
+ concernCandidates.add( psiClass );
+ }
+
+ return true;
+ }
+ } );
+
+ return concernCandidates;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection.java
new file mode 100644
index 0000000..d84fb33
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection.java
@@ -0,0 +1,90 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.common.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.PsiParameter;
+import com.intellij.psi.PsiParameterList;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static java.util.Arrays.asList;
+
+/**
+ * {@code AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection} is a helper method to check whether
+ * injection annotation are declared in either constructor or non static field.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public abstract class AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection
+ extends AbstractInjectionAnnotationDeclarationOnFieldInspection
+{
+ @Override
+ public final ProblemDescriptor[] checkMethod( @NotNull PsiMethod method,
+ @NotNull InspectionManager manager,
+ boolean isOnTheFly )
+ {
+ PsiParameterList parameterList = method.getParameterList();
+ PsiParameter[] parameters = parameterList.getParameters();
+ if( method.isConstructor() )
+ {
+ List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
+ for( PsiParameter parameter : parameters )
+ {
+ PsiAnnotation annotation = getAnnotationToCheck( parameter );
+ if( annotation != null )
+ {
+ ProblemDescriptor[] descriptors =
+ verifyAnnotationDeclaredCorrectly( parameter, annotation, manager );
+ if( descriptors != null )
+ {
+ problems.addAll( asList( descriptors ) );
+ }
+ }
+ }
+
+ return problems.toArray( new ProblemDescriptor[problems.size()] );
+ }
+ else
+ {
+ List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
+ for( PsiParameter parameter : parameters )
+ {
+ PsiAnnotation annotationToCheck = getAnnotationToCheck( parameter );
+ if( annotationToCheck != null )
+ {
+ String message = getInjectionAnnotationValidDeclarationMessage();
+ AbstractFix removeAnnotationFix = createRemoveAnnotationFix( annotationToCheck );
+ ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+ annotationToCheck, message, removeAnnotationFix, GENERIC_ERROR_OR_WARNING
+ );
+ problems.add( problemDescriptor );
+ }
+ }
+
+ return problems.toArray( new ProblemDescriptor[problems.size()] );
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldInspection.java
new file mode 100644
index 0000000..88b3e24
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/common/inspections/AbstractInjectionAnnotationDeclarationOnFieldInspection.java
@@ -0,0 +1,138 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.common.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiModifierList;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractInspection;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public abstract class AbstractInjectionAnnotationDeclarationOnFieldInspection extends AbstractInspection
+{
+ /**
+ * @return Remove annotation message fix.
+ * @since 0.1
+ */
+ @NotNull
+ protected abstract String getRemoveAnnotationMessageFix();
+
+ /**
+ * @return Annotation to check qualified name.
+ * @since 0.1
+ */
+ @NotNull
+ protected abstract String getAnnotationToCheckQualifiedName();
+
+ /**
+ * Verified that {@link #getAnnotationToCheck(com.intellij.psi.PsiVariable)} is declared correctly.
+ *
+ * @param psiVariable Variable to check. This could be class field member or constructor parameter.
+ * @param annotationToCheck annotation declared at variable to check.
+ * @param manager Inspection manager to use to create problem descriptor.
+ * @return {@code null} if annotation is declared correctly, otherwise an array of problem descriptor.
+ * @since 0.1
+ */
+ @Nullable
+ protected abstract ProblemDescriptor[] verifyAnnotationDeclaredCorrectly( @NotNull PsiVariable psiVariable,
+ @NotNull PsiAnnotation annotationToCheck,
+ @NotNull InspectionManager manager );
+
+ @Override
+ public final ProblemDescriptor[] checkField( @NotNull PsiField field,
+ @NotNull InspectionManager manager,
+ boolean isOnTheFly )
+ {
+ PsiAnnotation annotationToCheck = getAnnotationToCheck( field );
+ if( annotationToCheck == null )
+ {
+ return null;
+ }
+
+ PsiModifierList modifierList = field.getModifierList();
+ if( modifierList != null )
+ {
+ if( modifierList.hasModifierProperty( com.intellij.psi.PsiModifier.STATIC ) )
+ {
+ String message = getInjectionAnnotationValidDeclarationMessage();
+ AbstractFix removeAnnotationFix = createRemoveAnnotationFix( annotationToCheck );
+ ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+ annotationToCheck, message, removeAnnotationFix, com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING
+ );
+
+ return new ProblemDescriptor[]{ problemDescriptor };
+ }
+ }
+
+ return verifyAnnotationDeclaredCorrectly( field, annotationToCheck, manager );
+ }
+
+ /**
+ * @param variable variable to check.
+ * @return Annotation to check.
+ * @see #getAnnotationToCheckQualifiedName()
+ * @since 0.1
+ */
+ @Nullable
+ protected final PsiAnnotation getAnnotationToCheck( @NotNull PsiVariable variable )
+ {
+ String annotationQualifiedName = getAnnotationToCheckQualifiedName();
+ return findAnnotation( variable, annotationQualifiedName );
+ }
+
+ @NotNull protected String getInjectionAnnotationValidDeclarationMessage()
+ {
+ String annotationQualifiedName = getAnnotationToCheckQualifiedName();
+ return org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message( "abstract.injection.annotation.declaration.inspection.error.annotation.not.declared.correctly",
+ annotationQualifiedName );
+ }
+
+ @NotNull
+ protected final AbstractFix createRemoveAnnotationFix( @NotNull PsiAnnotation annotationToRemove )
+ {
+ String fixMessage = getRemoveAnnotationMessageFix();
+ return new RemoveAnnotationFix( fixMessage, annotationToRemove );
+ }
+
+ private static class RemoveAnnotationFix extends AbstractFix
+ {
+ private final PsiAnnotation annotationToRemove;
+
+ public RemoveAnnotationFix( @NotNull String fixMessage, @NotNull PsiAnnotation annotationToRemove )
+ {
+ super( fixMessage );
+ this.annotationToRemove = annotationToRemove;
+ }
+
+ public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+ {
+ annotationToRemove.delete();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationConstants.java
new file mode 100644
index 0000000..c2004c6
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationConstants.java
@@ -0,0 +1,30 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.invocation.common;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jInvocationAnnotationConstants
+{
+ public static final String QUALIFIED_NAME_INVOCATION_ANNOTATION = "org.qi4j.api.injection.scope.Invocation";
+
+ private Qi4jInvocationAnnotationConstants()
+ {
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationUtil.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationUtil.java
new file mode 100644
index 0000000..c7ef6da
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/common/Qi4jInvocationAnnotationUtil.java
@@ -0,0 +1,127 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.invocation.common;
+
+import com.intellij.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+import static com.intellij.psi.PsiModifier.STATIC;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiClassUtil.getPSIClass;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationConstants.QUALIFIED_NAME_INVOCATION_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationUtil.InvocationAnnotationDeclarationValidationResult.*;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.isInjecteableByStructureAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jInvocationAnnotationUtil
+{
+ /**
+ * Returns {@code @Invocation} annotation if exists.
+ *
+ * @param modifierListOwner modifier list owner to process.
+ * @return {@code @Invocation} annotation if exists, {@code null} otherwise.
+ * @since 0.1
+ */
+ @Nullable
+ public static PsiAnnotation getInvocationAnnotation( @NotNull PsiModifierListOwner modifierListOwner )
+ {
+ return findAnnotation( modifierListOwner, QUALIFIED_NAME_INVOCATION_ANNOTATION );
+ }
+
+ /**
+ * @param psiClass psi class to check.
+ * @return {@code true} if the specified psiClass is injectable by invocation annotation, {@code false} otherwise.
+ */
+ public static boolean isInjectableByInvocationAnnotation( @NotNull PsiClass psiClass )
+ {
+ if( psiClass.isAnnotationType() )
+ {
+ return true;
+ }
+
+ String classQualifiedName = psiClass.getQualifiedName();
+ return "java.lang.reflect.Method".equals( classQualifiedName ) ||
+ "java.lang.reflect.AnnotatedElement".equals( classQualifiedName );
+ }
+
+ /**
+ * Validates whether the variable has {@code @Invocation} annotation declared correctly.
+ *
+ * @param variable variable to check.
+ * @return Look at {@link InvocationAnnotationDeclarationValidationResult}.
+ * @since 0.1
+ */
+ @NotNull
+ public static InvocationAnnotationDeclarationValidationResult isValidInvocationAnnotationDeclaration(
+ @NotNull PsiVariable variable )
+ {
+ PsiAnnotation invocationAnnotation = getInvocationAnnotation( variable );
+ if( invocationAnnotation == null )
+ {
+ return invalidInvocationAnnotationNotDeclared;
+ }
+
+ PsiModifierList modifierList = variable.getModifierList();
+ if( modifierList != null )
+ {
+ if( modifierList.hasModifierProperty( STATIC ) )
+ {
+ return invalidDeclaredOnStaticVariable;
+ }
+ }
+
+ // TODO: Check whether variable is either an instance of java.lang.reflect.Method or
+ // java.lang.reflect.AnnotatedElement or Annotation
+ PsiTypeElement typeElement = variable.getTypeElement();
+ if( typeElement != null )
+ {
+ PsiClass psiClass = getPSIClass( typeElement );
+ if( psiClass != null )
+ {
+ if( !isInjectableByInvocationAnnotation( psiClass ) )
+ {
+ // Can't be type that is injected by @Structure
+ if( isInjecteableByStructureAnnotation( variable ) )
+ {
+ return invalidTypeIsInjectedViaStructureAnnotation;
+ }
+
+ return invalidType;
+ }
+ }
+ }
+
+ return valid;
+ }
+
+ public enum InvocationAnnotationDeclarationValidationResult
+ {
+ invalidInvocationAnnotationNotDeclared,
+ invalidDeclaredOnStaticVariable,
+ invalidTypeIsInjectedViaStructureAnnotation,
+ invalidType,
+ valid,
+ }
+
+ private Qi4jInvocationAnnotationUtil()
+ {
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/inspections/InvocationAnnotationDeclaredCorrectlyInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/inspections/InvocationAnnotationDeclaredCorrectlyInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/inspections/InvocationAnnotationDeclaredCorrectlyInspection.java
new file mode 100644
index 0000000..57e9b60
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/invocation/inspections/InvocationAnnotationDeclaredCorrectlyInspection.java
@@ -0,0 +1,119 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.invocation.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.injections.common.inspections.AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection;
+import org.apache.zest.ide.plugin.idea.injections.structure.common.ReplaceWithStructureAnnotation;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationConstants.QUALIFIED_NAME_INVOCATION_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationUtil.InvocationAnnotationDeclarationValidationResult;
+import static org.apache.zest.ide.plugin.idea.injections.invocation.common.Qi4jInvocationAnnotationUtil.isValidInvocationAnnotationDeclaration;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.getStructureAnnotation;
+
+/**
+ * {@code InvocationAnnotationDeclaredCorrectlyInspection} validates {@code @Invocation} injection annotation
+ * declaration.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public class InvocationAnnotationDeclaredCorrectlyInspection
+ extends AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection
+{
+ @NotNull
+ protected final String resourceBundlePrefixId()
+ {
+ return "injections.invocation.annotation.declared.correctly";
+ }
+
+ @NotNull
+ public final String getShortName()
+ {
+ return "InvocationAnnotationDeclaredCorrectlyInspection";
+ }
+
+ @NotNull
+ protected final String getRemoveAnnotationMessageFix()
+ {
+ return message( "injections.invocation.annotation.declared.correctly.fix.remove.annotation" );
+ }
+
+ @NotNull
+ protected final String getAnnotationToCheckQualifiedName()
+ {
+ return QUALIFIED_NAME_INVOCATION_ANNOTATION;
+ }
+
+ @Nullable
+ protected final ProblemDescriptor[] verifyAnnotationDeclaredCorrectly( @NotNull PsiVariable psiVariable,
+ @NotNull PsiAnnotation invocationAnnotation,
+ @NotNull InspectionManager manager )
+ {
+ LocalQuickFix fix = null;
+ String message = null;
+
+ String variableTypeQualifiedName = psiVariable.getType().getCanonicalText();
+
+ InvocationAnnotationDeclarationValidationResult validationResult =
+ isValidInvocationAnnotationDeclaration( psiVariable );
+ switch( validationResult )
+ {
+ case invalidTypeIsInjectedViaStructureAnnotation:
+ if( getStructureAnnotation( psiVariable ) == null )
+ {
+ fix = new ReplaceWithStructureAnnotation(
+ message( "injections.invocation.annotation.declared.correctly.fix.replace.with.structure.annotation" ),
+ invocationAnnotation );
+ }
+ message = message(
+ "injections.invocation.annotation.declared.correctly.error.type.is.injected.by.structure",
+ variableTypeQualifiedName
+ );
+ break;
+
+ case invalidType:
+ message = message( "injections.invocation.annotation.declared.correctly.error.type.is.not.injectable",
+ variableTypeQualifiedName );
+ break;
+ }
+
+ // If it's not an error, return null
+ if( message == null )
+ {
+ return null;
+ }
+
+ // If Fix not defined, by default we remove it.
+ if( fix == null )
+ {
+ fix = createRemoveAnnotationFix( invocationAnnotation );
+ }
+
+ ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+ invocationAnnotation, message, fix, GENERIC_ERROR_OR_WARNING );
+ return new ProblemDescriptor[]{ problemDescriptor };
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationConstants.java
new file mode 100644
index 0000000..4ab8602
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationConstants.java
@@ -0,0 +1,30 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.service.common;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jServiceAnnotationConstants
+{
+ public static final String QUALIFIED_NAME_SERVICE_ANNOTATION = "org.qi4j.api.injection.scope.Service";
+
+ private Qi4jServiceAnnotationConstants()
+ {
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationUtil.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationUtil.java
new file mode 100644
index 0000000..824466c
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/common/Qi4jServiceAnnotationUtil.java
@@ -0,0 +1,97 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.service.common;
+
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiModifierList;
+import com.intellij.psi.PsiModifierListOwner;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+import static com.intellij.psi.PsiModifier.STATIC;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationConstants.QUALIFIED_NAME_SERVICE_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationUtil.ServiceAnnotationDeclarationValidationResult.*;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.isInjecteableByStructureAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jServiceAnnotationUtil
+{
+ /**
+ * Returns {@code @Service} annotation if exists.
+ *
+ * @param modifierListOwner modifier list owner to process.
+ * @return {@code @Service} annotation if exists, {@code null} otherwise.
+ * @since 0.1
+ */
+ @Nullable
+ public static PsiAnnotation getServiceAnnotation( @NotNull PsiModifierListOwner modifierListOwner )
+ {
+ return findAnnotation( modifierListOwner, QUALIFIED_NAME_SERVICE_ANNOTATION );
+ }
+
+ /**
+ * Validates whether the variable has {@code @Service} annotation declared correctly.
+ *
+ * @param variable variable to check.
+ * @return Look at {@link ServiceAnnotationDeclarationValidationResult}.
+ * @since 0.1
+ */
+ @NotNull
+ public static ServiceAnnotationDeclarationValidationResult isValidServiceAnnotationDeclaration(
+ @NotNull PsiVariable variable )
+ {
+ PsiAnnotation serviceAnnotation = getServiceAnnotation( variable );
+ if( serviceAnnotation == null )
+ {
+ return invalidServiceAnnotationNotDeclared;
+ }
+
+ PsiModifierList modifierList = variable.getModifierList();
+ if( modifierList != null )
+ {
+ if( modifierList.hasModifierProperty( STATIC ) )
+ {
+ return invalidDeclaredOnStaticVariable;
+ }
+ }
+
+ // Can't be type that is injected by @Structure
+ if( isInjecteableByStructureAnnotation( variable ) )
+ {
+ return invalidTypeIsInjectedViaStructureAnnotation;
+ }
+
+ return valid;
+ }
+
+ public enum ServiceAnnotationDeclarationValidationResult
+ {
+ invalidServiceAnnotationNotDeclared,
+ invalidDeclaredOnStaticVariable,
+ invalidTypeIsInjectedViaStructureAnnotation,
+ valid,
+ }
+
+ private Qi4jServiceAnnotationUtil()
+ {
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/inspections/ServiceAnnotationDeclaredCorrectlyInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/inspections/ServiceAnnotationDeclaredCorrectlyInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/inspections/ServiceAnnotationDeclaredCorrectlyInspection.java
new file mode 100644
index 0000000..be3a82b
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/service/inspections/ServiceAnnotationDeclaredCorrectlyInspection.java
@@ -0,0 +1,110 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.service.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.injections.common.inspections.AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection;
+import org.apache.zest.ide.plugin.idea.injections.structure.common.ReplaceWithStructureAnnotation;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationConstants.QUALIFIED_NAME_SERVICE_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationUtil.ServiceAnnotationDeclarationValidationResult;
+import static org.apache.zest.ide.plugin.idea.injections.service.common.Qi4jServiceAnnotationUtil.isValidServiceAnnotationDeclaration;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.getStructureAnnotation;
+
+/**
+ * {@code ServiceAnnotationDeclaredCorrectly} validates {@code @Service} injection annotation declaration.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public class ServiceAnnotationDeclaredCorrectlyInspection
+ extends AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection
+{
+ @NotNull
+ protected final String resourceBundlePrefixId()
+ {
+ return "injections.service.annotation.declared.correctly";
+ }
+
+ @NotNull
+ public final String getShortName()
+ {
+ return "ServiceAnnotationDeclaredCorrectlyInspection";
+ }
+
+ @NotNull
+ protected final String getRemoveAnnotationMessageFix()
+ {
+ return message( "injections.service.annotation.declared.correctly.fix.remove.annotation" );
+ }
+
+ @NotNull
+ protected final String getAnnotationToCheckQualifiedName()
+ {
+ return QUALIFIED_NAME_SERVICE_ANNOTATION;
+ }
+
+ @Nullable
+ protected final ProblemDescriptor[] verifyAnnotationDeclaredCorrectly( @NotNull PsiVariable psiVariable,
+ @NotNull PsiAnnotation serviceAnnotation,
+ @NotNull InspectionManager manager )
+ {
+ ServiceAnnotationDeclarationValidationResult annotationCheck =
+ isValidServiceAnnotationDeclaration( psiVariable );
+ String message = null;
+ LocalQuickFix fix = null;
+ switch( annotationCheck )
+ {
+ case invalidTypeIsInjectedViaStructureAnnotation:
+ if( getStructureAnnotation( psiVariable ) == null )
+ {
+ fix = new ReplaceWithStructureAnnotation(
+ message( "injections.service.annotation.declared.correctly.fix.replace.with.structure.annotation" ),
+ serviceAnnotation );
+ }
+ message = message(
+ "injections.service.annotation.declared.correctly.error.type.is.injected.by.structure",
+ psiVariable.getType().getCanonicalText()
+ );
+ break;
+ }
+
+ // If it's not an error, return null
+ if( message == null )
+ {
+ return null;
+ }
+
+ // Default behavior to remove @Service annotation
+ if( fix == null )
+ {
+ fix = createRemoveAnnotationFix( serviceAnnotation );
+ }
+
+ ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+ serviceAnnotation, message, fix, GENERIC_ERROR_OR_WARNING );
+ return new ProblemDescriptor[]{ problemDescriptor };
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationConstants.java
new file mode 100644
index 0000000..9635ad4
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationConstants.java
@@ -0,0 +1,51 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.structure.common;
+
+import static java.util.Arrays.sort;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jStructureAnnotationConstants
+{
+ public static final String QUALIFIED_NAME_STRUCTURE_ANNOTATION = "org.qi4j.api.injection.scope.Structure";
+
+ public static final String[] VALID_STRUCTURE_INJECTION_TYPE;
+
+ static
+ {
+ VALID_STRUCTURE_INJECTION_TYPE = new String[]
+ {
+ "org.qi4j.composite.CompositeBuilderFactory",
+ "org.qi4j.object.ObjectBuilderFactory",
+ "org.qi4j.entity.UnitOfWorkFactory",
+ "org.qi4j.service.ServiceFinder",
+ "org.qi4j.structure.Module",
+ "org.qi4j.structure.Layer",
+ "org.qi4j.structure.Application",
+ "org.qi4j.Qi4j",
+ "org.qi4j.spi.Qi4jSPI"
+ };
+ sort( VALID_STRUCTURE_INJECTION_TYPE );
+ }
+
+ private Qi4jStructureAnnotationConstants()
+ {
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationUtil.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationUtil.java
new file mode 100644
index 0000000..da54dd9
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/Qi4jStructureAnnotationUtil.java
@@ -0,0 +1,122 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.structure.common;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+import static com.intellij.psi.PsiModifier.STATIC;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationConstants.QUALIFIED_NAME_STRUCTURE_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationConstants.VALID_STRUCTURE_INJECTION_TYPE;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.StructureAnnotationDeclarationValidationResult.*;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jStructureAnnotationUtil
+{
+ /**
+ * Returns {@code Structure} annotation if exists.
+ *
+ * @param modifierListOwner Modifier list owner.
+ * @return @Structure annotation if exists, {@code null} otherwise.
+ * @since 0.1
+ */
+ @Nullable
+ public static PsiAnnotation getStructureAnnotation( @NotNull PsiModifierListOwner modifierListOwner )
+ {
+ return findAnnotation( modifierListOwner, QUALIFIED_NAME_STRUCTURE_ANNOTATION );
+ }
+
+ /**
+ * Create structure annotation.
+ *
+ * @param project project to create structure annotation.
+ * @param context the context to create structure annotation.
+ * @return @Structure annotation.
+ */
+ @NotNull
+ public static PsiAnnotation createStructureAnnotation( @NotNull Project project,
+ @NotNull PsiElement context )
+ {
+ JavaPsiFacade psiFacade = JavaPsiFacade.getInstance( project );
+ PsiElementFactory factory = psiFacade.getElementFactory();
+ return factory.createAnnotationFromText( "@" + QUALIFIED_NAME_STRUCTURE_ANNOTATION, context );
+ }
+
+ /**
+ * @param variable variable to check.
+ * @return Look at {@link StructureAnnotationDeclarationValidationResult}.
+ * @since 0.1
+ */
+ @NotNull
+ public static StructureAnnotationDeclarationValidationResult validateStructureAnnotationDeclaration(
+ @NotNull PsiVariable variable )
+ {
+ PsiAnnotation structureAnnotation = getStructureAnnotation( variable );
+ if( structureAnnotation == null )
+ {
+ return invalidStructureAnnotationNotDeclared;
+ }
+
+ PsiModifierList modifierList = variable.getModifierList();
+ if( modifierList != null )
+ {
+ if( modifierList.hasModifierProperty( STATIC ) )
+ {
+ return invalidDeclaredOnStaticVariable;
+ }
+ }
+
+ if( !isInjecteableByStructureAnnotation( variable ) )
+ {
+ return invalidInjectionType;
+ }
+
+ return valid;
+ }
+
+ /**
+ * Returns a {@code boolean} indicator whether variable type is injectable by @Structure annotation.
+ *
+ * @param variable variable to check.
+ * @return {@code true} if variable type is injecteable by @Structure annotation.
+ * @since 0.1
+ */
+ public static boolean isInjecteableByStructureAnnotation( @NotNull PsiVariable variable )
+ {
+ PsiType type = variable.getType();
+ String fieldClassQualifiedName = type.getCanonicalText();
+ return binarySearch( VALID_STRUCTURE_INJECTION_TYPE, fieldClassQualifiedName ) > -1;
+ }
+
+ private Qi4jStructureAnnotationUtil()
+ {
+ }
+
+ public enum StructureAnnotationDeclarationValidationResult
+ {
+ invalidStructureAnnotationNotDeclared,
+ invalidDeclaredOnStaticVariable,
+ invalidInjectionType,
+ valid,
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/ReplaceWithStructureAnnotation.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/ReplaceWithStructureAnnotation.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/ReplaceWithStructureAnnotation.java
new file mode 100644
index 0000000..3cd6fb6
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/common/ReplaceWithStructureAnnotation.java
@@ -0,0 +1,47 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.structure.common;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotation;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.createStructureAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class ReplaceWithStructureAnnotation extends AbstractFix
+{
+ private final PsiAnnotation annotation;
+
+ public ReplaceWithStructureAnnotation( @NotNull String fixMessage,
+ @NotNull PsiAnnotation annotationToReplace )
+ {
+ super( fixMessage );
+ this.annotation = annotationToReplace;
+ }
+
+ public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+ {
+ PsiAnnotation structureAnnotation = createStructureAnnotation( project, annotation );
+ annotation.replace( structureAnnotation );
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/inspections/StructureAnnotationDeclaredCorrectlyInspection.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/inspections/StructureAnnotationDeclaredCorrectlyInspection.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/inspections/StructureAnnotationDeclaredCorrectlyInspection.java
new file mode 100644
index 0000000..7baea38
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/injections/structure/inspections/StructureAnnotationDeclaredCorrectlyInspection.java
@@ -0,0 +1,90 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.injections.structure.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiVariable;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.injections.common.inspections.AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationConstants.QUALIFIED_NAME_STRUCTURE_ANNOTATION;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.StructureAnnotationDeclarationValidationResult;
+import static org.apache.zest.ide.plugin.idea.injections.structure.common.Qi4jStructureAnnotationUtil.validateStructureAnnotationDeclaration;
+
+/**
+ * {@code StructureAnnotationUsedCorrectly} validates {@code @Structure} injection annotation declaration.
+ *
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public class StructureAnnotationDeclaredCorrectlyInspection
+ extends AbstractInjectionAnnotationDeclarationOnFieldAndConstructorInspection
+{
+ @NotNull
+ protected final String resourceBundlePrefixId()
+ {
+ return "injections.structure.annotation.declared.correctly";
+ }
+
+ @NotNull
+ public final String getShortName()
+ {
+ return "StructureAnnotationDeclaredCorrectlyInspection";
+ }
+
+ @NotNull
+ protected final String getRemoveAnnotationMessageFix()
+ {
+ return message( "injections.structure.annotation.declared.correctly.fix.remove.annotation" );
+ }
+
+ @NotNull
+ protected final String getAnnotationToCheckQualifiedName()
+ {
+ return QUALIFIED_NAME_STRUCTURE_ANNOTATION;
+ }
+
+ @Nullable
+ protected final ProblemDescriptor[] verifyAnnotationDeclaredCorrectly( @NotNull PsiVariable psiVariable,
+ @NotNull PsiAnnotation structureAnnotation,
+ @NotNull InspectionManager manager )
+ {
+ StructureAnnotationDeclarationValidationResult annotationCheck =
+ validateStructureAnnotationDeclaration( psiVariable );
+ switch( annotationCheck )
+ {
+ case invalidInjectionType:
+ String message = message(
+ "injections.structure.annotation.declared.correctly.error.invalid.injection.type",
+ psiVariable.getType().getCanonicalText()
+ );
+ AbstractFix removeStructureAnnotationFix = createRemoveAnnotationFix( structureAnnotation );
+ ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
+ structureAnnotation, message, removeStructureAnnotationFix, GENERIC_ERROR_OR_WARNING
+ );
+ return new ProblemDescriptor[]{ problemDescriptor };
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinConstants.java
new file mode 100644
index 0000000..e2f02df
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinConstants.java
@@ -0,0 +1,30 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.mixins.common;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jMixinConstants
+{
+ public static final String QUALIFIED_NAME_MIXINS = "org.qi4j.api.mixin.Mixins";
+
+ private Qi4jMixinConstants()
+ {
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinUtil.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinUtil.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinUtil.java
new file mode 100644
index 0000000..e8100bd
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/common/Qi4jMixinUtil.java
@@ -0,0 +1,194 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.mixins.common;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Set;
+
+import static com.intellij.codeInsight.AnnotationUtil.findAnnotation;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.emptySet;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiAnnotationUtil.getAnnotationDefaultParameterValue;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiAnnotationUtil.getClassReference;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiClassUtil.getExtendsDeep;
+import static org.apache.zest.ide.plugin.idea.common.psi.PsiClassUtil.getPSIClass;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.isAConcern;
+import static org.apache.zest.ide.plugin.idea.mixins.common.Qi4jMixinConstants.QUALIFIED_NAME_MIXINS;
+import static org.apache.zest.ide.plugin.idea.sideEffects.common.Qi4jSideEffectUtil.isASideEffect;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jMixinUtil
+{
+ /**
+ * Get all valid mixin types of given the {@code psiClass} argument.
+ *
+ * @param psiClass The psi class to check.
+ * @return all vlaid mixin types of the given {@code psiClass} argument.
+ * @since 0.1
+ */
+ @NotNull
+ public static Set<PsiClass> getAllValidMixinTypes( @NotNull PsiClass psiClass )
+ {
+ PsiAnnotation mixinsAnnotation = getMixinsAnnotation( psiClass );
+ if( mixinsAnnotation == null )
+ {
+ return emptySet();
+ }
+
+ Set<PsiClass> validMixinsType = getExtendsDeep( psiClass );
+ validMixinsType.add( psiClass );
+ return validMixinsType;
+ }
+
+ @NotNull
+ public static List<PsiAnnotationMemberValue> getMixinsAnnotationValue( @NotNull PsiClass psiClass )
+ {
+ return getMixinsAnnotationValue( getMixinsAnnotation( psiClass ) );
+ }
+
+ @NotNull
+ public static List<PsiAnnotationMemberValue> getMixinsAnnotationValue( @Nullable PsiAnnotation mixinsAnnotation )
+ {
+ if( mixinsAnnotation == null )
+ {
+ return emptyList();
+ }
+
+ String mixinsQualifiedName = mixinsAnnotation.getQualifiedName();
+ if( !QUALIFIED_NAME_MIXINS.equals( mixinsQualifiedName ) )
+ {
+ return emptyList();
+ }
+
+ return getAnnotationDefaultParameterValue( mixinsAnnotation );
+ }
+
+ @Nullable
+ public static PsiAnnotation getMixinsAnnotation( PsiElement element )
+ {
+ PsiClass psiClass = getPSIClass( element );
+ if( psiClass == null )
+ {
+ return null;
+ }
+
+ return findAnnotation( psiClass, QUALIFIED_NAME_MIXINS );
+ }
+
+ @NotNull
+ public static PsiAnnotation addOrReplaceMixinAnnotation( @NotNull PsiModifierListOwner modifierListOwner,
+ @NotNull PsiClass mixinClassToAdd )
+ {
+ Project project = modifierListOwner.getProject();
+ JavaPsiFacade psiFacade = JavaPsiFacade.getInstance( project );
+ PsiElementFactory factory = psiFacade.getElementFactory();
+ PsiAnnotation existingMixinsAnnotation = findAnnotation( modifierListOwner, QUALIFIED_NAME_MIXINS );
+
+ boolean isReplace = false;
+ PsiAnnotation newMixinsAnnotation;
+ if( existingMixinsAnnotation != null )
+ {
+ // Check duplicate
+ List<PsiAnnotationMemberValue> mixinsValues = getMixinsAnnotationValue( existingMixinsAnnotation );
+ for( PsiAnnotationMemberValue mixinValue : mixinsValues )
+ {
+ PsiJavaCodeReferenceElement mixinClassReference = getMixinClassReference( mixinValue );
+ if( mixinClassReference == null )
+ {
+ continue;
+ }
+
+ PsiElement mixinClass = mixinClassReference.resolve();
+ if( mixinClassToAdd.equals( mixinClass ) )
+ {
+ return existingMixinsAnnotation;
+ }
+ }
+
+ isReplace = true;
+ }
+
+ String mixinsAnnotationText = createMixinsAnnotationText( existingMixinsAnnotation, mixinClassToAdd );
+ newMixinsAnnotation = factory.createAnnotationFromText( mixinsAnnotationText, modifierListOwner );
+
+ if( isReplace )
+ {
+ // Replace @Mixins instead
+ existingMixinsAnnotation.replace( newMixinsAnnotation );
+ }
+ else
+ {
+ // @Mixins doesn't exists, add it as first child
+ PsiModifierList modifierList = modifierListOwner.getModifierList();
+ modifierList.addBefore( newMixinsAnnotation, modifierList.getFirstChild() );
+ }
+
+ // Shorten all class references if possible
+ JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance( project );
+ codeStyleManager.shortenClassReferences( newMixinsAnnotation );
+
+ return newMixinsAnnotation;
+ }
+
+ @NotNull
+ private static String createMixinsAnnotationText( @Nullable PsiAnnotation mixinsAnnotationBase,
+ @NotNull PsiClass mixinClassToAdd )
+ {
+ StringBuilder annotationTextBuilder = new StringBuilder();
+ annotationTextBuilder.append( "@" ).append( QUALIFIED_NAME_MIXINS ).append( "( {" );
+ List<PsiAnnotationMemberValue> mixinsValues = getMixinsAnnotationValue( mixinsAnnotationBase );
+ for( PsiAnnotationMemberValue mixinValue : mixinsValues )
+ {
+ annotationTextBuilder.append( mixinValue.getText() ).append( ", " );
+ }
+ annotationTextBuilder.append( mixinClassToAdd.getQualifiedName() ).append( ".class" );
+ annotationTextBuilder.append( "} )" );
+
+ return annotationTextBuilder.toString();
+ }
+
+
+ @Nullable
+ public static PsiJavaCodeReferenceElement getMixinClassReference( @NotNull PsiAnnotationMemberValue value )
+ {
+ return getClassReference( value );
+ }
+
+ /**
+ * Validate whether psiClass is a mixin.
+ *
+ * @param psiClass psi class to check.
+ * @return {@code true} if psiClass is a mixin, {@code false} otherwise.
+ */
+ public static boolean isAMixin( @NotNull PsiClass psiClass )
+ {
+ return !( psiClass.isInterface() || isAConcern( psiClass ) || isASideEffect( psiClass ) );
+ }
+
+ private Qi4jMixinUtil()
+ {
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinImplementsMixinType.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinImplementsMixinType.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinImplementsMixinType.java
new file mode 100644
index 0000000..f03722f
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinImplementsMixinType.java
@@ -0,0 +1,188 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.mixins.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotationMemberValue;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiJavaCodeReferenceElement;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractInspection;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.concerns.common.Qi4jConcernUtil.isAConcern;
+import static org.apache.zest.ide.plugin.idea.mixins.common.Qi4jMixinUtil.*;
+import static org.apache.zest.ide.plugin.idea.sideEffects.common.Qi4jSideEffectUtil.isASideEffect;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class MixinImplementsMixinType extends AbstractInspection
+{
+ @NotNull
+ protected final String resourceBundlePrefixId()
+ {
+ return "mixin.implements.mixin.type";
+ }
+
+ @NotNull
+ public final String getShortName()
+ {
+ return "MixinImplementsMixinType";
+ }
+
+ @Override
+ public final ProblemDescriptor[] checkClass( @NotNull PsiClass psiClass,
+ @NotNull InspectionManager manager,
+ boolean isOnTheFly )
+ {
+ // If psiClass is not an interface, ignore
+ if( !psiClass.isInterface() )
+ {
+ return null;
+ }
+
+ // If @Mixins annotation is empty, ignore
+ List<PsiAnnotationMemberValue> mixinAnnotationValues = getMixinsAnnotationValue( psiClass );
+ if( mixinAnnotationValues.isEmpty() )
+ {
+ return null;
+ }
+
+ // Get all valid mixin type
+ Set<PsiClass> validMixinsType = getAllValidMixinTypes( psiClass );
+ if( validMixinsType.isEmpty() )
+ {
+ return null;
+ }
+
+ // For each mixin
+ List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
+ for( PsiAnnotationMemberValue mixinAnnotationValue : mixinAnnotationValues )
+ {
+ PsiJavaCodeReferenceElement mixinClassReference = getMixinClassReference( mixinAnnotationValue );
+
+ // If it's not a class reference, ignore
+ if( mixinClassReference == null )
+ {
+ continue;
+ }
+
+ // If class reference can't be resolved, ignore
+ PsiClass mixinClass = (PsiClass) mixinClassReference.resolve();
+ if( mixinClass == null )
+ {
+ continue;
+ }
+
+ String mixinQualifiedName = mixinClass.getQualifiedName();
+
+ boolean isMixinsDeclarationValid = false;
+ String message = "";
+ if( mixinClass.isInterface() )
+ {
+ // Mixin can't be an interface
+ message = message( "mixin.implements.mixin.type.error.mixin.is.an.interface", mixinQualifiedName );
+ }
+ else if( isAConcern( mixinClass ) )
+ {
+ // Mixin can't be a concern
+ message = message( "mixin.implements.mixin.type.error.mixin.is.a.concern", mixinQualifiedName );
+ }
+ else if( isASideEffect( mixinClass ) )
+ {
+ // Mixin can't be a side effect
+ message = message( "mixin.implements.mixin.type.error.mixin.is.a.side.effect", mixinQualifiedName );
+ }
+ else
+ {
+ // If doesn't implement any mixin type, it's a problem
+ if( !isImplementValidMixinType( mixinClass, validMixinsType ) )
+ {
+ message = message(
+ "mixin.implements.mixin.type.error.does.not.implement.any.mixin.type",
+ mixinQualifiedName,
+ psiClass.getQualifiedName()
+ );
+ }
+ else
+ {
+ isMixinsDeclarationValid = true;
+ }
+ }
+
+ if( !isMixinsDeclarationValid )
+ {
+ ProblemDescriptor problemDescriptor = createProblemDescriptor(
+ manager, mixinAnnotationValue, mixinClassReference, message );
+ problems.add( problemDescriptor );
+ }
+ }
+
+ return problems.toArray( new ProblemDescriptor[problems.size()] );
+ }
+
+ private boolean isImplementValidMixinType( PsiClass mixinClass, Set<PsiClass> validMixinsType )
+ {
+ for( PsiClass validMixinTypeClass : validMixinsType )
+ {
+ if( mixinClass.isInheritor( validMixinTypeClass, true ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private ProblemDescriptor createProblemDescriptor( @NotNull InspectionManager manager,
+ @NotNull PsiAnnotationMemberValue mixinAnnotationValue,
+ @NotNull PsiJavaCodeReferenceElement mixinClassReference,
+ @NotNull String message )
+ {
+ RemoveInvalidMixinClassReferenceFix fix = new RemoveInvalidMixinClassReferenceFix(
+ mixinAnnotationValue, mixinClassReference
+ );
+ return manager.createProblemDescriptor( mixinAnnotationValue, message, fix, GENERIC_ERROR_OR_WARNING );
+ }
+
+ private static class RemoveInvalidMixinClassReferenceFix extends AbstractFix
+ {
+ private final PsiAnnotationMemberValue mixinClassAnnotationValue;
+
+ public RemoveInvalidMixinClassReferenceFix( @NotNull PsiAnnotationMemberValue mixinClassAnnotationValue,
+ @NotNull PsiJavaCodeReferenceElement mixinClassReference )
+ {
+ super( message( "mixin.implements.mixin.type.fix.remove.class.reference", mixinClassReference.getQualifiedName() ) );
+ this.mixinClassAnnotationValue = mixinClassAnnotationValue;
+ }
+
+ public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+ {
+ mixinClassAnnotationValue.delete();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinsAnnotationDeclaredOnMixinType.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinsAnnotationDeclaredOnMixinType.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinsAnnotationDeclaredOnMixinType.java
new file mode 100644
index 0000000..c4ebfde
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/mixins/inspections/MixinsAnnotationDeclaredOnMixinType.java
@@ -0,0 +1,90 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.mixins.inspections;
+
+import com.intellij.codeInspection.InspectionManager;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiAnnotationMemberValue;
+import com.intellij.psi.PsiClass;
+import org.jetbrains.annotations.NotNull;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractFix;
+import org.apache.zest.ide.plugin.idea.common.inspections.AbstractInspection;
+
+import static com.intellij.codeInspection.ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
+import static org.apache.zest.ide.plugin.idea.common.resource.Qi4jResourceBundle.message;
+import static org.apache.zest.ide.plugin.idea.mixins.common.Qi4jMixinUtil.getMixinsAnnotation;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class MixinsAnnotationDeclaredOnMixinType extends AbstractInspection
+{
+ @NotNull
+ public final String getShortName()
+ {
+ return "MixinsAnnotationDeclaredOnMixinType";
+ }
+
+ @NotNull
+ protected final String resourceBundlePrefixId()
+ {
+ return "mixins.annotation.declared.on.mixin.type";
+ }
+
+ @Override
+ public ProblemDescriptor[] checkClass( @NotNull PsiClass psiClass,
+ @NotNull InspectionManager manager,
+ boolean isOnTheFly )
+ {
+ PsiAnnotation mixinsAnnotation = getMixinsAnnotation( psiClass );
+ if( mixinsAnnotation == null )
+ {
+ return null;
+ }
+
+ if( psiClass.isInterface() )
+ {
+ return null;
+ }
+
+ String message = message( "mixins.annotation.declared.on.mixin.type.error.declared.on.class" );
+ RemoveInvalidMixinClassReferenceFix fix = new RemoveInvalidMixinClassReferenceFix( mixinsAnnotation );
+ ProblemDescriptor problemDescriptor = manager.createProblemDescriptor( mixinsAnnotation, message, fix,
+ GENERIC_ERROR_OR_WARNING );
+ return new ProblemDescriptor[]{ problemDescriptor };
+
+ }
+
+ private static class RemoveInvalidMixinClassReferenceFix extends AbstractFix
+ {
+ private final PsiAnnotationMemberValue mixinsAnnotation;
+
+ public RemoveInvalidMixinClassReferenceFix( @NotNull PsiAnnotationMemberValue mixinsAnnotation )
+ {
+ super( message( "mixins.annotation.declared.on.mixin.type.fix.remove.mixins.annotation" ) );
+ this.mixinsAnnotation = mixinsAnnotation;
+ }
+
+ public final void applyFix( @NotNull Project project, @NotNull ProblemDescriptor descriptor )
+ {
+ mixinsAnnotation.delete();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/zest-java/blob/fc41bb18/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/sideEffects/common/Qi4jSideEffectConstants.java
----------------------------------------------------------------------
diff --git a/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/sideEffects/common/Qi4jSideEffectConstants.java b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/sideEffects/common/Qi4jSideEffectConstants.java
new file mode 100644
index 0000000..d417575
--- /dev/null
+++ b/tools/qidea/src/main/java/org/apache/zest/ide/plugin/idea/sideEffects/common/Qi4jSideEffectConstants.java
@@ -0,0 +1,33 @@
+/* Copyright 2008 Edward Yakop.
+*
+* 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 org.apache.zest.ide.plugin.idea.sideEffects.common;
+
+/**
+ * @author edward.yakop@gmail.com
+ * @since 0.1
+ */
+public final class Qi4jSideEffectConstants
+{
+ public static final String QUALIFIED_NAME_SIDE_EFFECTS = "org.qi4j.api.sideeffect.SideEffects";
+
+ public static final String QUALIFIED_NAME_SIDE_EFFECT_OF = "org.qi4j.api.sideeffect.SideEffectOf";
+ public static final String QUALIFIED_NAME_GENERIC_SIDE_EFFECT = "org.qi4j.api.sideeffect.GenericSideEffect";
+
+ private Qi4jSideEffectConstants()
+ {
+ }
+}
\ No newline at end of file