diff options
author | Oluwatobi Bashir-Bello <nbashirbello@google.com> | 2014-03-31 16:16:16 -0400 |
---|---|---|
committer | Oluwatobi Bashir-Bello <nbashirbello@google.com> | 2014-04-01 11:17:11 -0400 |
commit | 2f1179407be788c7cfd2db1c57e08c5314657d00 (patch) | |
tree | e443427d533577c9d4f9825f348ba39c794502a5 /src/com | |
parent | 1bb97024812b4cb3821a1b55c084eb40c8cbf195 (diff) | |
download | cloud-2f1179407be788c7cfd2db1c57e08c5314657d00.tar.gz |
API Method Name Inspection. Checks that all the API method name specfied in @ApiMethod are unique for an Endpoints class.
Change-Id: Ic5edb7a18af05724fd319d508385d4434a0a247e
Diffstat (limited to 'src/com')
-rw-r--r-- | src/com/google/gct/intellij/endpoints/validation/FullMethodNameInspection.java | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/com/google/gct/intellij/endpoints/validation/FullMethodNameInspection.java b/src/com/google/gct/intellij/endpoints/validation/FullMethodNameInspection.java new file mode 100644 index 0000000..7fe09ad --- /dev/null +++ b/src/com/google/gct/intellij/endpoints/validation/FullMethodNameInspection.java @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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.google.gct.intellij.endpoints.validation; + +import com.google.common.collect.Maps; +import com.google.gct.intellij.endpoints.GctConstants; +import com.google.gct.intellij.endpoints.util.EndpointBundle; +import com.google.gct.intellij.endpoints.util.EndpointUtilities; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemsHolder; +import com.intellij.openapi.project.Project; +import com.intellij.psi.JavaPsiFacade; +import com.intellij.psi.PsiAnnotation; +import com.intellij.psi.PsiAnnotationMemberValue; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiModifierList; + +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +/** + * Inspection to check that the full method names are unique. + * The full method name is made up of the api name + "." + api method name + * (specified in @ApiMethod). + */ +public class FullMethodNameInspection extends EndpointInspectionBase { + private static final String API_METHOD_NAME_ATTRIBUTE = "name"; + + @Override + @Nullable + public String getStaticDescription() { + return EndpointBundle.message("full.method.name.description"); + } + + @Nls + @NotNull + @Override + public String getDisplayName() { + return EndpointBundle.message("full.method.name.name"); + } + + @NotNull + @Override + public String getShortName() { + return EndpointBundle.message("full.method.name.short.name"); + } + + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + return new EndpointPsiElementVisitor() { + /** + * Flags @ApiMethods that have a duplicate API method name. + */ + @Override + public void visitClass(PsiClass aClass){ + if (!isEndpointClass(aClass)) { + return; + } + + PsiMethod[] allMethods = aClass.getMethods(); + Map<String, PsiMethod> apiMethodNames = Maps.newHashMap(); + + for(PsiMethod aMethod : allMethods) { + validateBackendMethodNameUnique(aMethod, apiMethodNames); + } + } + + /** + * Checks that the API method name specified in @APiMethod's name attribute is unique. + * API methods. + */ + private void validateBackendMethodNameUnique(PsiMethod psiMethod, Map<String, PsiMethod> apiMethodNames) { + // Check if method is a public or non-static + if(!isApiMethod(psiMethod)) { + return; + } + + if(psiMethod.isConstructor()) { + return; + } + + // Get @ApiMethod's name attribute + PsiModifierList modifierList = psiMethod.getModifierList(); + PsiAnnotation apiMethodAnnotation = modifierList.findAnnotation(GctConstants.APP_ENGINE_ANNOTATION_API_METHOD); + if(apiMethodAnnotation == null) { + return; + } + + PsiAnnotationMemberValue apiMethodNameAttribute = apiMethodAnnotation.findAttributeValue(API_METHOD_NAME_ATTRIBUTE); + if(apiMethodNameAttribute == null) { + return; + } + + String nameValueWithQuotes = apiMethodNameAttribute.getText(); + String nameValue = EndpointUtilities.removeBeginningAndEndingQuotes(nameValueWithQuotes); + + // Check that @ApiMethod's name attribute has been used previously + PsiMethod seenMethod = apiMethodNames.get(nameValue); + if (seenMethod == null) { + apiMethodNames.put(nameValue, psiMethod); + } else { + holder.registerProblem(apiMethodAnnotation, "Multiple methods with same API method name are prohibited. \"" + nameValue + + "\" is the API method name for " + psiMethod.getName() + " and " + seenMethod.getName() + ".", new MyQuickFix()); + } + + } + }; + } + + public class MyQuickFix implements LocalQuickFix { + + @NotNull + @Override + public String getName() { + return getFamilyName() + ": Rename API method name"; + } + + @NotNull + @Override + public String getFamilyName() { + return getDisplayName(); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getPsiElement(); + if(!(element instanceof PsiAnnotation)) { + return; + } + + PsiAnnotation annotation = (PsiAnnotation)element; + if(!annotation.getQualifiedName().equals(GctConstants.APP_ENGINE_ANNOTATION_API_METHOD)) { + return; + } + + PsiAnnotationMemberValue apiMethodNameAttribute = annotation.findAttributeValue(API_METHOD_NAME_ATTRIBUTE); + if(apiMethodNameAttribute == null) { + return; + } + + // Get name + String nameValueWithQuotes = apiMethodNameAttribute.getText(); + String nameValue = EndpointUtilities.removeBeginningAndEndingQuotes(nameValueWithQuotes); + + // @A(name = "someName") + PsiAnnotationMemberValue newMemberValue = JavaPsiFacade.getInstance(project).getElementFactory() + .createAnnotationFromText("@A(" + API_METHOD_NAME_ATTRIBUTE + " = \"" + nameValue + "_1\")", null).findDeclaredAttributeValue(API_METHOD_NAME_ATTRIBUTE); + + apiMethodNameAttribute.replace(newMemberValue); + } + } +} |