/* * Copyright 2010-2016 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 org.jetbrains.android.inspections.klint; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.tools.klint.client.api.JavaEvaluator; import com.android.tools.klint.client.api.JavaParser; import com.android.tools.klint.detector.api.JavaContext; import com.android.tools.klint.detector.api.Location; import com.android.tools.klint.detector.api.Severity; import com.google.common.collect.Sets; import com.intellij.codeInsight.AnnotationUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.InheritanceUtil; import lombok.ast.Node; import lombok.ast.Position; import org.jetbrains.uast.UastContext; import java.io.File; import java.util.List; public class IdeaJavaParser extends JavaParser { private final IntellijLintClient myClient; private final Project myProject; private final UastContext myContext; private final JavaEvaluator myEvaluator; public IdeaJavaParser(IntellijLintClient client, Project myProject) { this.myClient = client; this.myProject = myProject; this.myEvaluator = new MyJavaEvaluator(myProject); myContext = ServiceManager.getService(myProject, UastContext.class); } @Override public UastContext getUastContext() { return myContext; } @Override public void prepareJavaParse(@NonNull List<JavaContext> contexts) { } @Override public PsiJavaFile parseJavaToPsi(@NonNull JavaContext context) { PsiFile psiFile = IntellijLintUtils.getPsiFile(context); if (!(psiFile instanceof PsiJavaFile)) { return null; } return (PsiJavaFile)psiFile; } @Override public JavaEvaluator getEvaluator() { return myEvaluator; } @Override public Project getIdeaProject() { return myProject; } @Override public Location getRangeLocation( @NonNull JavaContext context, @NonNull Node from, int fromDelta, @NonNull Node to, int toDelta ) { Position position1 = from.getPosition(); Position position2 = to.getPosition(); if (position1 == null) { return getLocation(context, to); } else if (position2 == null) { return getLocation(context, from); } int start = Math.max(0, from.getPosition().getStart() + fromDelta); int end = to.getPosition().getEnd() + toDelta; return Location.create(context.file, null, start, end); } @Override public Location.Handle createLocationHandle(@NonNull JavaContext context, @NonNull Node node) { return new LocationHandle(context.file, node); } @Override public void runReadAction(@NonNull Runnable runnable) { ApplicationManager.getApplication().runReadAction(runnable); } /* Handle for creating positions cheaply and returning full fledged locations later */ private class LocationHandle implements Location.Handle { private final File myFile; private final Node myNode; private Object mClientData; public LocationHandle(File file, Node node) { myFile = file; myNode = node; } @NonNull @Override public Location resolve() { Position pos = myNode.getPosition(); if (pos == null) { myClient.log(Severity.WARNING, null, "No position data found for node %1$s", myNode); return Location.create(myFile); } return Location.create(myFile, null /*contents*/, pos.getStart(), pos.getEnd()); } @Override public void setClientData(@Nullable Object clientData) { mClientData = clientData; } @Override @Nullable public Object getClientData() { return mClientData; } } private static class MyJavaEvaluator extends JavaEvaluator { private final Project myProject; public MyJavaEvaluator(Project project) { myProject = project; } @Nullable @Override public PsiClass findClass(@NonNull String qualifiedName) { return JavaPsiFacade.getInstance(myProject).findClass(qualifiedName, GlobalSearchScope.allScope(myProject)); } @Nullable @Override public PsiClassType getClassType(@Nullable PsiClass cls) { return cls != null ? JavaPsiFacade.getElementFactory(myProject).createType(cls) : null; } @NonNull @Override public PsiAnnotation[] getAllAnnotations(@NonNull PsiModifierListOwner owner) { return AnnotationUtil.getAllAnnotations(owner, true, null, true); } @Nullable @Override public PsiAnnotation findAnnotationInHierarchy(@NonNull PsiModifierListOwner listOwner, @NonNull String... annotationNames) { return AnnotationUtil.findAnnotationInHierarchy(listOwner, Sets.newHashSet(annotationNames)); } @Nullable @Override public PsiAnnotation findAnnotation(@Nullable PsiModifierListOwner listOwner, @NonNull String... annotationNames) { return AnnotationUtil.findAnnotation(listOwner, false, annotationNames); } @Nullable @Override public File getFile(@NonNull PsiFile file) { VirtualFile virtualFile = file.getVirtualFile(); return virtualFile != null ? VfsUtilCore.virtualToIoFile(virtualFile) : null; } } }